From 47c3d95b8b5d4d022018582baa4d1f9a9ae4dac1 Mon Sep 17 00:00:00 2001 From: Egor Orachev Date: Tue, 31 Oct 2023 13:13:27 +0300 Subject: [PATCH] gh-43: add compute pipeline support & bloom and tonemap on compute now --- .gitignore | 2 + engine/CMakeLists.txt | 3 + engine/core/log.cpp | 2 +- engine/gfx/gfx_ctx.cpp | 36 ++ engine/gfx/gfx_ctx.hpp | 24 +- engine/gfx/gfx_defs.hpp | 20 +- engine/gfx/gfx_driver.hpp | 11 +- engine/gfx/gfx_pipeline.cpp | 7 + engine/gfx/gfx_pipeline.hpp | 35 ++ engine/gfx/gfx_pipeline_cache.cpp | 14 + engine/gfx/gfx_pipeline_cache.hpp | 21 +- engine/gfx/gfx_shader.hpp | 11 +- engine/gfx/threaded/gfx_ctx_wrapper.cpp | 15 + engine/gfx/threaded/gfx_ctx_wrapper.hpp | 5 + engine/gfx/threaded/gfx_driver_wrapper.cpp | 25 ++ engine/gfx/threaded/gfx_driver_wrapper.hpp | 46 ++- engine/gfx/vulkan/vk_buffers.cpp | 30 +- engine/gfx/vulkan/vk_buffers.hpp | 1 + engine/gfx/vulkan/vk_ctx.cpp | 86 +++- engine/gfx/vulkan/vk_ctx.hpp | 7 + engine/gfx/vulkan/vk_defs.hpp | 2 + engine/gfx/vulkan/vk_desc_set.cpp | 7 + engine/gfx/vulkan/vk_driver.cpp | 31 +- engine/gfx/vulkan/vk_driver.hpp | 38 +- engine/gfx/vulkan/vk_pipeline.cpp | 94 ++++- engine/gfx/vulkan/vk_pipeline.hpp | 31 +- engine/gfx/vulkan/vk_shader.cpp | 119 ++++-- engine/gfx/vulkan/vk_shader.hpp | 17 +- engine/gfx/vulkan/vk_texture.cpp | 42 +- engine/gfx/vulkan/vk_texture.hpp | 1 + engine/platform/file_system.cpp | 21 +- engine/platform/file_system.hpp | 10 +- engine/render/deferred_pipeline.cpp | 12 +- engine/render/deferred_pipeline.hpp | 7 +- engine/render/graphics_pipeline.cpp | 7 +- engine/render/graphics_pipeline.hpp | 16 +- engine/render/post_process/pass_bloom.cpp | 116 +++--- engine/render/post_process/pass_bloom.hpp | 8 +- .../render/post_process/pass_composition.cpp | 115 ++++++ .../render/post_process/pass_composition.hpp | 60 +++ engine/render/post_process/pass_tonemap.cpp | 60 ++- engine/render/post_process/pass_tonemap.hpp | 6 +- engine/render/render_engine.hpp | 14 +- engine/render/shader_builder.cpp | 5 + engine/render/shader_manager.cpp | 2 + engine/render/shader_pass.cpp | 36 +- engine/shaders/base.frag | 1 + engine/shaders/bloom.comp | 125 ++++++ engine/shaders/bloom.frag | 1 + engine/shaders/canvas.frag | 1 + engine/shaders/color.glsl | 41 ++ engine/shaders/common_funcs.glsl | 31 -- engine/shaders/composition.frag | 21 + .../{tonemap.vert => composition.vert} | 0 .../generated/auto_base_gl410_frag.hpp | 52 +-- .../generated/auto_base_gl410_vert.hpp | 6 +- engine/shaders/generated/auto_base_pass.hpp | 2 +- .../generated/auto_base_reflection.hpp | 2 +- .../generated/auto_base_vk450_frag.hpp | 52 +-- .../generated/auto_base_vk450_vert.hpp | 6 +- ...410_frag.hpp => auto_bloom_gl410_comp.hpp} | 220 ++--------- engine/shaders/generated/auto_bloom_pass.hpp | 41 +- .../generated/auto_bloom_reflection.hpp | 22 +- ...450_frag.hpp => auto_bloom_vk450_comp.hpp} | 220 ++--------- .../generated/auto_canvas_gl410_frag.hpp | 51 +-- .../generated/auto_canvas_gl410_vert.hpp | 29 +- engine/shaders/generated/auto_canvas_pass.hpp | 2 +- .../generated/auto_canvas_reflection.hpp | 2 +- .../generated/auto_canvas_vk450_frag.hpp | 51 +-- .../generated/auto_canvas_vk450_vert.hpp | 29 +- ...ag.hpp => auto_composition_gl410_frag.hpp} | 129 +----- ...rt.hpp => auto_composition_gl410_vert.hpp} | 42 +- .../generated/auto_composition_pass.hpp | 120 ++++++ .../generated/auto_composition_reflection.hpp | 68 ++++ ...ag.hpp => auto_composition_vk450_frag.hpp} | 129 +----- ...rt.hpp => auto_composition_vk450_vert.hpp} | 42 +- .../generated/auto_material_gl410_frag.hpp | 54 +-- .../generated/auto_material_gl410_vert.hpp | 54 +-- .../shaders/generated/auto_material_pass.hpp | 2 +- .../generated/auto_material_reflection.hpp | 2 +- .../generated/auto_material_vk450_frag.hpp | 54 +-- .../generated/auto_material_vk450_vert.hpp | 54 +-- .../generated/auto_text_gl410_frag.hpp | 54 +-- .../generated/auto_text_gl410_vert.hpp | 30 +- engine/shaders/generated/auto_text_pass.hpp | 2 +- .../generated/auto_text_reflection.hpp | 2 +- .../generated/auto_text_vk450_frag.hpp | 54 +-- .../generated/auto_text_vk450_vert.hpp | 30 +- .../generated/auto_tonemap_gl410_comp.hpp | 201 ++++++++++ .../generated/auto_tonemap_gl410_vert.hpp | 372 ------------------ .../shaders/generated/auto_tonemap_pass.hpp | 41 +- .../generated/auto_tonemap_reflection.hpp | 39 +- .../generated/auto_tonemap_vk450_comp.hpp | 201 ++++++++++ .../generated/auto_tonemap_vk450_vert.hpp | 372 ------------------ engine/shaders/hdr.glsl | 24 +- engine/shaders/material_fs.glsl | 1 + engine/shaders/material_vs.glsl | 1 + engine/shaders/scripts/bloom.py | 4 +- engine/shaders/scripts/composition.py | 30 ++ engine/shaders/scripts/generator.py | 57 ++- engine/shaders/scripts/reflection.py | 45 ++- engine/shaders/scripts/shaders.py | 2 + engine/shaders/scripts/tonemap.py | 7 +- engine/shaders/text.frag | 3 +- engine/shaders/{tonemap.frag => tonemap.comp} | 26 +- template/config/engine.cfg | 4 +- .../materials/test_material_1.material | 2 +- .../materials/test_material_2.material | 2 +- .../materials/test_material_3.material | 2 +- template/resources/shaders/test_shader.shader | 2 +- 110 files changed, 2470 insertions(+), 2176 deletions(-) create mode 100644 engine/gfx/gfx_ctx.cpp create mode 100644 engine/render/post_process/pass_composition.cpp create mode 100644 engine/render/post_process/pass_composition.hpp create mode 100644 engine/shaders/bloom.comp create mode 100644 engine/shaders/color.glsl create mode 100644 engine/shaders/composition.frag rename engine/shaders/{tonemap.vert => composition.vert} (100%) rename engine/shaders/generated/{auto_bloom_gl410_frag.hpp => auto_bloom_gl410_comp.hpp} (63%) rename engine/shaders/generated/{auto_bloom_vk450_frag.hpp => auto_bloom_vk450_comp.hpp} (64%) rename engine/shaders/generated/{auto_tonemap_gl410_frag.hpp => auto_composition_gl410_frag.hpp} (64%) rename engine/shaders/generated/{auto_bloom_gl410_vert.hpp => auto_composition_gl410_vert.hpp} (89%) create mode 100644 engine/shaders/generated/auto_composition_pass.hpp create mode 100644 engine/shaders/generated/auto_composition_reflection.hpp rename engine/shaders/generated/{auto_tonemap_vk450_frag.hpp => auto_composition_vk450_frag.hpp} (64%) rename engine/shaders/generated/{auto_bloom_vk450_vert.hpp => auto_composition_vk450_vert.hpp} (89%) create mode 100644 engine/shaders/generated/auto_tonemap_gl410_comp.hpp delete mode 100644 engine/shaders/generated/auto_tonemap_gl410_vert.hpp create mode 100644 engine/shaders/generated/auto_tonemap_vk450_comp.hpp delete mode 100644 engine/shaders/generated/auto_tonemap_vk450_vert.hpp create mode 100644 engine/shaders/scripts/composition.py rename engine/shaders/{tonemap.frag => tonemap.comp} (68%) diff --git a/.gitignore b/.gitignore index 5a022a926..82b2d0844 100644 --- a/.gitignore +++ b/.gitignore @@ -20,8 +20,10 @@ template/logs template/debug template/cache +template/.wgengine # logs, caches and debug data games/flappyowl/logs games/flappyowl/debug games/flappyowl/cache +games/flappyowl/.wgengine diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index e368a7d5a..71f2d6205 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -114,6 +114,7 @@ add_library(wmoge STATIC gfx/gfx_defs.hpp gfx/gfx_desc_set.cpp gfx/gfx_desc_set.hpp + gfx/gfx_ctx.cpp gfx/gfx_ctx.hpp gfx/gfx_driver.hpp gfx/gfx_dynamic_buffers.cpp @@ -301,6 +302,8 @@ add_library(wmoge STATIC render/geometry/pass_gbuffer.hpp render/post_process/pass_bloom.cpp render/post_process/pass_bloom.hpp + render/post_process/pass_composition.cpp + render/post_process/pass_composition.hpp render/post_process/pass_tonemap.cpp render/post_process/pass_tonemap.hpp resource/audio_stream.cpp diff --git a/engine/core/log.cpp b/engine/core/log.cpp index 4b1fca958..8ee65fb6a 100644 --- a/engine/core/log.cpp +++ b/engine/core/log.cpp @@ -92,7 +92,7 @@ namespace wmoge { std::time_t time = engine->get_time(); std::stringstream log_file_name; - log_file_name << "root://logs/log_" + log_file_name << "logs://log_" << m_name << " " << engine->get_time_formatted("%Y-%m-%d %H-%M-%S", time) << ".log"; diff --git a/engine/gfx/gfx_ctx.cpp b/engine/gfx/gfx_ctx.cpp new file mode 100644 index 000000000..2d24aad8d --- /dev/null +++ b/engine/gfx/gfx_ctx.cpp @@ -0,0 +1,36 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "gfx_ctx.hpp" + +namespace wmoge { + + Vec3i GfxCtx::group_size(int x, int y, int local_size) { + return Vec3i(int(Math::div_up(x, local_size)), int(Math::div_up(y, local_size)), 1); + } + +}// namespace wmoge diff --git a/engine/gfx/gfx_ctx.hpp b/engine/gfx/gfx_ctx.hpp index f3b0c359b..d8c4535b1 100644 --- a/engine/gfx/gfx_ctx.hpp +++ b/engine/gfx/gfx_ctx.hpp @@ -72,14 +72,18 @@ namespace wmoge { virtual void update_texture_2d_array(const Ref& texture, int mip, int slice, Rect2i region, const Ref& data) = 0; virtual void update_texture_cube(const Ref& texture, int mip, int face, Rect2i region, const Ref& data) = 0; - virtual void* map_vert_buffer(const Ref& buffer) = 0; - virtual void* map_index_buffer(const Ref& buffer) = 0; - virtual void* map_uniform_buffer(const Ref& buffer) = 0; - virtual void* map_storage_buffer(const Ref& buffer) = 0; - virtual void unmap_vert_buffer(const Ref& buffer) = 0; - virtual void unmap_index_buffer(const Ref& buffer) = 0; - virtual void unmap_uniform_buffer(const Ref& buffer) = 0; - virtual void unmap_storage_buffer(const Ref& buffer) = 0; + virtual void* map_vert_buffer(const Ref& buffer) = 0; + virtual void* map_index_buffer(const Ref& buffer) = 0; + virtual void* map_uniform_buffer(const Ref& buffer) = 0; + virtual void* map_storage_buffer(const Ref& buffer) = 0; + + virtual void unmap_vert_buffer(const Ref& buffer) = 0; + virtual void unmap_index_buffer(const Ref& buffer) = 0; + virtual void unmap_uniform_buffer(const Ref& buffer) = 0; + virtual void unmap_storage_buffer(const Ref& buffer) = 0; + + virtual void barrier_image(const Ref& texture, GfxTexBarrierType barrier_type) = 0; + virtual void barrier_buffer(const Ref& buffer) = 0; virtual void begin_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name = StringId()) = 0; virtual void bind_target(const Ref& window) = 0; @@ -89,12 +93,14 @@ namespace wmoge { virtual void clear(int target, const Vec4f& color) = 0; virtual void clear(float depth, int stencil) = 0; virtual bool bind_pipeline(const Ref& pipeline) = 0; + virtual bool bind_comp_pipeline(const Ref& pipeline) = 0; virtual void bind_vert_buffer(const Ref& buffer, int index, int offset = 0) = 0; virtual void bind_index_buffer(const Ref& buffer, GfxIndexType index_type, int offset = 0) = 0; virtual void bind_desc_set(const Ref& set, int index) = 0; virtual void bind_desc_sets(const ArrayView& sets, int offset = 0) = 0; virtual void draw(int vertex_count, int base_vertex, int instance_count) = 0; virtual void draw_indexed(int index_count, int base_vertex, int instance_count) = 0; + virtual void dispatch(Vec3i group_count) = 0; virtual void end_render_pass() = 0; virtual void execute(const std::function& functor) = 0; @@ -108,6 +114,8 @@ namespace wmoge { [[nodiscard]] virtual const Mat4x4f& clip_matrix() const = 0; [[nodiscard]] virtual GfxCtxType ctx_type() const = 0; + + static Vec3i group_size(int x, int y, int local_size); }; /** diff --git a/engine/gfx/gfx_defs.hpp b/engine/gfx/gfx_defs.hpp index fbef1c1ac..2f833943d 100644 --- a/engine/gfx/gfx_defs.hpp +++ b/engine/gfx/gfx_defs.hpp @@ -99,6 +99,21 @@ namespace wmoge { GpuDedicated }; + /** @brief Texture sub region */ + struct GfxTexRegion { + int base_mip = 0; + int num_mips = 0; + int base_array_slice = 0; + int num_array_slices = 0; + }; + + /** @brief Texture manual barrier type */ + enum class GfxTexBarrierType : int { + RenderTarget, + Sampling, + Storage + }; + /** @brief Texture type */ enum class GfxTex : int { Unknown = 0, @@ -115,6 +130,8 @@ namespace wmoge { DepthTarget = 2, /** Texture can be used as render target color attachment */ ColorTarget = 3, + /** Texture can be used in compute shaders as storage image */ + Storage = 3, /** Texture can be sampled within shader */ Sampling = 4 }; @@ -432,7 +449,8 @@ namespace wmoge { Unknown = 0, SampledTexture, UniformBuffer, - StorageBuffer + StorageBuffer, + StorageImage }; /** @brief How to bind resource to gfx pipeline */ diff --git a/engine/gfx/gfx_driver.hpp b/engine/gfx/gfx_driver.hpp index 91c1836a6..42161dd70 100644 --- a/engine/gfx/gfx_driver.hpp +++ b/engine/gfx/gfx_driver.hpp @@ -75,12 +75,14 @@ namespace wmoge { virtual Ref make_uniform_buffer(int size, GfxMemUsage usage, const StringId& name = StringId()) = 0; virtual Ref make_storage_buffer(int size, GfxMemUsage usage, const StringId& name = StringId()) = 0; virtual Ref make_shader(std::string vertex, std::string fragment, const GfxDescSetLayouts& layouts, const StringId& name = StringId()) = 0; + virtual Ref make_shader(std::string compute, const GfxDescSetLayouts& layouts, const StringId& name = StringId()) = 0; virtual Ref make_shader(Ref code, const StringId& name = StringId()) = 0; virtual Ref make_texture_2d(int width, int height, int mips, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, GfxTexSwizz swizz, const StringId& name = StringId()) = 0; virtual Ref make_texture_2d_array(int width, int height, int mips, int slices, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, const StringId& name = StringId()) = 0; virtual Ref make_texture_cube(int width, int height, int mips, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, const StringId& name = StringId()) = 0; virtual Ref make_sampler(const GfxSamplerDesc& desc, const StringId& name = StringId()) = 0; virtual Ref make_pipeline(const GfxPipelineState& state, const StringId& name = StringId()) = 0; + virtual Ref make_comp_pipeline(const GfxCompPipelineState& state, const StringId& name = StringId()) = 0; virtual Ref make_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name = StringId()) = 0; virtual Ref make_dyn_vert_buffer(int chunk_size, const StringId& name = StringId()) = 0; virtual Ref make_dyn_index_buffer(int chunk_size, const StringId& name = StringId()) = 0; @@ -95,10 +97,11 @@ namespace wmoge { virtual void prepare_window(const Ref& window) = 0; virtual void swap_buffers(const Ref& window) = 0; - [[nodiscard]] virtual class GfxCtx* ctx_immediate() = 0; - [[nodiscard]] virtual class GfxCtx* ctx_async() = 0; - [[nodiscard]] virtual GfxPipelineCache* pso_cache() = 0; - [[nodiscard]] virtual GfxVertFormatCache* vert_fmt_cache() = 0; + [[nodiscard]] virtual class GfxCtx* ctx_immediate() = 0; + [[nodiscard]] virtual class GfxCtx* ctx_async() = 0; + [[nodiscard]] virtual GfxPipelineCache* pso_cache() = 0; + [[nodiscard]] virtual GfxCompPipelineCache* comp_pso_cache() = 0; + [[nodiscard]] virtual GfxVertFormatCache* vert_fmt_cache() = 0; [[nodiscard]] virtual GfxUniformPool* uniform_pool() = 0; [[nodiscard]] virtual GfxDynVertBuffer* dyn_vert_buffer() = 0; diff --git a/engine/gfx/gfx_pipeline.cpp b/engine/gfx/gfx_pipeline.cpp index 7bfd0aa6d..636906487 100644 --- a/engine/gfx/gfx_pipeline.cpp +++ b/engine/gfx/gfx_pipeline.cpp @@ -62,4 +62,11 @@ namespace wmoge { return static_cast(Crc32::hash(this, sizeof(GfxPipelineState))); } + bool GfxCompPipelineState::operator==(const GfxCompPipelineState& other) const { + return shader == other.shader; + } + std::size_t GfxCompPipelineState::hash() const { + return static_cast(Crc32::hash(this, sizeof(GfxCompPipelineState))); + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/gfx_pipeline.hpp b/engine/gfx/gfx_pipeline.hpp index 5231a52f5..8aa995ca6 100644 --- a/engine/gfx/gfx_pipeline.hpp +++ b/engine/gfx/gfx_pipeline.hpp @@ -68,6 +68,18 @@ namespace wmoge { int blending; // = false; }; + /** + * @class GfxCompPipelineState + * @brief Gfx compute pipeline state description + */ + struct GfxCompPipelineState { + GfxCompPipelineState() = default; + bool operator==(const GfxCompPipelineState& other) const; + std::size_t hash() const; + + Ref shader;// = nullptr; + }; + /** * @class GfxPipeline * @brief Represents created and compiled graphics pipeline state object @@ -86,6 +98,22 @@ namespace wmoge { virtual const GfxPipelineState& state() const = 0; }; + /** + * @class GfxCompPipeline + * @brief Represents created and compiled compute pipeline state object + * + * Pipeline is a compete object which can be directly bound to the command list for the compute dispatch. + * Pipeline creation is asynchronous and done in the background. + * When pipeline created it will be used in the rendering. + */ + class GfxCompPipeline : public GfxResource { + public: + ~GfxCompPipeline() override = default; + virtual GfxPipelineStatus status() const = 0; + virtual std::string message() const = 0; + virtual const GfxCompPipelineState& state() const = 0; + }; + }// namespace wmoge namespace std { @@ -97,6 +125,13 @@ namespace std { } }; + template<> + struct hash { + std::size_t operator()(const wmoge::GfxCompPipelineState& desc) const { + return desc.hash(); + } + }; + }// namespace std #endif//WMOGE_GFX_PIPELINE_HPP diff --git a/engine/gfx/gfx_pipeline_cache.cpp b/engine/gfx/gfx_pipeline_cache.cpp index 643b2644a..9fc6ec698 100644 --- a/engine/gfx/gfx_pipeline_cache.cpp +++ b/engine/gfx/gfx_pipeline_cache.cpp @@ -45,4 +45,18 @@ namespace wmoge { m_cache[state] = pipeline; } + std::optional> GfxCompPipelineCache::get(const GfxCompPipelineState& state) { + std::lock_guard guard(m_mutex); + auto it = m_cache.find(state); + if (it != m_cache.end()) { + return it->second; + } + return std::nullopt; + } + + void GfxCompPipelineCache::add(const GfxCompPipelineState& state, const Ref& pipeline) { + std::lock_guard guard(m_mutex); + m_cache[state] = pipeline; + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/gfx_pipeline_cache.hpp b/engine/gfx/gfx_pipeline_cache.hpp index d55ae6a64..cd4bf92ae 100644 --- a/engine/gfx/gfx_pipeline_cache.hpp +++ b/engine/gfx/gfx_pipeline_cache.hpp @@ -39,7 +39,7 @@ namespace wmoge { /** * @class GfxPipelineCache - * @brief Runtime cache of pipelines + * @brief Runtime cache of graphics pipelines */ class GfxPipelineCache final { public: @@ -56,6 +56,25 @@ namespace wmoge { SpinMutex m_mutex; }; + /** + * @class GfxCompPipelineCache + * @brief Runtime cache of compute pipelines + */ + class GfxCompPipelineCache final { + public: + GfxCompPipelineCache() = default; + GfxCompPipelineCache(const GfxCompPipelineCache&) = delete; + GfxCompPipelineCache(GfxCompPipelineCache&&) = delete; + ~GfxCompPipelineCache() = default; + + std::optional> get(const GfxCompPipelineState& state); + void add(const GfxCompPipelineState& state, const Ref& pipeline); + + private: + fast_map> m_cache; + SpinMutex m_mutex; + }; + }// namespace wmoge #endif//WMOGE_GFX_PIPELINE_CACHE_HPP \ No newline at end of file diff --git a/engine/gfx/gfx_shader.hpp b/engine/gfx/gfx_shader.hpp index 92e5ca86b..7a02af394 100644 --- a/engine/gfx/gfx_shader.hpp +++ b/engine/gfx/gfx_shader.hpp @@ -36,6 +36,7 @@ #include #include +#include namespace wmoge { @@ -90,11 +91,11 @@ namespace wmoge { */ class GfxShader : public GfxResource { public: - ~GfxShader() override = default; - virtual GfxShaderStatus status() const = 0; - virtual std::string message() const = 0; - virtual const GfxShaderReflection* reflection() const = 0; - virtual Ref byte_code() const = 0; + ~GfxShader() override = default; + virtual GfxShaderStatus status() const = 0; + virtual std::string message() const = 0; + virtual std::optional reflection() const = 0; + virtual Ref byte_code() const = 0; }; }// namespace wmoge diff --git a/engine/gfx/threaded/gfx_ctx_wrapper.cpp b/engine/gfx/threaded/gfx_ctx_wrapper.cpp index 838ed326c..f3395f1c6 100644 --- a/engine/gfx/threaded/gfx_ctx_wrapper.cpp +++ b/engine/gfx/threaded/gfx_ctx_wrapper.cpp @@ -103,6 +103,13 @@ namespace wmoge { m_stream->push([=]() { m_ctx->unmap_storage_buffer(buffer); }); } + void GfxCtxWrapper::barrier_image(const Ref& texture, GfxTexBarrierType barrier_type) { + m_stream->push([=]() { m_ctx->barrier_image(texture, barrier_type); }); + } + void GfxCtxWrapper::barrier_buffer(const Ref& buffer) { + m_stream->push([=]() { m_ctx->barrier_buffer(buffer); }); + } + void GfxCtxWrapper::begin_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) { m_stream->push([=]() { m_ctx->begin_render_pass(pass_desc, name); }); } @@ -129,6 +136,11 @@ namespace wmoge { m_stream->push_and_wait([&]() { is_bound = m_ctx->bind_pipeline(pipeline); }); return is_bound; } + bool GfxCtxWrapper::bind_comp_pipeline(const Ref& pipeline) { + bool is_bound = false; + m_stream->push_and_wait([&]() { is_bound = m_ctx->bind_comp_pipeline(pipeline); }); + return is_bound; + } void GfxCtxWrapper::bind_vert_buffer(const Ref& buffer, int index, int offset) { m_stream->push([=]() { m_ctx->bind_vert_buffer(buffer, index, offset); }); } @@ -147,6 +159,9 @@ namespace wmoge { void GfxCtxWrapper::draw_indexed(int index_count, int base_vertex, int instance_count) { m_stream->push([=]() { m_ctx->draw_indexed(index_count, base_vertex, instance_count); }); } + void GfxCtxWrapper::dispatch(Vec3i group_count) { + m_stream->push([=]() { m_ctx->dispatch(group_count); }); + } void GfxCtxWrapper::end_render_pass() { m_stream->push([=]() { m_ctx->end_render_pass(); }); } diff --git a/engine/gfx/threaded/gfx_ctx_wrapper.hpp b/engine/gfx/threaded/gfx_ctx_wrapper.hpp index 40ed061b7..3b326fb89 100644 --- a/engine/gfx/threaded/gfx_ctx_wrapper.hpp +++ b/engine/gfx/threaded/gfx_ctx_wrapper.hpp @@ -72,6 +72,9 @@ namespace wmoge { void unmap_uniform_buffer(const Ref& buffer) override; void unmap_storage_buffer(const Ref& buffer) override; + void barrier_image(const Ref& texture, GfxTexBarrierType barrier_type) override; + void barrier_buffer(const Ref& buffer) override; + void begin_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) override; void bind_target(const Ref& window) override; void bind_color_target(const Ref& texture, int target, int mip, int slice) override; @@ -80,12 +83,14 @@ namespace wmoge { void clear(int target, const Vec4f& color) override; void clear(float depth, int stencil) override; bool bind_pipeline(const Ref& pipeline) override; + bool bind_comp_pipeline(const Ref& pipeline) override; void bind_vert_buffer(const Ref& buffer, int index, int offset) override; void bind_index_buffer(const Ref& buffer, GfxIndexType index_type, int offset) override; void bind_desc_set(const Ref& set, int index) override; void bind_desc_sets(const ArrayView& sets, int offset) override; void draw(int vertex_count, int base_vertex, int instance_count) override; void draw_indexed(int index_count, int base_vertex, int instance_count) override; + void dispatch(Vec3i group_count) override; void end_render_pass() override; void execute(const std::function& functor) override; diff --git a/engine/gfx/threaded/gfx_driver_wrapper.cpp b/engine/gfx/threaded/gfx_driver_wrapper.cpp index 2091dc91d..8ca40b9ca 100644 --- a/engine/gfx/threaded/gfx_driver_wrapper.cpp +++ b/engine/gfx/threaded/gfx_driver_wrapper.cpp @@ -55,6 +55,7 @@ namespace wmoge { m_ctx_immediate = driver->ctx_immediate(); m_ctx_async = driver->ctx_async(); m_pso_cache = driver->pso_cache(); + m_comp_pso_cache = driver->comp_pso_cache(); m_vert_fmt_cache = driver->vert_fmt_cache(); } @@ -105,6 +106,13 @@ namespace wmoge { m_stream->push_and_wait([&]() { shader = m_driver->make_shader(std::move(vertex), std::move(fragment), layouts, name); }); return shader; } + Ref GfxDriverWrapper::make_shader(std::string compute, const GfxDescSetLayouts& layouts, const StringId& name) { + WG_AUTO_PROFILE_GFX("GfxDriverWrapper::make_shader"); + + Ref shader; + m_stream->push_and_wait([&]() { shader = m_driver->make_shader(std::move(compute), layouts, name); }); + return shader; + } Ref GfxDriverWrapper::make_shader(Ref code, const StringId& name) { WG_AUTO_PROFILE_GFX("GfxDriverWrapper::make_shader"); @@ -154,6 +162,20 @@ namespace wmoge { WG_LOG_INFO("cache new pso " << name); return pipeline; } + Ref GfxDriverWrapper::make_comp_pipeline(const GfxCompPipelineState& state, const StringId& name) { + WG_AUTO_PROFILE_GFX("GfxDriverWrapper::make_comp_pipeline"); + + auto cached = m_comp_pso_cache->get(state); + if (cached.has_value()) { + return cached.value(); + } + + Ref pipeline; + m_stream->push_and_wait([&]() { pipeline = m_driver->make_comp_pipeline(state, name); }); + m_comp_pso_cache->add(state, pipeline); + WG_LOG_INFO("cache new comp pso " << name); + return pipeline; + } Ref GfxDriverWrapper::make_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) { WG_AUTO_PROFILE_GFX("GfxDriverWrapper::make_render_pass"); @@ -233,6 +255,9 @@ namespace wmoge { GfxPipelineCache* GfxDriverWrapper::pso_cache() { return m_pso_cache; } + GfxCompPipelineCache* GfxDriverWrapper::comp_pso_cache() { + return m_comp_pso_cache; + } GfxVertFormatCache* GfxDriverWrapper::vert_fmt_cache() { return m_vert_fmt_cache; } diff --git a/engine/gfx/threaded/gfx_driver_wrapper.hpp b/engine/gfx/threaded/gfx_driver_wrapper.hpp index b1ea5558f..5d28779fe 100644 --- a/engine/gfx/threaded/gfx_driver_wrapper.hpp +++ b/engine/gfx/threaded/gfx_driver_wrapper.hpp @@ -58,12 +58,14 @@ namespace wmoge { Ref make_uniform_buffer(int size, GfxMemUsage usage, const StringId& name) override; Ref make_storage_buffer(int size, GfxMemUsage usage, const StringId& name) override; Ref make_shader(std::string vertex, std::string fragment, const GfxDescSetLayouts& layouts, const StringId& name) override; + Ref make_shader(std::string compute, const GfxDescSetLayouts& layouts, const StringId& name) override; Ref make_shader(Ref code, const StringId& name) override; Ref make_texture_2d(int width, int height, int mips, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, GfxTexSwizz swizz, const StringId& name) override; Ref make_texture_2d_array(int width, int height, int mips, int slices, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, const StringId& name) override; Ref make_texture_cube(int width, int height, int mips, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, const StringId& name) override; Ref make_sampler(const GfxSamplerDesc& desc, const StringId& name) override; Ref make_pipeline(const GfxPipelineState& state, const StringId& name) override; + Ref make_comp_pipeline(const GfxCompPipelineState& state, const StringId& name) override; Ref make_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) override; Ref make_dyn_vert_buffer(int chunk_size, const StringId& name) override; Ref make_dyn_index_buffer(int chunk_size, const StringId& name) override; @@ -78,10 +80,11 @@ namespace wmoge { void prepare_window(const Ref& window) override; void swap_buffers(const Ref& window) override; - [[nodiscard]] class GfxCtx* ctx_immediate() override; - [[nodiscard]] class GfxCtx* ctx_async() override; - [[nodiscard]] GfxPipelineCache* pso_cache() override; - [[nodiscard]] GfxVertFormatCache* vert_fmt_cache() override; + [[nodiscard]] class GfxCtx* ctx_immediate() override; + [[nodiscard]] class GfxCtx* ctx_async() override; + [[nodiscard]] GfxPipelineCache* pso_cache() override; + [[nodiscard]] GfxCompPipelineCache* comp_pso_cache() override; + [[nodiscard]] GfxVertFormatCache* vert_fmt_cache() override; [[nodiscard]] GfxUniformPool* uniform_pool() override; [[nodiscard]] GfxDynVertBuffer* dyn_vert_buffer() override; @@ -99,23 +102,24 @@ namespace wmoge { [[nodiscard]] GfxShaderLang shader_lang() const override; private: - GfxDriverThreaded* m_driver = nullptr; - GfxUniformPool* m_uniform_pool = nullptr; - GfxDynVertBuffer* m_dyn_vert_buffer = nullptr; - GfxDynIndexBuffer* m_dyn_index_buffer = nullptr; - GfxDynUniformBuffer* m_dyn_uniform_buffer = nullptr; - GfxShaderLang m_shader_lang; - CallbackStream* m_stream = nullptr; - GfxDeviceCaps m_device_caps; - StringId m_driver_name; - std::thread::id m_thread_id; - Mat4x4f m_clip_matrix; - std::string m_shader_cache_path; - std::string m_pipeline_cache_path; - class GfxCtx* m_ctx_immediate = nullptr; - class GfxCtx* m_ctx_async = nullptr; - GfxPipelineCache* m_pso_cache = nullptr; - GfxVertFormatCache* m_vert_fmt_cache = nullptr; + GfxDriverThreaded* m_driver = nullptr; + GfxUniformPool* m_uniform_pool = nullptr; + GfxDynVertBuffer* m_dyn_vert_buffer = nullptr; + GfxDynIndexBuffer* m_dyn_index_buffer = nullptr; + GfxDynUniformBuffer* m_dyn_uniform_buffer = nullptr; + GfxShaderLang m_shader_lang; + CallbackStream* m_stream = nullptr; + GfxDeviceCaps m_device_caps; + StringId m_driver_name; + std::thread::id m_thread_id; + Mat4x4f m_clip_matrix; + std::string m_shader_cache_path; + std::string m_pipeline_cache_path; + class GfxCtx* m_ctx_immediate = nullptr; + class GfxCtx* m_ctx_async = nullptr; + GfxPipelineCache* m_pso_cache = nullptr; + GfxCompPipelineCache* m_comp_pso_cache = nullptr; + GfxVertFormatCache* m_vert_fmt_cache = nullptr; }; }// namespace wmoge diff --git a/engine/gfx/vulkan/vk_buffers.cpp b/engine/gfx/vulkan/vk_buffers.cpp index 9a45a6dd8..175bf6f5f 100644 --- a/engine/gfx/vulkan/vk_buffers.cpp +++ b/engine/gfx/vulkan/vk_buffers.cpp @@ -204,7 +204,35 @@ namespace wmoge { } void VKStorageBuffer::update(VkCommandBuffer cmd, VkDeviceSize offset, VkDeviceSize size, const Ref& mem) { VKBuffer::update(cmd, offset, size, mem); - VKBuffer::barrier(cmd, offset, size, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT); + VKBuffer::barrier(cmd, offset, size, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + } + + void VKStorageBuffer::barrier(VkCommandBuffer cmd) { + const VkAccessFlags flags = + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT; + + const VkPipelineStageFlags stages = + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_TRANSFER_BIT; + + VkBufferMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.srcAccessMask = flags; + barrier.dstAccessMask = flags; + barrier.buffer = m_buffer; + barrier.offset = 0; + barrier.size = VKBuffer::m_size; + + vkCmdPipelineBarrier(cmd, stages, stages, 0, + 0, nullptr, 1, &barrier, 0, nullptr); } }// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/vulkan/vk_buffers.hpp b/engine/gfx/vulkan/vk_buffers.hpp index 2c8b7a973..88aff5957 100644 --- a/engine/gfx/vulkan/vk_buffers.hpp +++ b/engine/gfx/vulkan/vk_buffers.hpp @@ -119,6 +119,7 @@ namespace wmoge { void create(int size, GfxMemUsage usage, const StringId& name); void unmap(VkCommandBuffer cmd) override; void update(VkCommandBuffer cmd, VkDeviceSize offset, VkDeviceSize size, const Ref& mem) override; + void barrier(VkCommandBuffer cmd); class VKDriver& driver() override { return m_driver; } }; diff --git a/engine/gfx/vulkan/vk_ctx.cpp b/engine/gfx/vulkan/vk_ctx.cpp index c605d6fdb..716e9c170 100644 --- a/engine/gfx/vulkan/vk_ctx.cpp +++ b/engine/gfx/vulkan/vk_ctx.cpp @@ -202,6 +202,17 @@ namespace wmoge { dynamic_cast(buffer.get())->unmap(cmd_current()); } + void VKCtx::barrier_image(const Ref& texture, GfxTexBarrierType barrier_type) { + WG_AUTO_PROFILE_VULKAN("VKCtx::barrier_image"); + + dynamic_cast(texture.get())->transition_layout(cmd_current(), barrier_type); + } + void VKCtx::barrier_buffer(const Ref& buffer) { + WG_AUTO_PROFILE_VULKAN("VKCtx::barrier_buffer"); + + dynamic_cast(buffer.get())->barrier(cmd_current()); + } + void VKCtx::begin_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) { WG_AUTO_PROFILE_VULKAN("VKCtx::begin_render_pass"); @@ -210,8 +221,9 @@ namespace wmoge { assert(pass_desc == GfxRenderPassDesc{});// not supported pass desc yet m_render_pass_binder->start(name); - m_in_render_pass = true; - m_render_pass_name = name; + m_in_render_pass = true; + m_comp_pipeline_bound = false; + m_render_pass_name = name; } void VKCtx::bind_target(const Ref& window) { WG_AUTO_PROFILE_VULKAN("VKCtx::bind_target"); @@ -300,6 +312,29 @@ namespace wmoge { return true; } + bool VKCtx::bind_comp_pipeline(const Ref& pipeline) { + WG_AUTO_PROFILE_VULKAN("VKCtx::bind_pipeline"); + + assert(check_thread_valid()); + assert(!m_in_render_pass); + assert(pipeline); + + Ref new_pipeline = pipeline.cast(); + + if (new_pipeline == m_current_comp_pipeline) { + return true; + } + if (!new_pipeline->validate()) { + return false; + } + + vkCmdBindPipeline(cmd_current(), VK_PIPELINE_BIND_POINT_COMPUTE, new_pipeline->pipeline()); + m_current_comp_pipeline = std::move(new_pipeline); + m_current_shader = m_current_comp_pipeline->state().shader.cast(); + m_comp_pipeline_bound = true; + + return true; + } void VKCtx::bind_vert_buffer(const Ref& buffer, int index, int offset) { WG_AUTO_PROFILE_VULKAN("VKCtx::bind_vert_buffer"); @@ -331,19 +366,26 @@ namespace wmoge { WG_AUTO_PROFILE_VULKAN("VKCtx::bind_desc_set"); assert(check_thread_valid()); - assert(m_pipeline_bound); - assert(m_target_bound); + assert(m_pipeline_bound || m_comp_pipeline_bound); assert(set); + VkPipelineBindPoint bind_point = VK_PIPELINE_BIND_POINT_MAX_ENUM; + + if (m_pipeline_bound) { + bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS; + } + if (m_comp_pipeline_bound) { + bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; + } + m_desc_sets[index] = set.cast()->set(); - vkCmdBindDescriptorSets(cmd_current(), VK_PIPELINE_BIND_POINT_GRAPHICS, m_current_shader->layout(), index, 1, &m_desc_sets[index], 0, nullptr); + vkCmdBindDescriptorSets(cmd_current(), bind_point, m_current_shader->layout(), index, 1, &m_desc_sets[index], 0, nullptr); } void VKCtx::bind_desc_sets(const ArrayView& sets, int offset) { WG_AUTO_PROFILE_VULKAN("VKCtx::bind_desc_sets"); assert(check_thread_valid()); - assert(m_pipeline_bound); - assert(m_target_bound); + assert(m_pipeline_bound || m_comp_pipeline_bound); assert(!sets.empty()); const int count = int(sets.size()); @@ -353,7 +395,16 @@ namespace wmoge { m_desc_sets[i + offset] = dynamic_cast(sets[i])->set(); } - vkCmdBindDescriptorSets(cmd_current(), VK_PIPELINE_BIND_POINT_GRAPHICS, m_current_shader->layout(), offset, count, &m_desc_sets[offset], 0, nullptr); + VkPipelineBindPoint bind_point = VK_PIPELINE_BIND_POINT_MAX_ENUM; + + if (m_pipeline_bound) { + bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS; + } + if (m_comp_pipeline_bound) { + bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; + } + + vkCmdBindDescriptorSets(cmd_current(), bind_point, m_current_shader->layout(), offset, count, &m_desc_sets[offset], 0, nullptr); } void VKCtx::draw(int vertex_count, int base_vertex, int instance_count) { WG_AUTO_PROFILE_VULKAN("VKCtx::draw"); @@ -373,6 +424,14 @@ namespace wmoge { vkCmdDrawIndexed(cmd_current(), index_count, instance_count, 0, base_vertex, 0); } + void VKCtx::dispatch(Vec3i group_count) { + WG_AUTO_PROFILE_VULKAN("VKCtx::dispatch"); + + assert(check_thread_valid()); + assert(m_comp_pipeline_bound); + + vkCmdDispatch(cmd_current(), std::uint32_t(group_count.x()), std::uint32_t(group_count.y()), std::uint32_t(group_count.z())); + } void VKCtx::end_render_pass() { WG_AUTO_PROFILE_VULKAN("VKCtx::end_render_pass"); @@ -424,7 +483,18 @@ namespace wmoge { void VKCtx::end_frame() { WG_AUTO_PROFILE_VULKAN("VKCtx::end_frame"); + assert(!m_render_pass_started); + m_cmd_manager->update(); + + m_current_pipeline.reset(); + m_current_comp_pipeline.reset(); + m_current_shader.reset(); + + m_target_bound = false; + m_pipeline_bound = false; + m_comp_pipeline_bound = false; + m_render_pass_started = false; } void VKCtx::begin_label(const StringId& label) { diff --git a/engine/gfx/vulkan/vk_ctx.hpp b/engine/gfx/vulkan/vk_ctx.hpp index 6cb049553..7a481b9d3 100644 --- a/engine/gfx/vulkan/vk_ctx.hpp +++ b/engine/gfx/vulkan/vk_ctx.hpp @@ -80,6 +80,9 @@ namespace wmoge { void unmap_uniform_buffer(const Ref& buffer) override; void unmap_storage_buffer(const Ref& buffer) override; + void barrier_image(const Ref& texture, GfxTexBarrierType barrier_type) override; + void barrier_buffer(const Ref& buffer) override; + void begin_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) override; void bind_target(const Ref& window) override; void bind_color_target(const Ref& texture, int target, int mip, int slice) override; @@ -88,12 +91,14 @@ namespace wmoge { void clear(int target, const Vec4f& color) override; void clear(float depth, int stencil) override; bool bind_pipeline(const Ref& pipeline) override; + bool bind_comp_pipeline(const Ref& pipeline) override; void bind_vert_buffer(const Ref& buffer, int index, int offset) override; void bind_index_buffer(const Ref& buffer, GfxIndexType index_type, int offset) override; void bind_desc_set(const Ref& set, int index) override; void bind_desc_sets(const ArrayView& sets, int offset) override; void draw(int vertex_count, int base_vertex, int instance_count) override; void draw_indexed(int index_count, int base_vertex, int instance_count) override; + void dispatch(Vec3i group_count) override; void end_render_pass() override; void execute(const std::function& functor) override; @@ -124,6 +129,7 @@ namespace wmoge { std::unique_ptr m_render_pass_binder; Ref m_current_pass; Ref m_current_pipeline; + Ref m_current_comp_pipeline; Ref m_current_shader; Ref m_current_index_buffer; std::array, GfxLimits::MAX_VERT_BUFFERS> m_current_vert_buffers{}; @@ -137,6 +143,7 @@ namespace wmoge { bool m_in_render_pass = false; bool m_render_pass_started = false; bool m_pipeline_bound = false; + bool m_comp_pipeline_bound = false; bool m_target_bound = false; StringId m_render_pass_name; diff --git a/engine/gfx/vulkan/vk_defs.hpp b/engine/gfx/vulkan/vk_defs.hpp index 12ad86581..6e05ec087 100644 --- a/engine/gfx/vulkan/vk_defs.hpp +++ b/engine/gfx/vulkan/vk_defs.hpp @@ -131,6 +131,8 @@ namespace wmoge { return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; case GfxBindingType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case GfxBindingType::StorageImage: + return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; default: return VK_DESCRIPTOR_TYPE_MAX_ENUM; } diff --git a/engine/gfx/vulkan/vk_desc_set.cpp b/engine/gfx/vulkan/vk_desc_set.cpp index d92480478..52a7e3bb1 100644 --- a/engine/gfx/vulkan/vk_desc_set.cpp +++ b/engine/gfx/vulkan/vk_desc_set.cpp @@ -145,6 +145,13 @@ namespace wmoge { write_info.pBufferInfo = &buffer_info; break; } + case GfxBindingType::StorageImage: { + VkDescriptorImageInfo& image_info = image_infos[image_count++]; + image_info.imageView = value.resource.cast()->view(); + image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + write_info.pImageInfo = &image_info; + break; + } default: return; } diff --git a/engine/gfx/vulkan/vk_driver.cpp b/engine/gfx/vulkan/vk_driver.cpp index a735ebde1..cc6ac6ae3 100644 --- a/engine/gfx/vulkan/vk_driver.cpp +++ b/engine/gfx/vulkan/vk_driver.cpp @@ -132,6 +132,7 @@ namespace wmoge { // init caches m_pso_cache = std::make_unique(); + m_comp_pso_cache = std::make_unique(); m_vert_fmt_cache = std::make_unique(); // setup pool and dynamic buffers @@ -223,6 +224,22 @@ namespace wmoge { return shader; } + Ref VKDriver::make_shader(std::string compute, const GfxDescSetLayouts& layouts, const StringId& name) { + WG_AUTO_PROFILE_VULKAN("VKDriver::make_shader"); + + assert(on_gfx_thread()); + + auto shader = make_ref(std::move(compute), layouts, name, *this); + + Task compile_shader(SID("vk_compile_shader_" + name.str()), [shader](TaskContext&) { + shader->compile_from_source(); + return 0; + }); + + compile_shader.schedule(); + + return shader; + } Ref VKDriver::make_shader(Ref code, const StringId& name) { WG_AUTO_PROFILE_VULKAN("VKDriver::make_shader"); @@ -288,6 +305,13 @@ namespace wmoge { return make_ref(state, name, *this); } + Ref VKDriver::make_comp_pipeline(const GfxCompPipelineState& state, const StringId& name) { + WG_AUTO_PROFILE_VULKAN("VKDriver::make_comp_pipeline"); + + assert(on_gfx_thread()); + + return make_ref(state, name, *this); + } Ref VKDriver::make_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) { WG_AUTO_PROFILE_VULKAN("VKDriver::make_render_pass"); @@ -359,10 +383,13 @@ namespace wmoge { WG_VK_CHECK(vkDeviceWaitIdle(m_device)); - m_vert_fmt_cache.reset(); + m_pso_cache.reset(); flush_release(); - m_pso_cache.reset(); + m_comp_pso_cache.reset(); + flush_release(); + + m_vert_fmt_cache.reset(); flush_release(); m_uniform_pool.reset(); diff --git a/engine/gfx/vulkan/vk_driver.hpp b/engine/gfx/vulkan/vk_driver.hpp index 2f4436a0f..20fcad272 100644 --- a/engine/gfx/vulkan/vk_driver.hpp +++ b/engine/gfx/vulkan/vk_driver.hpp @@ -70,12 +70,14 @@ namespace wmoge { Ref make_uniform_buffer(int size, GfxMemUsage usage, const StringId& name) override; Ref make_storage_buffer(int size, GfxMemUsage usage, const StringId& name) override; Ref make_shader(std::string vertex, std::string fragment, const GfxDescSetLayouts& layouts, const StringId& name) override; + Ref make_shader(std::string compute, const GfxDescSetLayouts& layouts, const StringId& name) override; Ref make_shader(Ref code, const StringId& name) override; Ref make_texture_2d(int width, int height, int mips, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, GfxTexSwizz swizz, const StringId& name) override; Ref make_texture_2d_array(int width, int height, int mips, int slices, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, const StringId& name) override; Ref make_texture_cube(int width, int height, int mips, GfxFormat format, GfxTexUsages usages, GfxMemUsage mem_usage, const StringId& name) override; Ref make_sampler(const GfxSamplerDesc& desc, const StringId& name) override; Ref make_pipeline(const GfxPipelineState& state, const StringId& name) override; + Ref make_comp_pipeline(const GfxCompPipelineState& state, const StringId& name) override; Ref make_render_pass(const GfxRenderPassDesc& pass_desc, const StringId& name) override; Ref make_frame_buffer(const VKFrameBufferDesc& desc, const StringId& name); Ref make_dyn_vert_buffer(int chunk_size, const StringId& name) override; @@ -91,10 +93,11 @@ namespace wmoge { void prepare_window(const Ref& window) override; void swap_buffers(const Ref& window) override; - class GfxCtx* ctx_immediate() override { return m_ctx_immediate.get(); } - class GfxCtx* ctx_async() override { return m_ctx_async.get(); } - GfxPipelineCache* pso_cache() override { return m_pso_cache.get(); } - GfxVertFormatCache* vert_fmt_cache() override { return m_vert_fmt_cache.get(); } + class GfxCtx* ctx_immediate() override { return m_ctx_immediate.get(); } + class GfxCtx* ctx_async() override { return m_ctx_async.get(); } + GfxPipelineCache* pso_cache() override { return m_pso_cache.get(); } + GfxCompPipelineCache* comp_pso_cache() override { return m_comp_pso_cache.get(); } + GfxVertFormatCache* vert_fmt_cache() override { return m_vert_fmt_cache.get(); } GfxUniformPool* uniform_pool() override { return m_uniform_pool.get(); } GfxDynVertBuffer* dyn_vert_buffer() override { return m_dyn_vert_buffer.get(); } @@ -184,19 +187,20 @@ namespace wmoge { std::vector m_required_device_extensions; bool m_use_validation = false; - std::unique_ptr m_driver_wrapper; - std::unique_ptr m_ctx_immediate_wrapper; - std::unique_ptr m_driver_worker; - std::unique_ptr m_driver_cmd_stream; - std::unique_ptr m_window_manager; - std::unique_ptr m_queues; - std::unique_ptr m_mem_manager; - std::unique_ptr m_desc_manager; - std::unique_ptr m_ctx_immediate; - std::unique_ptr m_ctx_async; - std::unique_ptr m_pso_cache; - std::unique_ptr m_vert_fmt_cache; - std::vector m_device_extensions; + std::unique_ptr m_driver_wrapper; + std::unique_ptr m_ctx_immediate_wrapper; + std::unique_ptr m_driver_worker; + std::unique_ptr m_driver_cmd_stream; + std::unique_ptr m_window_manager; + std::unique_ptr m_queues; + std::unique_ptr m_mem_manager; + std::unique_ptr m_desc_manager; + std::unique_ptr m_ctx_immediate; + std::unique_ptr m_ctx_async; + std::unique_ptr m_pso_cache; + std::unique_ptr m_comp_pso_cache; + std::unique_ptr m_vert_fmt_cache; + std::vector m_device_extensions; }; }// namespace wmoge diff --git a/engine/gfx/vulkan/vk_pipeline.cpp b/engine/gfx/vulkan/vk_pipeline.cpp index 56f150f49..32c883497 100644 --- a/engine/gfx/vulkan/vk_pipeline.cpp +++ b/engine/gfx/vulkan/vk_pipeline.cpp @@ -40,13 +40,9 @@ namespace wmoge { m_state = state; } VKPipeline::~VKPipeline() { - WG_AUTO_PROFILE_VULKAN("VKPipeline::~VKPipeline"); - release(); } bool VKPipeline::validate(const Ref& render_pass) { - WG_AUTO_PROFILE_VULKAN("VKPipeline::validate"); - GfxPipelineStatus status = m_status.load(); // creating pipeline in a background task, wait @@ -249,4 +245,94 @@ namespace wmoge { return m_state; } + VKCompPipeline::VKCompPipeline(const GfxCompPipelineState& state, const StringId& name, VKDriver& driver) : VKResource(driver) { + m_state = state; + m_name = name; + } + VKCompPipeline::~VKCompPipeline() { + release(); + } + bool VKCompPipeline::validate() { + GfxPipelineStatus status = m_status.load(); + + // creating pipeline in a background task, wait + if (status == GfxPipelineStatus::Creating) { + return false; + } + // creating is failed, pipeline is broken, nothing to do + if (status == GfxPipelineStatus::Failed) { + return false; + } + // pipeline is not yet created or version out of date, have to create new pipeline + if (status != GfxPipelineStatus::Created) { + auto shader = m_state.shader.cast(); + + if (shader->status() != GfxShaderStatus::Compiled) { + return false; + } + + m_status.store(GfxPipelineStatus::Creating); + + Task compilation_task(m_name, [self = Ref(this)](auto&) { + self->compile(); + return 0; + }); + + compilation_task.schedule(); + + return false; + } + + // so everything is ok, can draw + return true; + } + GfxPipelineStatus VKCompPipeline::status() const { + return m_status.load(); + } + std::string VKCompPipeline::message() const { + return status() != GfxPipelineStatus::Creating ? m_message : std::string(); + } + const GfxCompPipelineState& VKCompPipeline::state() const { + return m_state; + } + void VKCompPipeline::compile() { + WG_AUTO_PROFILE_VULKAN("VKCompPipeline::compile"); + + Timer timer; + timer.start(); + + auto shader = m_state.shader.cast(); + + VkPipelineShaderStageCreateInfo shader_stage{}; + shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + shader_stage.module = shader->modules()[0]; + shader_stage.pName = "main"; + + VkComputePipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pipeline_info.layout = shader->layout(); + pipeline_info.stage = shader_stage; + + VkPipeline new_pipeline; + + WG_VK_CHECK(vkCreateComputePipelines(m_driver.device(), m_driver.pipeline_cache(), 1, &pipeline_info, nullptr, &new_pipeline)); + WG_VK_NAME(m_driver.device(), new_pipeline, VK_OBJECT_TYPE_PIPELINE, "pso " + name().str()); + + m_pipeline = new_pipeline; + + timer.stop(); + WG_LOG_INFO("compiled: " << name() << " time: " << timer.get_elapsed_sec() << " sec"); + + m_status.store(GfxPipelineStatus::Created); + } + void VKCompPipeline::release() { + WG_AUTO_PROFILE_VULKAN("VKCompPipeline::release"); + + if (m_pipeline) { + m_driver.release_queue()->push([p = m_pipeline, d = m_driver.device()]() { vkDestroyPipeline(d, p, nullptr); }); + m_pipeline = VK_NULL_HANDLE; + } + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/vulkan/vk_pipeline.hpp b/engine/gfx/vulkan/vk_pipeline.hpp index a21d0ca04..d7f52fe20 100644 --- a/engine/gfx/vulkan/vk_pipeline.hpp +++ b/engine/gfx/vulkan/vk_pipeline.hpp @@ -38,7 +38,7 @@ namespace wmoge { /** * @class VKPipeline - * @brief Vulkan pipeline implementation + * @brief Vulkan graphics pipeline implementation */ class VKPipeline final : public VKResource { public: @@ -66,6 +66,35 @@ namespace wmoge { VkPipelineLayout m_layout = VK_NULL_HANDLE; }; + /** + * @class VKCompPipeline + * @brief Vulkan compute pipeline implementation + */ + class VKCompPipeline final : public VKResource { + public: + VKCompPipeline(const GfxCompPipelineState& state, const StringId& name, class VKDriver& driver); + ~VKCompPipeline() override; + + bool validate(); + + GfxPipelineStatus status() const override; + std::string message() const override; + const GfxCompPipelineState& state() const override; + VkPipeline pipeline() const { return m_pipeline; } + VkPipelineLayout layout() const { return m_layout; } + + private: + void compile(); + void release(); + + private: + GfxCompPipelineState m_state; + std::atomic m_status{GfxPipelineStatus::Default}; + std::string m_message; + VkPipeline m_pipeline = VK_NULL_HANDLE; + VkPipelineLayout m_layout = VK_NULL_HANDLE; + }; + }// namespace wmoge #endif//WMOGE_VK_PIPELINE_HPP diff --git a/engine/gfx/vulkan/vk_shader.cpp b/engine/gfx/vulkan/vk_shader.cpp index fcf241620..9128fdeba 100644 --- a/engine/gfx/vulkan/vk_shader.cpp +++ b/engine/gfx/vulkan/vk_shader.cpp @@ -26,12 +26,13 @@ /**********************************************************************************/ #include "vk_shader.hpp" -#include "vk_driver.hpp" #include "core/timer.hpp" #include "debug/profiler.hpp" +#include "gfx/vulkan/vk_driver.hpp" #include "io/archive.hpp" #include "io/archive_memory.hpp" +#include "io/enum.hpp" namespace wmoge { @@ -58,6 +59,13 @@ namespace wmoge { m_sources.push_back(std::move(fragment)); m_set_layouts = layouts; } + VKShader::VKShader(std::string compute, const GfxDescSetLayouts& layouts, const StringId& name, VKDriver& driver) + : VKResource(driver) { + + m_name = name; + m_sources.push_back(std::move(compute)); + m_set_layouts = layouts; + } VKShader::VKShader(Ref byte_code, const StringId& name, class VKDriver& driver) : VKResource(driver) { @@ -82,8 +90,11 @@ namespace wmoge { std::string VKShader::message() const { return status() != GfxShaderStatus::Compiling ? m_message : std::string(); } - const GfxShaderReflection* VKShader::reflection() const { - return status() == GfxShaderStatus::Compiled ? &m_reflection : nullptr; + std::optional VKShader::reflection() const { + if (status() == GfxShaderStatus::Compiled) { + return &m_reflection; + } + return std::nullopt; } Ref VKShader::byte_code() const { return status() == GfxShaderStatus::Compiled ? m_byte_code : Ref(); @@ -91,24 +102,19 @@ namespace wmoge { void VKShader::compile_from_source() { WG_AUTO_PROFILE_VULKAN("VKShader::compile_from_source"); - Timer timer; - timer.start(); + const bool compile_vert_frag = m_sources.size() == 2; + const bool compile_compute = m_sources.size() == 1; - glslang::TProgram program; - glslang::TShader shaders[2] = {glslang::TShader(EShLangVertex), glslang::TShader(EShLangFragment)}; - EShLanguage types[2] = {EShLangVertex, EShLangFragment}; + assert(compile_vert_frag || compile_compute); - const char* sources[2] = {m_sources[0].c_str(), m_sources[1].c_str()}; - const int lengths[2] = {static_cast(m_sources[0].size()), static_cast(m_sources[1].size())}; + Timer timer; + timer.start(); const auto messages = static_cast(EShMsgSpvRules | EShMsgVulkanRules); - for (int i = 0; i < 2; i++) { - auto language = types[i]; - auto& shader = shaders[i]; - - const char* shader_sources[1] = {sources[i]}; - const int shader_lengths[1] = {lengths[i]}; + auto compile_single_shader = [&](EShLanguage language, glslang::TShader& shader, const std::string& source) { + const char* shader_sources[1] = {source.data()}; + const int shader_lengths[1] = {int(source.size())}; shader.setStringsWithLengths(shader_sources, shader_lengths, 1); @@ -230,14 +236,46 @@ namespace wmoge { const int default_version = 100; if (!shader.parse(&built_in_res, default_version, true, messages)) { - WG_LOG_ERROR("failed to parse shader Num=" << i << ": " << shader.getInfoLog()); - WG_LOG_INFO(sources[i]); + WG_LOG_ERROR("failed to parse shader Num=" << Enum::to_str(language) << ": " << shader.getInfoLog()); + WG_LOG_INFO(source); m_message = shader.getInfoLog(); m_status.store(GfxShaderStatus::Failed); + return false; + } + + return true; + }; + + glslang::TProgram program; + fast_vector shaders; + + glslang::TShader shader_vertex(EShLangVertex); + glslang::TShader shader_fragment(EShLangFragment); + glslang::TShader shader_compute(EShLangCompute); + + if (compile_vert_frag) { + shaders.push_back(&shader_vertex); + shaders.push_back(&shader_fragment); + + if (!compile_single_shader(EShLangVertex, *shaders[0], m_sources[0])) { + return; + } + if (!compile_single_shader(EShLangFragment, *shaders[1], m_sources[1])) { return; } - program.addShader(&shader); + program.addShader(shaders[0]); + program.addShader(shaders[1]); + } + + if (compile_compute) { + shaders.push_back(&shader_compute); + + if (!compile_single_shader(EShLangCompute, *shaders.back(), m_sources[0])) { + return; + } + + program.addShader(shaders[0]); } if (!program.link(messages)) { @@ -247,26 +285,36 @@ namespace wmoge { return; } - std::vector spirv[2]; - Ref spirv_datas[2]; + fast_vector> spirvs; + fast_vector> spirv_datas; - for (int i = 0; i < 2; i++) { - glslang::TIntermediate* intermediate = program.getIntermediate(types[i]); + auto extract_spirv = [&](EShLanguage langugage, std::vector& spirv, Ref& spirv_data) { + glslang::TIntermediate* intermediate = program.getIntermediate(langugage); spv::SpvBuildLogger logger; glslang::SpvOptions spv_options; spv_options.disableOptimizer = false; spv_options.validate = true; spv_options.optimizeSize = true; - glslang::GlslangToSpv(*intermediate, spirv[i], &logger, &spv_options); + glslang::GlslangToSpv(*intermediate, spirv, &logger, &spv_options); - if (spirv[i].empty()) { + if (spirv.empty()) { WG_LOG_ERROR("failed to compile program: " << logger.getAllMessages()); m_message = logger.getAllMessages(); m_status.store(GfxShaderStatus::Failed); - return; + return false; } - spirv_datas[i] = make_ref(spirv[i].data(), sizeof(uint32_t) * spirv[i].size()); + spirv_data = make_ref(spirv.data(), sizeof(uint32_t) * spirv.size()); + return true; + }; + + for (auto& shader : shaders) { + auto& spirv = spirvs.emplace_back(); + auto& spirv_data = spirv_datas.emplace_back(); + + if (!extract_spirv(shader->getStage(), spirv, spirv_data)) { + return; + } } if (!program.buildReflection()) { @@ -277,12 +325,12 @@ namespace wmoge { } reflect(program); - gen_byte_code(spirv_datas[0], spirv_datas[1]); + gen_byte_code(spirv_datas); timer.stop(); WG_LOG_INFO("compiled (source): " << name() << ", code " << m_byte_code->size_as_kib() << " KiB, time: " << timer.get_elapsed_sec() << " sec"); - init(spirv_datas[0], spirv_datas[1]); + init(spirv_datas); } void VKShader::compile_from_byte_code() { WG_AUTO_PROFILE_VULKAN("VKShader::compile_from_byte_code"); @@ -307,7 +355,7 @@ namespace wmoge { timer.stop(); WG_LOG_INFO("compiled (byte code): " << name() << " time: " << timer.get_elapsed_sec() << " sec"); - init(binary.spirvs[0], binary.spirvs[1]); + init(binary.spirvs); } void VKShader::reflect(glslang::TProgram& program) { WG_AUTO_PROFILE_VULKAN("VKShader::reflect"); @@ -379,12 +427,11 @@ namespace wmoge { } } } - void VKShader::gen_byte_code(const Ref& vertex, const Ref& fragment) { + void VKShader::gen_byte_code(const fast_vector>& spirvs) { WG_AUTO_PROFILE_VULKAN("VKShader::gen_byte_code"); VKShaderBinary binary; - binary.spirvs.push_back(vertex); - binary.spirvs.push_back(fragment); + binary.spirvs = spirvs; binary.reflection = m_reflection; for (auto& layout : m_set_layouts) { @@ -400,12 +447,10 @@ namespace wmoge { m_byte_code = make_ref(archive.get_data().data(), archive.get_data().size()); } - void VKShader::init(const Ref& vertex, const Ref& fragment) { + void VKShader::init(const fast_vector>& spirvs) { WG_AUTO_PROFILE_VULKAN("VKShader::init"); - const Data* binaries[2] = {vertex.get(), fragment.get()}; - - for (auto binary : binaries) { + for (auto& binary : spirvs) { VkShaderModuleCreateInfo create_info{}; create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; create_info.codeSize = static_cast(binary->size()); diff --git a/engine/gfx/vulkan/vk_shader.hpp b/engine/gfx/vulkan/vk_shader.hpp index 63949950c..a6e52d00c 100644 --- a/engine/gfx/vulkan/vk_shader.hpp +++ b/engine/gfx/vulkan/vk_shader.hpp @@ -65,23 +65,24 @@ namespace wmoge { class VKShader final : public VKResource { public: VKShader(std::string vertex, std::string fragment, const GfxDescSetLayouts& layouts, const StringId& name, class VKDriver& driver); + VKShader(std::string compute, const GfxDescSetLayouts& layouts, const StringId& name, class VKDriver& driver); VKShader(Ref byte_code, const StringId& name, class VKDriver& driver); ~VKShader() override; void compile_from_source(); void compile_from_byte_code(); - [[nodiscard]] GfxShaderStatus status() const override; - [[nodiscard]] std::string message() const override; - [[nodiscard]] const GfxShaderReflection* reflection() const override; - [[nodiscard]] Ref byte_code() const override; - [[nodiscard]] const fast_vector& modules() const { return m_modules; } - [[nodiscard]] VkPipelineLayout layout() const { return m_layout; } + [[nodiscard]] GfxShaderStatus status() const override; + [[nodiscard]] std::string message() const override; + [[nodiscard]] std::optional reflection() const override; + [[nodiscard]] Ref byte_code() const override; + [[nodiscard]] const fast_vector& modules() const { return m_modules; } + [[nodiscard]] VkPipelineLayout layout() const { return m_layout; } private: void reflect(glslang::TProgram& program); - void gen_byte_code(const Ref& vertex, const Ref& fragment); - void init(const Ref& vertex, const Ref& fragment); + void gen_byte_code(const fast_vector>& spirvs); + void init(const fast_vector>& spirvs); private: fast_vector m_sources; diff --git a/engine/gfx/vulkan/vk_texture.cpp b/engine/gfx/vulkan/vk_texture.cpp index 0e46236c9..32fd2604e 100644 --- a/engine/gfx/vulkan/vk_texture.cpp +++ b/engine/gfx/vulkan/vk_texture.cpp @@ -149,9 +149,36 @@ namespace wmoge { update(cmd, mip, face, region, data); } - void VKTexture::transition_layout(VkCommandBuffer cmd, VkImageLayout destination) { - WG_AUTO_PROFILE_VULKAN("VKTexture::transition_layout"); + void VKTexture::transition_layout(VkCommandBuffer cmd, GfxTexBarrierType barrier_type) { + VkImageLayout destination = VK_IMAGE_LAYOUT_UNDEFINED; + + if (barrier_type == GfxTexBarrierType::Storage) { + assert(m_usages.get(GfxTexUsageFlag::Storage)); + destination = VK_IMAGE_LAYOUT_GENERAL; + } + if (barrier_type == GfxTexBarrierType::Sampling) { + assert(m_usages.get(GfxTexUsageFlag::Sampling)); + destination = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + if (barrier_type == GfxTexBarrierType::RenderTarget) { + assert(m_usages.get(GfxTexUsageFlag::ColorTarget) || + m_usages.get(GfxTexUsageFlag::DepthTarget) || + m_usages.get(GfxTexUsageFlag::DepthStencilTarget)); + + if (m_usages.get(GfxTexUsageFlag::ColorTarget)) { + destination = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + if (m_usages.get(GfxTexUsageFlag::DepthTarget)) { + destination = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + } + if (m_usages.get(GfxTexUsageFlag::DepthStencilTarget)) { + destination = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + } + transition_layout(cmd, destination); + } + void VKTexture::transition_layout(VkCommandBuffer cmd, VkImageLayout destination) { VkImageSubresourceRange subresource{}; subresource.aspectMask = VKDefs::get_aspect_flags(m_format); subresource.baseMipLevel = 0; @@ -197,6 +224,9 @@ namespace wmoge { access = VK_ACCESS_SHADER_READ_BIT; stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; + case VK_IMAGE_LAYOUT_GENERAL: + access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + stage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: access = 0; stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; @@ -231,6 +261,10 @@ namespace wmoge { barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; src_stage_flags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; get_dst_layout_settings(destination, barrier.dstAccessMask, dst_stage_flags); + } else if (m_current_layout == VK_IMAGE_LAYOUT_GENERAL) { + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + src_stage_flags = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + get_dst_layout_settings(destination, barrier.dstAccessMask, dst_stage_flags); } else if (m_current_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { barrier.srcAccessMask = 0; src_stage_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; @@ -268,6 +302,10 @@ namespace wmoge { assert(!m_usages.get(GfxTexUsageFlag::ColorTarget)); assert(!m_usages.get(GfxTexUsageFlag::DepthStencilTarget)); } + if (m_usages.get(GfxTexUsageFlag::Storage)) { + m_primary_layout = VK_IMAGE_LAYOUT_GENERAL; + m_usage_flags |= VK_IMAGE_USAGE_STORAGE_BIT; + } if (m_usages.get(GfxTexUsageFlag::Sampling)) { m_primary_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; m_usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT; diff --git a/engine/gfx/vulkan/vk_texture.hpp b/engine/gfx/vulkan/vk_texture.hpp index ff0220c5d..020de2b66 100644 --- a/engine/gfx/vulkan/vk_texture.hpp +++ b/engine/gfx/vulkan/vk_texture.hpp @@ -53,6 +53,7 @@ namespace wmoge { void update_2d_array(VkCommandBuffer cmd, int mip, int slice, const Rect2i& region, const Ref& data); void update_cube(VkCommandBuffer cmd, int mip, int face, const Rect2i& region, const Ref& data); + void transition_layout(VkCommandBuffer cmd, GfxTexBarrierType barrier_type); void transition_layout(VkCommandBuffer cmd, VkImageLayout destination); void transition_layout(VkCommandBuffer cmd, VkImageLayout destination, const VkImageSubresourceRange& range); diff --git a/engine/platform/file_system.cpp b/engine/platform/file_system.cpp index cb03e0c10..bbfc330b8 100644 --- a/engine/platform/file_system.cpp +++ b/engine/platform/file_system.cpp @@ -68,8 +68,10 @@ namespace wmoge { std::filesystem::path FileSystem::resolve(const std::string& path) { static const std::string PREFIX_RES = "res://"; static const std::string PREFIX_ROOT = "root://"; + static const std::string PREFIX_ENG = "eng://"; static const std::string PREFIX_CACHE = "cache://"; static const std::string PREFIX_DEBUG = "debug://"; + static const std::string PREFIX_LOG = "logs://"; if (path.find(PREFIX_RES) == 0) { return m_resources_path / path.substr(PREFIX_RES.length()); @@ -77,11 +79,17 @@ namespace wmoge { if (path.find(PREFIX_ROOT) == 0) { return m_root_path / path.substr(PREFIX_ROOT.length()); } + if (path.find(PREFIX_ENG) == 0) { + return m_eng_path / path.substr(PREFIX_ENG.length()); + } if (path.find(PREFIX_CACHE) == 0) { return m_cache_path / path.substr(PREFIX_CACHE.length()); } if (path.find(PREFIX_DEBUG) == 0) { - return m_debug_path / path.substr(PREFIX_CACHE.length()); + return m_debug_path / path.substr(PREFIX_DEBUG.length()); + } + if (path.find(PREFIX_LOG) == 0) { + return m_log_path / path.substr(PREFIX_LOG.length()); } WG_LOG_ERROR("unknown domain of the file path " << path); @@ -208,8 +216,10 @@ namespace wmoge { m_root_path = path; m_resources_path = m_root_path / "resources"; - m_cache_path = m_root_path / "cache"; - m_debug_path = m_root_path / "debug"; + m_eng_path = m_root_path / ".wgengine"; + m_cache_path = m_eng_path / "cache"; + m_debug_path = m_eng_path / "debug"; + m_log_path = m_eng_path / "logs"; if (!std::filesystem::exists(m_resources_path)) std::filesystem::create_directories(m_resources_path); @@ -217,14 +227,13 @@ namespace wmoge { std::filesystem::create_directories(m_cache_path); if (!std::filesystem::exists(m_debug_path)) std::filesystem::create_directories(m_debug_path); + if (!std::filesystem::exists(m_log_path)) + std::filesystem::create_directories(m_log_path); auto config_path = m_root_path / "config"; - auto log_path = m_root_path / "logs"; if (!std::filesystem::exists(config_path)) std::filesystem::create_directories(config_path); - if (!std::filesystem::exists(log_path)) - std::filesystem::create_directories(log_path); } const std::filesystem::path& FileSystem::executable_path() const { diff --git a/engine/platform/file_system.hpp b/engine/platform/file_system.hpp index eb9395f89..61a9de276 100644 --- a/engine/platform/file_system.hpp +++ b/engine/platform/file_system.hpp @@ -48,13 +48,15 @@ namespace wmoge { * File system abstracts the way how engine files are stored on a target machine. * It uses '/' as a universal delimiter and directory separator. * It provides a domain prefix in a form of `://` to specify paths. - * Standards prefixes are `root://`, `res://` and `cache://`. + * Standards prefixes are `root://`, `eng://`, `res://` and `cache://`. * This prefixes must be used for all paths to access engine files. * * Prefixes description: - * - `root://` prefix to a file relative to the engine directory - * - `res://` prefix relative to a engine resources directory + * - `root://` prefix to a file relative to the running game main directory + * - `eng://` prefix to a file relative to the engine private files directory + * - `res://` prefix relative to engine resources directory * - `cache://` prefix relative to engine cache directory for a cached files + * - `logs://` prefix relative to engine logs directory */ class FileSystem { public: @@ -83,9 +85,11 @@ namespace wmoge { private: std::filesystem::path m_executable_path;// absolute exe path std::filesystem::path m_root_path; // path to root directory of engine files (virtual) + std::filesystem::path m_eng_path; // path to directory with engine prvate files std::filesystem::path m_resources_path; // path to resources inside root std::filesystem::path m_cache_path; // path to cache inside root std::filesystem::path m_debug_path; // path to debug data inside root + std::filesystem::path m_log_path; // path to log data inside root std::vector> m_watchers; }; diff --git a/engine/render/deferred_pipeline.cpp b/engine/render/deferred_pipeline.cpp index 5f752a18c..9327616a0 100644 --- a/engine/render/deferred_pipeline.cpp +++ b/engine/render/deferred_pipeline.cpp @@ -32,6 +32,7 @@ #include "geometry/pass_gbuffer.hpp" #include "platform/window_manager.hpp" #include "post_process/pass_bloom.hpp" +#include "post_process/pass_composition.hpp" #include "post_process/pass_tonemap.hpp" namespace wmoge { @@ -42,13 +43,15 @@ namespace wmoge { void DeferredPipeline::init() { WG_AUTO_PROFILE_RENDER("DeferredPipeline::init"); - m_pass_gbuffer = std::make_unique(); - m_pass_bloom = std::make_unique(); - m_pass_tonemap = std::make_unique(); + m_pass_gbuffer = std::make_unique(); + m_pass_bloom = std::make_unique(); + m_pass_tonemap = std::make_unique(); + m_pass_composition = std::make_unique(); m_stages.push_back(m_pass_gbuffer.get()); m_stages.push_back(m_pass_bloom.get()); m_stages.push_back(m_pass_tonemap.get()); + m_stages.push_back(m_pass_composition.get()); for (GraphicsPipelineStage* stage : m_stages) { stage->set_pipeline(this); @@ -82,7 +85,8 @@ namespace wmoge { m_pass_gbuffer->execute(view_idx); m_pass_bloom->execute(view_idx); - m_pass_tonemap->execute(view_idx, Engine::instance()->window_manager()->primary_window());//tmp + m_pass_tonemap->execute(view_idx); + m_pass_composition->execute(0, engine->window_manager()->primary_window()); } } } diff --git a/engine/render/deferred_pipeline.hpp b/engine/render/deferred_pipeline.hpp index e2f66f7f8..46ec0de0f 100644 --- a/engine/render/deferred_pipeline.hpp +++ b/engine/render/deferred_pipeline.hpp @@ -51,9 +51,10 @@ namespace wmoge { std::string get_name() override; private: - std::unique_ptr m_pass_gbuffer; - std::unique_ptr m_pass_bloom; - std::unique_ptr m_pass_tonemap; + std::unique_ptr m_pass_gbuffer; + std::unique_ptr m_pass_bloom; + std::unique_ptr m_pass_tonemap; + std::unique_ptr m_pass_composition; // std::unique_ptr m_pass_forward; // std::unique_ptr m_pass_deferred_lighting; diff --git a/engine/render/graphics_pipeline.cpp b/engine/render/graphics_pipeline.cpp index 35603ad6a..b6be38e98 100644 --- a/engine/render/graphics_pipeline.cpp +++ b/engine/render/graphics_pipeline.cpp @@ -57,7 +57,6 @@ namespace wmoge { Status yaml_read(const YamlConstNodeRef& node, TonemapSettings& settings) { WG_YAML_READ_AS_OPT(node, "exposure", settings.exposure); - WG_YAML_READ_AS_OPT(node, "gamma", settings.gamma); WG_YAML_READ_AS_OPT(node, "white_point", settings.white_point); WG_YAML_READ_AS_OPT(node, "mode", settings.mode); return StatusCode::Ok; @@ -65,7 +64,6 @@ namespace wmoge { Status yaml_write(YamlNodeRef node, const TonemapSettings& settings) { WG_YAML_MAP(node); WG_YAML_WRITE_AS(node, "exposure", settings.exposure); - WG_YAML_WRITE_AS(node, "gamma", settings.gamma); WG_YAML_WRITE_AS(node, "white_point", settings.white_point); WG_YAML_WRITE_AS(node, "mode", settings.mode); return StatusCode::Ok; @@ -88,7 +86,7 @@ namespace wmoge { GfxDriver* gfx_driver = engine->gfx_driver(); const Size2i size = new_target_resoulution; - const GfxTexUsages usages = {GfxTexUsageFlag::ColorTarget, GfxTexUsageFlag::Sampling}; + const GfxTexUsages usages = {GfxTexUsageFlag::ColorTarget, GfxTexUsageFlag::Sampling, GfxTexUsageFlag::Storage}; const GfxTexUsages depth_usages = {GfxTexUsageFlag::DepthTarget, GfxTexUsageFlag::Sampling}; depth = gfx_driver->make_texture_2d(size.x(), size.y(), 1, GfxFormat::DEPTH32F, depth_usages, GfxMemUsage::GpuLocal, GfxTexSwizz::None, SID("depth")); @@ -112,12 +110,15 @@ namespace wmoge { } color_hdr = gbuffer[0];//tmp + color_ldr = gfx_driver->make_texture_2d(size.x(), size.y(), 1, GfxFormat::RGBA8, usages, GfxMemUsage::GpuLocal, GfxTexSwizz::None, SID("color_ldr")); target_viewport = Rect2i(0, 0, new_target_resoulution.x(), new_target_resoulution.y()); + target_size = Vec2u(new_target_resoulution.x(), new_target_resoulution.y()); } void GraphicsPipelineTextures::update_viewport(Size2i new_resoulution) { viewport = Rect2i(0, 0, new_resoulution.x(), new_resoulution.y()); + size = Vec2u(new_resoulution.x(), new_resoulution.y()); } GraphicsPipelineStage::GraphicsPipelineStage() { diff --git a/engine/render/graphics_pipeline.hpp b/engine/render/graphics_pipeline.hpp index 5783f43c0..b31c5abe2 100644 --- a/engine/render/graphics_pipeline.hpp +++ b/engine/render/graphics_pipeline.hpp @@ -53,12 +53,12 @@ namespace wmoge { */ struct BloomSettings { bool enable = true; - float intensity = 0.9f; - float threshold = 0.9f; + float intensity = 1.0f; + float threshold = 1.0f; float knee = 0.5f; - float radius = 1.0f; - float uspample_weight = 0.85f; - float dirt_mask_intensity = 2.5f; + float radius = 4.0f; + float uspample_weight = 0.4f; + float dirt_mask_intensity = 3.0f; std::optional> dirt_mask; friend Status yaml_read(const YamlConstNodeRef& node, BloomSettings& settings); @@ -81,7 +81,6 @@ namespace wmoge { }; float exposure = 0.8f; - float gamma = 2.2f; float white_point = 1.0f; Mode mode = Mode::Exponential; @@ -113,7 +112,8 @@ namespace wmoge { AutoExposure, ToneMapping, SunShafts, - Total = 10 + Composition, + Total = 11 }; /** @@ -133,6 +133,8 @@ namespace wmoge { Rect2i viewport; Rect2i target_viewport; + Vec2u size; + Vec2u target_size; void resize(Size2i new_target_resoulution); void update_viewport(Size2i new_resoulution); diff --git a/engine/render/post_process/pass_bloom.cpp b/engine/render/post_process/pass_bloom.cpp index 31b021e36..040f70de4 100644 --- a/engine/render/post_process/pass_bloom.cpp +++ b/engine/render/post_process/pass_bloom.cpp @@ -41,24 +41,16 @@ namespace wmoge { m_sampler = get_gfx_driver()->make_sampler(sampler_desc, SID(sampler_desc.to_str())); - GfxVertAttribs attribgs = {GfxVertAttrib::Pos2f, GfxVertAttrib::Uv02f}; - GfxVertElements elements; - elements.add_vert_attribs(attribgs, 0, false); + GfxCompPipelineState pso_state; - GfxPipelineState pso_state; - pso_state.depth_enable = false; - pso_state.depth_write = false; - pso_state.blending = false; - pso_state.vert_format = get_gfx_driver()->make_vert_format(elements, SID("[pos2, uv2,]")); + pso_state.shader = get_shader_manager()->get_shader(SID("bloom"), {"BLOOM_DOWNSAMPLE_PREFILTER"}); + m_pipeline_downsample_prefilter = get_gfx_driver()->make_comp_pipeline(pso_state, SID("bloom_downsample_prefilter")); - pso_state.shader = get_shader_manager()->get_shader(SID("bloom"), attribgs, {"BLOOM_DOWNSAMPLE_PREFILTER"}); - m_pipeline_downsample_prefilter = get_gfx_driver()->make_pipeline(pso_state, SID("bloom_downsample_prefilter")); + pso_state.shader = get_shader_manager()->get_shader(SID("bloom"), {"BLOOM_DOWNSAMPLE"}); + m_pipeline_downsample = get_gfx_driver()->make_comp_pipeline(pso_state, SID("bloom_downsample")); - pso_state.shader = get_shader_manager()->get_shader(SID("bloom"), attribgs, {"BLOOM_DOWNSAMPLE"}); - m_pipeline_downsample = get_gfx_driver()->make_pipeline(pso_state, SID("bloom_downsample")); - - pso_state.shader = get_shader_manager()->get_shader(SID("bloom"), attribgs, {"BLOOM_UPSAMPLE"}); - m_pipeline_upsample = get_gfx_driver()->make_pipeline(pso_state, SID("bloom_upsample")); + pso_state.shader = get_shader_manager()->get_shader(SID("bloom"), {"BLOOM_UPSAMPLE"}); + m_pipeline_upsample = get_gfx_driver()->make_comp_pipeline(pso_state, SID("bloom_upsample")); } void PassBloom::execute(int view_idx) { @@ -73,7 +65,6 @@ namespace wmoge { } ShaderBloom::Params params; - params.Clip = (get_gfx_driver()->clip_matrix()).transpose(); params.ThresholdKnee = Vec4f(settings.threshold, settings.threshold - settings.knee, settings.knee * 2.0f, 0.25f / settings.knee); params.UpsampleWeight = settings.uspample_weight; params.UpsampleRadius = settings.radius; @@ -103,12 +94,20 @@ namespace wmoge { value.resource = textures.color_hdr; value.sampler = m_sampler; } + { + auto& [bind, value] = resources.emplace_back(); + bind.type = GfxBindingType::StorageImage; + bind.binding = ShaderBloom::RESULT_SLOT; + value.resource = textures.bloom_downsample[0]; + } WG_GFX_LABEL(get_gfx_ctx(), SID("PassBloom::execute")); + const int BLOCK_SIZE = 8; + // Downsample { - WG_GFX_LABEL(get_gfx_ctx(), SID("Downsample")); + WG_GFX_LABEL(get_gfx_ctx(), SID("downsample")); // Downsample prefilter pass { @@ -117,21 +116,20 @@ namespace wmoge { auto desc_set = get_gfx_driver()->make_desc_set(resources); get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { - thread_ctx->begin_render_pass({}, SID("downsample + prefilter")); - { - const int w = textures.bloom_downsample[0]->width(); - const int h = textures.bloom_downsample[0]->height(); + WG_GFX_LABEL(thread_ctx, SID("downsample + prefilter")); - thread_ctx->bind_color_target(textures.bloom_downsample[0], 0, 0, 0); - thread_ctx->viewport(Rect2i(0, 0, w, h)); + const auto& result = textures.bloom_downsample[0]; + const int w = result->width(); + const int h = result->height(); - if (thread_ctx->bind_pipeline(m_pipeline_downsample_prefilter)) { - thread_ctx->bind_desc_set(desc_set, 0); - thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); - thread_ctx->draw(3, 0, 1); - } + thread_ctx->barrier_image(result, GfxTexBarrierType::Storage); + + if (thread_ctx->bind_comp_pipeline(m_pipeline_downsample_prefilter)) { + thread_ctx->bind_desc_set(desc_set, 0); + thread_ctx->dispatch(GfxCtx::group_size(w, h, BLOCK_SIZE)); } - thread_ctx->end_render_pass(); + + thread_ctx->barrier_image(result, GfxTexBarrierType::Sampling); }); } @@ -140,29 +138,32 @@ namespace wmoge { WG_AUTO_PROFILE_RENDER("downsample"); for (int i = 1; i < num_bloom_mips; i++) { + const auto& result = textures.bloom_downsample[i]; { auto& [bind, value] = resources[ShaderBloom::SOURCE_SLOT]; value.resource = textures.bloom_downsample[i - 1]; } + { + auto& [bind, value] = resources[ShaderBloom::RESULT_SLOT]; + value.resource = result; + } auto desc_set = get_gfx_driver()->make_desc_set(resources); get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { - thread_ctx->begin_render_pass({}, SID("downsample mip=" + StringUtils::from_int(i))); - { - const int w = textures.bloom_downsample[i]->width(); - const int h = textures.bloom_downsample[i]->height(); - - thread_ctx->bind_color_target(textures.bloom_downsample[i], 0, 0, 0); - thread_ctx->viewport(Rect2i(0, 0, w, h)); - - if (thread_ctx->bind_pipeline(m_pipeline_downsample)) { - thread_ctx->bind_desc_set(desc_set, 0); - thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); - thread_ctx->draw(3, 0, 1); - } + WG_GFX_LABEL(thread_ctx, SID("downsample mip=" + StringUtils::from_int(i))); + + const int w = result->width(); + const int h = result->height(); + + thread_ctx->barrier_image(result, GfxTexBarrierType::Storage); + + if (thread_ctx->bind_comp_pipeline(m_pipeline_downsample)) { + thread_ctx->bind_desc_set(desc_set, 0); + thread_ctx->dispatch(GfxCtx::group_size(w, h, BLOCK_SIZE)); } - thread_ctx->end_render_pass(); + + thread_ctx->barrier_image(result, GfxTexBarrierType::Sampling); }); } } @@ -170,12 +171,13 @@ namespace wmoge { // Upsample pass { - WG_GFX_LABEL(get_gfx_ctx(), SID("Upsample")); + WG_GFX_LABEL(get_gfx_ctx(), SID("upsample")); WG_AUTO_PROFILE_RENDER("upsample"); Ref source_prev = textures.bloom_downsample.back(); for (int i = num_bloom_mips - 2; i >= 0; i--) { + const auto& result = textures.bloom_upsample[i]; { auto& [bind, value] = resources[ShaderBloom::SOURCE_SLOT]; value.resource = textures.bloom_downsample[i]; @@ -184,25 +186,27 @@ namespace wmoge { auto& [bind, value] = resources[ShaderBloom::SOURCEPREV_SLOT]; value.resource = source_prev; } + { + auto& [bind, value] = resources[ShaderBloom::RESULT_SLOT]; + value.resource = result; + } auto desc_set = get_gfx_driver()->make_desc_set(resources); get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { - thread_ctx->begin_render_pass({}, SID("upsample mip=" + StringUtils::from_int(i))); - { - const int w = textures.bloom_upsample[i]->width(); - const int h = textures.bloom_upsample[i]->height(); + WG_GFX_LABEL(thread_ctx, SID("upsample mip=" + StringUtils::from_int(i))); - thread_ctx->bind_color_target(textures.bloom_upsample[i], 0, 0, 0); - thread_ctx->viewport(Rect2i(0, 0, w, h)); + const int w = result->width(); + const int h = result->height(); - if (thread_ctx->bind_pipeline(m_pipeline_upsample)) { - thread_ctx->bind_desc_set(desc_set, 0); - thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); - thread_ctx->draw(3, 0, 1); - } + thread_ctx->barrier_image(result, GfxTexBarrierType::Storage); + + if (thread_ctx->bind_comp_pipeline(m_pipeline_upsample)) { + thread_ctx->bind_desc_set(desc_set, 0); + thread_ctx->dispatch(GfxCtx::group_size(w, h, BLOCK_SIZE)); } - thread_ctx->end_render_pass(); + + thread_ctx->barrier_image(result, GfxTexBarrierType::Sampling); }); source_prev = textures.bloom_upsample[i]; diff --git a/engine/render/post_process/pass_bloom.hpp b/engine/render/post_process/pass_bloom.hpp index 1e693f11d..3ac0e6aef 100644 --- a/engine/render/post_process/pass_bloom.hpp +++ b/engine/render/post_process/pass_bloom.hpp @@ -53,10 +53,10 @@ namespace wmoge { GraphicsPipelineStageType get_type() const override; private: - Ref m_pipeline_downsample_prefilter; - Ref m_pipeline_downsample; - Ref m_pipeline_upsample; - Ref m_sampler; + Ref m_pipeline_downsample_prefilter; + Ref m_pipeline_downsample; + Ref m_pipeline_upsample; + Ref m_sampler; }; }// namespace wmoge diff --git a/engine/render/post_process/pass_composition.cpp b/engine/render/post_process/pass_composition.cpp new file mode 100644 index 000000000..d0898bf03 --- /dev/null +++ b/engine/render/post_process/pass_composition.cpp @@ -0,0 +1,115 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "pass_composition.hpp" + +#include "debug/profiler.hpp" +#include "shaders/generated/auto_composition_reflection.hpp" + +namespace wmoge { + + PassComposition::PassComposition() { + GfxSamplerDesc sampler_desc; + sampler_desc.min_flt = GfxSampFlt::Linear; + sampler_desc.mag_flt = GfxSampFlt::Linear; + sampler_desc.u = GfxSampAddress::ClampToEdge; + sampler_desc.v = GfxSampAddress::ClampToEdge; + + m_sampler = get_gfx_driver()->make_sampler(sampler_desc, SID(sampler_desc.to_str())); + + GfxVertAttribs attribs = {GfxVertAttrib::Pos2f, GfxVertAttrib::Uv02f}; + GfxVertElements elements; + elements.add_vert_attribs(attribs, 0, false); + + GfxPipelineState pso_state; + pso_state.shader = get_shader_manager()->get_shader(SID("composition"), attribs, {}); + pso_state.vert_format = get_gfx_driver()->make_vert_format(elements, SID("[pos2, uv2,]")); + pso_state.depth_enable = false; + pso_state.depth_write = false; + pso_state.blending = false; + + m_pipeline = get_gfx_driver()->make_pipeline(pso_state, SID("composition")); + } + + void PassComposition::execute(int view_idx, const Ref& window) { + WG_AUTO_PROFILE_RENDER("PassComposition::execute"); + + const GraphicsPipelineTextures& textures = get_pipeline()->get_textures(); + const RenderSettings& render_settings = get_render_engine()->get_settings(); + + ShaderComposition::Params params; + params.Clip = get_gfx_driver()->clip_matrix().transpose(); + + auto setup = get_gfx_driver()->uniform_pool()->allocate(params); + + GfxDescSetResources resources; + { + { + auto& [bind, value] = resources.emplace_back(); + bind.binding = ShaderComposition::PARAMS_SLOT; + bind.type = GfxBindingType::UniformBuffer; + value.resource = Ref(setup.buffer); + value.offset = setup.offset; + value.range = setup.range; + } + { + auto& [bind, value] = resources.emplace_back(); + bind.binding = ShaderComposition::COLOR_SLOT; + bind.type = GfxBindingType::SampledTexture; + value.resource = textures.color_ldr.as(); + value.sampler = m_sampler; + } + } + + auto desc_set = get_gfx_driver()->make_desc_set(resources, SID("composition")); + + get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { + thread_ctx->begin_render_pass({}, SID("PassComposition::execute")); + { + thread_ctx->bind_target(window); + thread_ctx->viewport(Rect2i(0, 0, window->fbo_width(), window->fbo_height())); + thread_ctx->clear(1.0f, 0); + + if (thread_ctx->bind_pipeline(m_pipeline)) { + thread_ctx->bind_desc_set(desc_set, 0); + thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); + thread_ctx->draw(3, 0, 1); + } + } + thread_ctx->end_render_pass(); + }); + } + + std::string PassComposition::get_name() const { + return "PassComposition"; + } + + GraphicsPipelineStageType PassComposition::get_type() const { + return GraphicsPipelineStageType::Composition; + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/render/post_process/pass_composition.hpp b/engine/render/post_process/pass_composition.hpp new file mode 100644 index 000000000..3ee283fbc --- /dev/null +++ b/engine/render/post_process/pass_composition.hpp @@ -0,0 +1,60 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#ifndef WMOGE_PASS_COMPOSITION_HPP +#define WMOGE_PASS_COMPOSITION_HPP + +#include "gfx/gfx_buffers.hpp" +#include "gfx/gfx_desc_set.hpp" +#include "gfx/gfx_pipeline.hpp" +#include "gfx/gfx_sampler.hpp" +#include "render/graphics_pipeline.hpp" +#include "render/render_engine.hpp" + +namespace wmoge { + + /** + * @class PassComposition + * @brief Executes final composition + */ + class PassComposition : public GraphicsPipelineStage { + public: + PassComposition(); + + void execute(int view_idx, const Ref& window); + + std::string get_name() const override; + GraphicsPipelineStageType get_type() const override; + + private: + Ref m_pipeline; + Ref m_sampler; + }; + +}// namespace wmoge + +#endif//WMOGE_PASS_COMPOSITION_HPP \ No newline at end of file diff --git a/engine/render/post_process/pass_tonemap.cpp b/engine/render/post_process/pass_tonemap.cpp index 1d76a2608..e44552e5c 100644 --- a/engine/render/post_process/pass_tonemap.cpp +++ b/engine/render/post_process/pass_tonemap.cpp @@ -41,31 +41,24 @@ namespace wmoge { m_sampler = get_gfx_driver()->make_sampler(sampler_desc, SID(sampler_desc.to_str())); - GfxVertAttribs attribgs = {GfxVertAttrib::Pos2f, GfxVertAttrib::Uv02f}; - GfxVertElements elements; - elements.add_vert_attribs(attribgs, 0, false); - - GfxPipelineState pso_state; - pso_state.shader = get_shader_manager()->get_shader(SID("tonemap"), attribgs, {}); - pso_state.vert_format = get_gfx_driver()->make_vert_format(elements, SID("[pos2, uv2,]")); - pso_state.depth_enable = false; - pso_state.depth_write = false; - pso_state.blending = false; - - m_pipeline = get_gfx_driver()->make_pipeline(pso_state, SID("tonemap")); + GfxCompPipelineState pso_state; + pso_state.shader = get_shader_manager()->get_shader(SID("tonemap"), {}); + + m_pipeline = get_gfx_driver()->make_comp_pipeline(pso_state, SID("tonemap")); } - void PassToneMap::execute(int view_idx, const Ref& window) { + void PassToneMap::execute(int view_idx) { WG_AUTO_PROFILE_RENDER("PassToneMap::execute"); const BloomSettings& bloom_settings = get_pipeline()->get_settings().bloom; const TonemapSettings& tonemap_settings = get_pipeline()->get_settings().tonemap; const RenderView& view = get_pipeline()->get_views()[view_idx]; const GraphicsPipelineTextures& textures = get_pipeline()->get_textures(); + const RenderSettings& render_settings = get_render_engine()->get_settings(); ShaderTonemap::Params params; - params.Clip = get_gfx_driver()->clip_matrix().transpose(); - params.InverseGamma = 1.0f / tonemap_settings.gamma; + params.TargetSize = textures.size; + params.InverseGamma = 1.0f / render_settings.gamma; params.Exposure = tonemap_settings.exposure; params.WhitePoint = tonemap_settings.white_point; params.Mode = float(tonemap_settings.mode); @@ -74,11 +67,11 @@ namespace wmoge { auto setup = get_gfx_driver()->uniform_pool()->allocate(params); - Ref black = get_tex_manager()->get_gfx_default_texture_black(); - Ref bloom = bloom_settings.enable ? textures.bloom_upsample[0] : black; - const bool has_bloom_dirt = bloom_settings.enable && bloom_settings.dirt_mask.has_value(); - Ref bloom_dirt = has_bloom_dirt ? bloom_settings.dirt_mask->get_safe()->get_texture() : black; - Ref bloom_dirt_sampler = has_bloom_dirt ? bloom_settings.dirt_mask->get_safe()->get_sampler() : m_sampler; + const Ref black = get_tex_manager()->get_gfx_default_texture_black(); + const Ref bloom = bloom_settings.enable ? textures.bloom_upsample[0] : black; + const bool has_bloom_dirt = bloom_settings.enable && bloom_settings.dirt_mask.has_value(); + const Ref bloom_dirt = has_bloom_dirt ? bloom_settings.dirt_mask->get_safe()->get_texture() : black; + const Ref bloom_dirt_sampler = has_bloom_dirt ? bloom_settings.dirt_mask->get_safe()->get_sampler() : m_sampler; GfxDescSetResources resources; { @@ -111,24 +104,27 @@ namespace wmoge { value.resource = bloom_dirt.as(); value.sampler = bloom_dirt_sampler; } + { + auto& [bind, value] = resources.emplace_back(); + bind.binding = ShaderTonemap::RESULT_SLOT; + bind.type = GfxBindingType::StorageImage; + value.resource = textures.color_ldr.as(); + } } auto desc_set = get_gfx_driver()->make_desc_set(resources, SID("tonemap")); get_gfx_ctx()->execute([&](GfxCtx* thread_ctx) { - thread_ctx->begin_render_pass({}, SID("PassToneMap::execute")); - { - thread_ctx->bind_target(window);// tmp - thread_ctx->viewport(Rect2i(0, 0, window->fbo_width(), window->fbo_height())); - thread_ctx->clear(1.0f, 0);// tmp - - if (thread_ctx->bind_pipeline(m_pipeline)) { - thread_ctx->bind_desc_set(desc_set, 0); - thread_ctx->bind_vert_buffer(get_render_engine()->get_fullscreen_tria(), 0, 0); - thread_ctx->draw(3, 0, 1); - } + WG_GFX_LABEL(thread_ctx, SID("PassToneMap::execute")); + + thread_ctx->barrier_image(textures.color_ldr, GfxTexBarrierType::Storage); + + if (thread_ctx->bind_comp_pipeline(m_pipeline)) { + thread_ctx->bind_desc_set(desc_set, 0); + thread_ctx->dispatch(GfxCtx::group_size(params.TargetSize.x(), params.TargetSize.y(), 16)); } - thread_ctx->end_render_pass(); + + thread_ctx->barrier_image(textures.color_ldr, GfxTexBarrierType::Sampling); }); } diff --git a/engine/render/post_process/pass_tonemap.hpp b/engine/render/post_process/pass_tonemap.hpp index 996e87507..5f740830e 100644 --- a/engine/render/post_process/pass_tonemap.hpp +++ b/engine/render/post_process/pass_tonemap.hpp @@ -45,14 +45,14 @@ namespace wmoge { public: PassToneMap(); - void execute(int view_idx, const Ref& window); + void execute(int view_idx); std::string get_name() const override; GraphicsPipelineStageType get_type() const override; private: - Ref m_pipeline; - Ref m_sampler; + Ref m_pipeline; + Ref m_sampler; }; }// namespace wmoge diff --git a/engine/render/render_engine.hpp b/engine/render/render_engine.hpp index 9898ea6c5..3830853dd 100644 --- a/engine/render/render_engine.hpp +++ b/engine/render/render_engine.hpp @@ -53,10 +53,18 @@ namespace wmoge { + /** + * @class RenderSettings + * @brief Global rendering settings for the engine + */ + struct RenderSettings { + float gamma = 2.2f; + }; + /** * @class RenderView * @brief Holds data required to render a single view - */ + */ struct RenderView { static constexpr int QUEUE_COUNT = MESH_PASSES_TOTAL; @@ -84,7 +92,7 @@ namespace wmoge { * @see RenderObjectCollector * @see MeshBatchCollector * @see MeshBatchCompiler - */ + */ class RenderEngine { public: RenderEngine(); @@ -118,6 +126,7 @@ namespace wmoge { [[nodiscard]] ArrayView get_views() { return ArrayView(m_views.data(), m_cameras.get_size()); } [[nodiscard]] float get_time() const { return m_time; } [[nodiscard]] float get_delta_time() const { return m_delta_time; } + [[nodiscard]] const RenderSettings& get_settings() const { return m_settings; } [[nodiscard]] const Color4f& get_clear_color() const { return m_clear_color; } [[nodiscard]] const Ref& get_main_target() const { return m_main_target; } [[nodiscard]] const Ref& get_frame_data() const { return m_frame_data; } @@ -134,6 +143,7 @@ namespace wmoge { RenderCmdAllocator m_cmd_allocator; GfxVector m_fullscreen_tria; + RenderSettings m_settings; Color4f m_clear_color = Color::BLACK4f; Ref m_main_target; Ref m_frame_data; diff --git a/engine/render/shader_builder.cpp b/engine/render/shader_builder.cpp index 6f01213f1..377d05812 100644 --- a/engine/render/shader_builder.cpp +++ b/engine/render/shader_builder.cpp @@ -94,6 +94,11 @@ namespace wmoge { return true; } + if (compute.has_value()) { + gfx_shader = gfx_driver->make_shader(compute->str(), layouts, key); + return true; + } + WG_LOG_ERROR("unknown shader modules combination"); return false; } diff --git a/engine/render/shader_manager.cpp b/engine/render/shader_manager.cpp index 36ff75fa7..c62e39441 100644 --- a/engine/render/shader_manager.cpp +++ b/engine/render/shader_manager.cpp @@ -44,6 +44,7 @@ #include "shaders/generated/auto_base_pass.hpp" #include "shaders/generated/auto_bloom_pass.hpp" #include "shaders/generated/auto_canvas_pass.hpp" +#include "shaders/generated/auto_composition_pass.hpp" #include "shaders/generated/auto_material_pass.hpp" #include "shaders/generated/auto_text_pass.hpp" #include "shaders/generated/auto_tonemap_pass.hpp" @@ -359,6 +360,7 @@ namespace wmoge { register_pass(std::make_unique()); register_pass(std::make_unique()); register_pass(std::make_unique()); + register_pass(std::make_unique()); } void ShaderManager::load_sources_from_disk() { WG_AUTO_PROFILE_RENDER("ShaderManager::load_sources_from_disk"); diff --git a/engine/render/shader_pass.cpp b/engine/render/shader_pass.cpp index f9abe97c4..e2407f9ce 100644 --- a/engine/render/shader_pass.cpp +++ b/engine/render/shader_pass.cpp @@ -39,10 +39,20 @@ namespace wmoge { GfxShaderLang gfx_lang = driver->shader_lang(); + const std::string& sources_vertex = get_vertex(gfx_lang); + const std::string& sources_fragment = get_fragment(gfx_lang); + const std::string& sources_compute = get_compute(gfx_lang); + + const bool has_vertex = !sources_vertex.empty(); + const bool has_fragment = !sources_fragment.empty(); + const bool has_compute = !sources_compute.empty(); + ShaderBuilder builder; builder.key = name; - builder.configure_vs(); - builder.configure_fs(); + + if (has_vertex) builder.configure_vs(); + if (has_fragment) builder.configure_fs(); + if (has_compute) builder.configure_cs(); if (gfx_lang == GfxShaderLang::GlslVk450) { builder.add_vs_module("#version 450 core\n"); @@ -63,18 +73,16 @@ namespace wmoge { int location_index = 0; - attribs.for_each([&](int i, GfxVertAttrib attrib) { - builder.add_define("ATTRIB_" + Enum::to_str(attrib)); - builder.vertex.value() << "layout(location = " << location_index << ") in " - << GfxVertAttribGlslTypes[i] << " " - << "in" << Enum::to_str(attrib) - << ";\n"; - location_index += 1; - }); - - const std::string& sources_vertex = get_vertex(gfx_lang); - const std::string& sources_fragment = get_fragment(gfx_lang); - const std::string& sources_compute = get_compute(gfx_lang); + if (has_vertex || has_fragment) { + attribs.for_each([&](int i, GfxVertAttrib attrib) { + builder.add_define("ATTRIB_" + Enum::to_str(attrib)); + builder.vertex.value() << "layout(location = " << location_index << ") in " + << GfxVertAttribGlslTypes[i] << " " + << "in" << Enum::to_str(attrib) + << ";\n"; + location_index += 1; + }); + } if (shader) { builder.add_vs_module(StringUtils::find_replace_first(sources_vertex, "__SHADER_CODE_VERTEX__", shader->get_include_parameters() + "\n" + shader->get_vertex())); diff --git a/engine/shaders/base.frag b/engine/shaders/base.frag index 92f932bf9..fa3e4f567 100644 --- a/engine/shaders/base.frag +++ b/engine/shaders/base.frag @@ -9,6 +9,7 @@ #include "inout_attributes.glsl" #include "common_funcs.glsl" +#include "color.glsl" layout (location = 0) out vec4 out_color; diff --git a/engine/shaders/bloom.comp b/engine/shaders/bloom.comp new file mode 100644 index 000000000..5f9ddbdf5 --- /dev/null +++ b/engine/shaders/bloom.comp @@ -0,0 +1,125 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/**********************************************************************************/ + +#include "common_funcs.glsl" +#include "color.glsl" + +// Better, temporally stable box filtering +// [Jimenez14] http://goo.gl/eomGso +// . . . . . . . +// . A . B . C . +// . . D . E . . +// . F . G . H . +// . . I . J . . +// . K . L . M . +// . . . . . . . +vec3 DownsampleBox13Tap(in vec2 uv) { + vec3 result = vec3(0,0,0); + + const vec3 A = textureOffset(Source, uv, ivec2(-2, -2)).rgb; + const vec3 B = textureOffset(Source, uv, ivec2( 0, -2)).rgb; + const vec3 C = textureOffset(Source, uv, ivec2( 2, -2)).rgb; + const vec3 D = textureOffset(Source, uv, ivec2(-1, -1)).rgb; + const vec3 E = textureOffset(Source, uv, ivec2( 1, -1)).rgb; + const vec3 F = textureOffset(Source, uv, ivec2(-2, 0)).rgb; + const vec3 G = textureOffset(Source, uv, ivec2( 0, 0)).rgb; + const vec3 H = textureOffset(Source, uv, ivec2( 2, 0)).rgb; + const vec3 I = textureOffset(Source, uv, ivec2(-1, 1)).rgb; + const vec3 J = textureOffset(Source, uv, ivec2( 1, 1)).rgb; + const vec3 K = textureOffset(Source, uv, ivec2(-2, 2)).rgb; + const vec3 L = textureOffset(Source, uv, ivec2( 0, 2)).rgb; + const vec3 M = textureOffset(Source, uv, ivec2( 2, 2)).rgb; + + const vec2 div = (1.0 / 4.0) * vec2(0.5, 0.125); + + result += (D + E + I + J) * div.x; + result += (A + B + G + F) * div.y; + result += (B + C + H + G) * div.y; + result += (F + G + L + K) * div.y; + result += (G + H + M + L) * div.y; + + return result; +} + +// Clamp color using user settings for bloom +// Settings: threshold and curve with knee param +vec4 Prefilter(vec3 color) { + color = QuadraticThreshold(color, ThresholdKnee.x, ThresholdKnee.yzw); + return vec4(color, 1.0f); +} + +vec4 DownsamplePrefilterPass(in vec2 uv) { + return Prefilter(DownsampleBox13Tap(uv)); +} + +vec4 DownsamplePass(in vec2 uv) { + return vec4(DownsampleBox13Tap(uv), 1.0f); +} + +// 9-tap bilinear upsampler (tent filter) +vec3 UpsampleTent(in vec2 uv) { + const vec2 texel = 1.0f / textureSize(Source, 0); + const vec2 offset = UpsampleRadius * texel; + + vec3 result = vec3(0,0,0); + + result += texture(SourcePrev, uv + offset * vec2(-1,-1)).rgb; + result += texture(SourcePrev, uv + offset * vec2( 0,-1)).rgb * 2.0; + result += texture(SourcePrev, uv + offset * vec2( 1,-1)).rgb; + + result += texture(SourcePrev, uv + offset * vec2(-1, 0)).rgb * 2.0; + result += texture(SourcePrev, uv + offset * vec2( 0, 0)).rgb * 4.0; + result += texture(SourcePrev, uv + offset * vec2( 1, 0)).rgb * 2.0; + + result += texture(SourcePrev, uv + offset * vec2(-1, 1)).rgb; + result += texture(SourcePrev, uv + offset * vec2( 0, 1)).rgb * 2.0; + result += texture(SourcePrev, uv + offset * vec2( 1, 1)).rgb; + + return result * (1.0f / 16.0f); +} + +vec4 Combine(vec3 bloom, in vec2 uv) { + vec3 color = texture(Source, uv).rgb; + vec3 mixed = mix(color, bloom, UpsampleWeight); + return vec4(mixed, 1.0f); +} + +vec4 UpsamplePass(in vec2 uv) { + return Combine(UpsampleTent(uv), uv); +} + +#define GROUP_SIZE_DEFAULT 8 + +layout (local_size_x = GROUP_SIZE_DEFAULT, local_size_y = GROUP_SIZE_DEFAULT, local_size_z = 1) in; + +void main() { + const uvec2 gid = gl_GlobalInvocationID.xy; + const ivec2 size = imageSize(Result); + const vec2 uv = vec2(gid) / vec2(size); + + if (gid.x >= size.x || gid.y >= size.y) { + return; + } + + vec4 outColor; + +#ifdef BLOOM_DOWNSAMPLE_PREFILTER + outColor = DownsamplePrefilterPass(uv); +#endif + +#ifdef BLOOM_DOWNSAMPLE + outColor = DownsamplePass(uv); +#endif + +#ifdef BLOOM_UPSAMPLE + outColor = UpsamplePass(uv); +#endif + + imageStore(Result, ivec2(gid), outColor); +} \ No newline at end of file diff --git a/engine/shaders/bloom.frag b/engine/shaders/bloom.frag index 9f570eca6..ba2276642 100644 --- a/engine/shaders/bloom.frag +++ b/engine/shaders/bloom.frag @@ -8,6 +8,7 @@ /**********************************************************************************/ #include "common_funcs.glsl" +#include "color.glsl" #include "inout_attributes.glsl" layout (location = 0) out vec4 out_color; diff --git a/engine/shaders/canvas.frag b/engine/shaders/canvas.frag index 40932fca4..b603bfb3a 100644 --- a/engine/shaders/canvas.frag +++ b/engine/shaders/canvas.frag @@ -8,6 +8,7 @@ /**********************************************************************************/ #include "common_funcs.glsl" +#include "color.glsl" #include "inout_attributes.glsl layout (location = 0) out vec4 out_color; diff --git a/engine/shaders/color.glsl b/engine/shaders/color.glsl new file mode 100644 index 000000000..15ee50689 --- /dev/null +++ b/engine/shaders/color.glsl @@ -0,0 +1,41 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/**********************************************************************************/ + +#include "common_defines.glsl" + +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); +} + +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} + +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} + +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + + return color; +} \ No newline at end of file diff --git a/engine/shaders/common_funcs.glsl b/engine/shaders/common_funcs.glsl index af266188b..045cfec6c 100644 --- a/engine/shaders/common_funcs.glsl +++ b/engine/shaders/common_funcs.glsl @@ -9,37 +9,6 @@ #include "common_defines.glsl" -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} - -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} - -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} - -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - - return color; -} - // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN diff --git a/engine/shaders/composition.frag b/engine/shaders/composition.frag new file mode 100644 index 000000000..58c5ff374 --- /dev/null +++ b/engine/shaders/composition.frag @@ -0,0 +1,21 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/**********************************************************************************/ + +#include "inout_attributes.glsl" + +layout (location = 0) out vec4 out_color; + +void main() { + const InoutAttributes attributes = ReadInoutAttributes(); + const vec2 uv = attributes.uv[0]; + + const vec4 ldrColor = texture(Color, uv).rgba; + + out_color = ldrColor; +} \ No newline at end of file diff --git a/engine/shaders/tonemap.vert b/engine/shaders/composition.vert similarity index 100% rename from engine/shaders/tonemap.vert rename to engine/shaders/composition.vert diff --git a/engine/shaders/generated/auto_base_gl410_frag.hpp b/engine/shaders/generated/auto_base_gl410_frag.hpp index 4b1c39424..d41ad37ac 100644 --- a/engine/shaders/generated/auto_base_gl410_frag.hpp +++ b/engine/shaders/generated/auto_base_gl410_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,6 +39,10 @@ namespace wmoge { static const char source_base_gl410_frag[] = R"( + + + + layout (std140) uniform Params { mat4 mat_clip_proj_view; vec4 base_color; @@ -213,6 +217,29 @@ InoutAttributes ReadInoutAttributes() { return attributes; } #endif//FRAGMENT_SHADER +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { return pow(color, vec3(gamma)); } @@ -237,29 +264,6 @@ vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) color *= max(rq, br - threshold) / max(br, EPSILON); return color; } -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} layout (location = 0) out vec4 out_color; void main() { InoutAttributes attributes = ReadInoutAttributes(); diff --git a/engine/shaders/generated/auto_base_gl410_vert.hpp b/engine/shaders/generated/auto_base_gl410_vert.hpp index 641f4c251..b7220102a 100644 --- a/engine/shaders/generated/auto_base_gl410_vert.hpp +++ b/engine/shaders/generated/auto_base_gl410_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,6 +39,10 @@ namespace wmoge { static const char source_base_gl410_vert[] = R"( + + + + layout (std140) uniform Params { mat4 mat_clip_proj_view; vec4 base_color; diff --git a/engine/shaders/generated/auto_base_pass.hpp b/engine/shaders/generated/auto_base_pass.hpp index bc7449a7c..ab3936443 100644 --- a/engine/shaders/generated/auto_base_pass.hpp +++ b/engine/shaders/generated/auto_base_pass.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_base_reflection.hpp b/engine/shaders/generated/auto_base_reflection.hpp index effe222bc..dfddcd6cd 100644 --- a/engine/shaders/generated/auto_base_reflection.hpp +++ b/engine/shaders/generated/auto_base_reflection.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_base_vk450_frag.hpp b/engine/shaders/generated/auto_base_vk450_frag.hpp index 5022cdd7d..007db3121 100644 --- a/engine/shaders/generated/auto_base_vk450_frag.hpp +++ b/engine/shaders/generated/auto_base_vk450_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,6 +39,10 @@ namespace wmoge { static const char source_base_vk450_frag[] = R"( + + + + layout (set = 0, binding = 0, std140) uniform Params { mat4 mat_clip_proj_view; vec4 base_color; @@ -213,6 +217,29 @@ InoutAttributes ReadInoutAttributes() { return attributes; } #endif//FRAGMENT_SHADER +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { return pow(color, vec3(gamma)); } @@ -237,29 +264,6 @@ vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) color *= max(rq, br - threshold) / max(br, EPSILON); return color; } -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} layout (location = 0) out vec4 out_color; void main() { InoutAttributes attributes = ReadInoutAttributes(); diff --git a/engine/shaders/generated/auto_base_vk450_vert.hpp b/engine/shaders/generated/auto_base_vk450_vert.hpp index 89fa17e1b..087ae75b2 100644 --- a/engine/shaders/generated/auto_base_vk450_vert.hpp +++ b/engine/shaders/generated/auto_base_vk450_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,6 +39,10 @@ namespace wmoge { static const char source_base_vk450_vert[] = R"( + + + + layout (set = 0, binding = 0, std140) uniform Params { mat4 mat_clip_proj_view; vec4 base_color; diff --git a/engine/shaders/generated/auto_bloom_gl410_frag.hpp b/engine/shaders/generated/auto_bloom_gl410_comp.hpp similarity index 63% rename from engine/shaders/generated/auto_bloom_gl410_frag.hpp rename to engine/shaders/generated/auto_bloom_gl410_comp.hpp index 9c6763519..33b8d552c 100644 --- a/engine/shaders/generated/auto_bloom_gl410_frag.hpp +++ b/engine/shaders/generated/auto_bloom_gl410_comp.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -38,13 +38,18 @@ namespace wmoge { - static const char source_bloom_gl410_frag[] = R"( + static const char source_bloom_gl410_comp[] = R"( + + uniform sampler2D Source; uniform sampler2D SourcePrev; + +layout (rgba16f) uniform writeonly image2D Result; + + layout (std140) uniform Params { -mat4 Clip; vec4 ThresholdKnee; float UpsampleRadius; float UpsampleWeight; @@ -70,30 +75,6 @@ float _pr_pad1; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN @@ -117,154 +98,30 @@ vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { return (normalMatrix * vec4(normLocal, 0.0f)).xyz; } -#ifdef VERTEX_SHADER - #define INOUT out -#endif -#ifdef FRAGMENT_SHADER - #define INOUT in -#endif -#ifndef INOUT - #error "Must be defined" -#endif -#if !defined(INOUT_DISABLE_POS) && (defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f)) - LAYOUT_LOCATION( 0) INOUT vec3 inout_worldPos; -#endif -#if !defined(INOUT_DISABLE_NORM) && defined(ATTRIB_Norm3f) - LAYOUT_LOCATION( 1) INOUT vec3 inout_worldNorm; -#endif -#ifdef ATTRIB_Tang3f - LAYOUT_LOCATION( 2) INOUT vec3 inout_worldTang; -#endif -#ifdef ATTRIB_Col04f - LAYOUT_LOCATION( 3) INOUT vec4 inout_col0; -#endif -#ifdef ATTRIB_Col14f - LAYOUT_LOCATION( 4) INOUT vec4 inout_col1; -#endif -#ifdef ATTRIB_Col24f - LAYOUT_LOCATION( 5) INOUT vec4 inout_col2; -#endif -#ifdef ATTRIB_Col34f - LAYOUT_LOCATION( 6) INOUT vec4 inout_col3; -#endif -#ifdef ATTRIB_Uv02f - LAYOUT_LOCATION( 7) INOUT vec2 inout_uv0; -#endif -#ifdef ATTRIB_Uv12f - LAYOUT_LOCATION( 8) INOUT vec2 inout_uv1; -#endif -#ifdef ATTRIB_Uv22f - LAYOUT_LOCATION( 9) INOUT vec2 inout_uv2; -#endif -#ifdef ATTRIB_Uv32f - LAYOUT_LOCATION(10) INOUT vec2 inout_uv3; -#endif -#ifdef ATTRIB_PrimitiveIdi - LAYOUT_LOCATION(11) flat INOUT int inout_primitiveId; -#endif -struct InoutAttributes { - vec3 worldPos; - vec3 worldNorm; - vec3 worldTang; - vec4 col[4]; - vec2 uv[4]; - int primitiveId; -}; -#ifdef VERTEX_SHADER -void StoreInoutAttributes(in InoutAttributes attributes) { - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - inout_worldPos = attributes.worldPos; - #endif - #ifdef ATTRIB_Norm3f - inout_worldNorm = attributes.worldNorm; - #endif - #ifdef ATTRIB_Tang3f - inout_worldTang = attributes.worldTang; - #endif - #ifdef ATTRIB_Col04f - inout_col0 = attributes.col[0]; - #endif - #ifdef ATTRIB_Col14f - inout_col1 = attributes.col[1]; - #endif - #ifdef ATTRIB_Col24f - inout_col2 = attributes.col[2]; - #endif - #ifdef ATTRIB_Col34f - inout_col3 = attributes.col[3]; - #endif - #ifdef ATTRIB_Uv02f - inout_uv0 = attributes.uv[0]; - #endif - #ifdef ATTRIB_Uv12f - inout_uv1 = attributes.uv[1]; - #endif - #ifdef ATTRIB_Uv22f - inout_uv2 = attributes.uv[2]; - #endif - #ifdef ATTRIB_Uv32f - inout_uv3 = attributes.uv[3]; - #endif - #ifdef ATTRIB_PrimitiveIdi - inout_primitiveId = attributes.primitiveId; - #endif +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); } -#endif//VERTEX_SHADER -#ifdef FRAGMENT_SHADER -InoutAttributes ReadInoutAttributes() { - InoutAttributes attributes; - attributes.worldPos = vec3(0,0,0); - attributes.worldNorm = vec3(0,0,0); - attributes.worldTang = vec3(0,0,0); - attributes.col[0] = vec4(0,0,0,0); - attributes.col[1] = vec4(0,0,0,0); - attributes.col[2] = vec4(0,0,0,0); - attributes.col[3] = vec4(0,0,0,0); - attributes.uv[0] = vec2(0,0); - attributes.uv[1] = vec2(0,0); - attributes.uv[2] = vec2(0,0); - attributes.uv[3] = vec2(0,0); - attributes.primitiveId = -1; - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - attributes.worldPos = inout_worldPos; - #endif - #ifdef ATTRIB_Norm3f - attributes.worldNorm = inout_worldNorm; - #endif - #ifdef ATTRIB_Tang3f - attributes.worldTang = inout_worldTang; - #endif - #ifdef ATTRIB_Col04f - attributes.col[0] = inout_col0; - #endif - #ifdef ATTRIB_Col14f - attributes.col[1] = inout_col1; - #endif - #ifdef ATTRIB_Col24f - attributes.col[2] = inout_col2; - #endif - #ifdef ATTRIB_Col34f - attributes.col[3] = inout_col3; - #endif - #ifdef ATTRIB_Uv02f - attributes.uv[0] = inout_uv0; - #endif - #ifdef ATTRIB_Uv12f - attributes.uv[1] = inout_uv1; - #endif - #ifdef ATTRIB_Uv22f - attributes.uv[2] = inout_uv2; - #endif - #ifdef ATTRIB_Uv32f - attributes.uv[3] = inout_uv3; - #endif - #ifdef ATTRIB_PrimitiveIdi - attributes.primitiveId = inout_primitiveId; - #endif - return attributes; +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; } -#endif//FRAGMENT_SHADER -layout (location = 0) out vec4 out_color; // Better, temporally stable box filtering // [Jimenez14] http://goo.gl/eomGso // . . . . . . . @@ -334,17 +191,26 @@ vec4 Combine(vec3 bloom, in vec2 uv) { vec4 UpsamplePass(in vec2 uv) { return Combine(UpsampleTent(uv), uv); } +#define GROUP_SIZE_DEFAULT 8 +layout (local_size_x = GROUP_SIZE_DEFAULT, local_size_y = GROUP_SIZE_DEFAULT, local_size_z = 1) in; void main() { - const InoutAttributes attributes = ReadInoutAttributes(); + const uvec2 gid = gl_GlobalInvocationID.xy; + const ivec2 size = imageSize(Result); + const vec2 uv = vec2(gid) / vec2(size); + if (gid.x >= size.x || gid.y >= size.y) { + return; + } + vec4 outColor; #ifdef BLOOM_DOWNSAMPLE_PREFILTER - out_color = DownsamplePrefilterPass(attributes.uv[0]); + outColor = DownsamplePrefilterPass(uv); #endif #ifdef BLOOM_DOWNSAMPLE - out_color = DownsamplePass(attributes.uv[0]); + outColor = DownsamplePass(uv); #endif #ifdef BLOOM_UPSAMPLE - out_color = UpsamplePass(attributes.uv[0]); + outColor = UpsamplePass(uv); #endif + imageStore(Result, ivec2(gid), outColor); } )"; diff --git a/engine/shaders/generated/auto_bloom_pass.hpp b/engine/shaders/generated/auto_bloom_pass.hpp index 1791ec657..13d4dac5f 100644 --- a/engine/shaders/generated/auto_bloom_pass.hpp +++ b/engine/shaders/generated/auto_bloom_pass.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -37,10 +37,8 @@ #include "math/vec.hpp" #include "render/shader_pass.hpp" -#include "auto_bloom_gl410_frag.hpp" -#include "auto_bloom_gl410_vert.hpp" -#include "auto_bloom_vk450_frag.hpp" -#include "auto_bloom_vk450_vert.hpp" +#include "auto_bloom_gl410_comp.hpp" +#include "auto_bloom_vk450_comp.hpp" namespace wmoge { /** @brief Auto generated pass for 'bloom' shader */ @@ -68,44 +66,35 @@ namespace wmoge { binding_SourcePrev.binding = 2; binding_SourcePrev.count = 1; binding_SourcePrev.type = GfxBindingType::SampledTexture; + auto& binding_Result = layout.emplace_back(); + binding_Result.name = SID("Result"); + binding_Result.binding = 3; + binding_Result.count = 1; + binding_Result.type = GfxBindingType::StorageImage; } } Status reload_sources(const std::string& folder, FileSystem* file_system) override { // lang is vk450 { - const auto file_path = folder + '/' + "auto_bloom_vk450_vert.glsl"; - if (file_system->read_file(file_path, m_vertex[0])) { + const auto file_path = folder + '/' + "auto_bloom_vk450_comp.glsl"; + if (file_system->read_file(file_path, m_compute[0])) { WG_LOG_INFO("reload shader from file " << file_path); } } // lang is gl410 { - const auto file_path = folder + '/' + "auto_bloom_gl410_vert.glsl"; - if (file_system->read_file(file_path, m_vertex[1])) { - WG_LOG_INFO("reload shader from file " << file_path); - } - } - // lang is vk450 - { - const auto file_path = folder + '/' + "auto_bloom_vk450_frag.glsl"; - if (file_system->read_file(file_path, m_fragment[0])) { - WG_LOG_INFO("reload shader from file " << file_path); - } - } - // lang is gl410 - { - const auto file_path = folder + '/' + "auto_bloom_gl410_frag.glsl"; - if (file_system->read_file(file_path, m_fragment[1])) { + const auto file_path = folder + '/' + "auto_bloom_gl410_comp.glsl"; + if (file_system->read_file(file_path, m_compute[1])) { WG_LOG_INFO("reload shader from file " << file_path); } } return StatusCode::Ok; } const std::string& get_vertex(GfxShaderLang lang) override { return m_vertex[int(lang)]; } - std::string m_vertex[2] = {source_bloom_vk450_vert, source_bloom_gl410_vert}; + std::string m_vertex[2]; const std::string& get_fragment(GfxShaderLang lang) override { return m_fragment[int(lang)]; } - std::string m_fragment[2] = {source_bloom_vk450_frag, source_bloom_gl410_frag}; + std::string m_fragment[2]; const std::string& get_compute(GfxShaderLang lang) override { return m_compute[int(lang)]; } - std::string m_compute[2]; + std::string m_compute[2] = {source_bloom_vk450_comp, source_bloom_gl410_comp}; }; }// namespace wmoge diff --git a/engine/shaders/generated/auto_bloom_reflection.hpp b/engine/shaders/generated/auto_bloom_reflection.hpp index b98f53814..e132999a2 100644 --- a/engine/shaders/generated/auto_bloom_reflection.hpp +++ b/engine/shaders/generated/auto_bloom_reflection.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -42,7 +42,7 @@ namespace wmoge { struct ShaderBloom { static constexpr const char NAME[] = "bloom"; static constexpr const char CLS[] = "Bloom"; - static constexpr int NUM_FILES = 2; + static constexpr int NUM_FILES = 1; static constexpr int NUM_CONSTS = 0; static constexpr int NUM_SAMPLERS = 2; static constexpr int NUM_BUFFERS = 1; @@ -57,13 +57,19 @@ namespace wmoge { static constexpr const auto SOURCEPREV_LOC = GfxLocation{0, 2}; static constexpr const char SOURCEPREV_NAME[] = "SourcePrev"; + static constexpr const int RESULT_SET = 0; + static constexpr const int RESULT_SLOT = 3; + static constexpr const auto RESULT_LOC = GfxLocation{0, 3}; + static constexpr const char RESULT_NAME[] = "Result"; + static constexpr const char RESULT_FORMAT[] = "rgba16f"; + static constexpr const char RESULT_QUALIFIER[] = "writeonly"; + struct Params { - Mat4x4f Clip; - Vec4f ThresholdKnee; - float UpsampleRadius; - float UpsampleWeight; - float _pr_pad0; - float _pr_pad1; + Vec4f ThresholdKnee; + float UpsampleRadius; + float UpsampleWeight; + float _pr_pad0; + float _pr_pad1; }; static constexpr const int PARAMS_SET = 0; diff --git a/engine/shaders/generated/auto_bloom_vk450_frag.hpp b/engine/shaders/generated/auto_bloom_vk450_comp.hpp similarity index 64% rename from engine/shaders/generated/auto_bloom_vk450_frag.hpp rename to engine/shaders/generated/auto_bloom_vk450_comp.hpp index c08b799d0..0f9712eb3 100644 --- a/engine/shaders/generated/auto_bloom_vk450_frag.hpp +++ b/engine/shaders/generated/auto_bloom_vk450_comp.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -38,13 +38,18 @@ namespace wmoge { - static const char source_bloom_vk450_frag[] = R"( + static const char source_bloom_vk450_comp[] = R"( + + layout (set = 0, binding = 1) uniform sampler2D Source; layout (set = 0, binding = 2) uniform sampler2D SourcePrev; + +layout (set = 0, binding = 3, rgba16f) uniform writeonly image2D Result; + + layout (set = 0, binding = 0, std140) uniform Params { -mat4 Clip; vec4 ThresholdKnee; float UpsampleRadius; float UpsampleWeight; @@ -70,30 +75,6 @@ float _pr_pad1; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN @@ -117,154 +98,30 @@ vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { return (normalMatrix * vec4(normLocal, 0.0f)).xyz; } -#ifdef VERTEX_SHADER - #define INOUT out -#endif -#ifdef FRAGMENT_SHADER - #define INOUT in -#endif -#ifndef INOUT - #error "Must be defined" -#endif -#if !defined(INOUT_DISABLE_POS) && (defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f)) - LAYOUT_LOCATION( 0) INOUT vec3 inout_worldPos; -#endif -#if !defined(INOUT_DISABLE_NORM) && defined(ATTRIB_Norm3f) - LAYOUT_LOCATION( 1) INOUT vec3 inout_worldNorm; -#endif -#ifdef ATTRIB_Tang3f - LAYOUT_LOCATION( 2) INOUT vec3 inout_worldTang; -#endif -#ifdef ATTRIB_Col04f - LAYOUT_LOCATION( 3) INOUT vec4 inout_col0; -#endif -#ifdef ATTRIB_Col14f - LAYOUT_LOCATION( 4) INOUT vec4 inout_col1; -#endif -#ifdef ATTRIB_Col24f - LAYOUT_LOCATION( 5) INOUT vec4 inout_col2; -#endif -#ifdef ATTRIB_Col34f - LAYOUT_LOCATION( 6) INOUT vec4 inout_col3; -#endif -#ifdef ATTRIB_Uv02f - LAYOUT_LOCATION( 7) INOUT vec2 inout_uv0; -#endif -#ifdef ATTRIB_Uv12f - LAYOUT_LOCATION( 8) INOUT vec2 inout_uv1; -#endif -#ifdef ATTRIB_Uv22f - LAYOUT_LOCATION( 9) INOUT vec2 inout_uv2; -#endif -#ifdef ATTRIB_Uv32f - LAYOUT_LOCATION(10) INOUT vec2 inout_uv3; -#endif -#ifdef ATTRIB_PrimitiveIdi - LAYOUT_LOCATION(11) flat INOUT int inout_primitiveId; -#endif -struct InoutAttributes { - vec3 worldPos; - vec3 worldNorm; - vec3 worldTang; - vec4 col[4]; - vec2 uv[4]; - int primitiveId; -}; -#ifdef VERTEX_SHADER -void StoreInoutAttributes(in InoutAttributes attributes) { - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - inout_worldPos = attributes.worldPos; - #endif - #ifdef ATTRIB_Norm3f - inout_worldNorm = attributes.worldNorm; - #endif - #ifdef ATTRIB_Tang3f - inout_worldTang = attributes.worldTang; - #endif - #ifdef ATTRIB_Col04f - inout_col0 = attributes.col[0]; - #endif - #ifdef ATTRIB_Col14f - inout_col1 = attributes.col[1]; - #endif - #ifdef ATTRIB_Col24f - inout_col2 = attributes.col[2]; - #endif - #ifdef ATTRIB_Col34f - inout_col3 = attributes.col[3]; - #endif - #ifdef ATTRIB_Uv02f - inout_uv0 = attributes.uv[0]; - #endif - #ifdef ATTRIB_Uv12f - inout_uv1 = attributes.uv[1]; - #endif - #ifdef ATTRIB_Uv22f - inout_uv2 = attributes.uv[2]; - #endif - #ifdef ATTRIB_Uv32f - inout_uv3 = attributes.uv[3]; - #endif - #ifdef ATTRIB_PrimitiveIdi - inout_primitiveId = attributes.primitiveId; - #endif +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); } -#endif//VERTEX_SHADER -#ifdef FRAGMENT_SHADER -InoutAttributes ReadInoutAttributes() { - InoutAttributes attributes; - attributes.worldPos = vec3(0,0,0); - attributes.worldNorm = vec3(0,0,0); - attributes.worldTang = vec3(0,0,0); - attributes.col[0] = vec4(0,0,0,0); - attributes.col[1] = vec4(0,0,0,0); - attributes.col[2] = vec4(0,0,0,0); - attributes.col[3] = vec4(0,0,0,0); - attributes.uv[0] = vec2(0,0); - attributes.uv[1] = vec2(0,0); - attributes.uv[2] = vec2(0,0); - attributes.uv[3] = vec2(0,0); - attributes.primitiveId = -1; - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - attributes.worldPos = inout_worldPos; - #endif - #ifdef ATTRIB_Norm3f - attributes.worldNorm = inout_worldNorm; - #endif - #ifdef ATTRIB_Tang3f - attributes.worldTang = inout_worldTang; - #endif - #ifdef ATTRIB_Col04f - attributes.col[0] = inout_col0; - #endif - #ifdef ATTRIB_Col14f - attributes.col[1] = inout_col1; - #endif - #ifdef ATTRIB_Col24f - attributes.col[2] = inout_col2; - #endif - #ifdef ATTRIB_Col34f - attributes.col[3] = inout_col3; - #endif - #ifdef ATTRIB_Uv02f - attributes.uv[0] = inout_uv0; - #endif - #ifdef ATTRIB_Uv12f - attributes.uv[1] = inout_uv1; - #endif - #ifdef ATTRIB_Uv22f - attributes.uv[2] = inout_uv2; - #endif - #ifdef ATTRIB_Uv32f - attributes.uv[3] = inout_uv3; - #endif - #ifdef ATTRIB_PrimitiveIdi - attributes.primitiveId = inout_primitiveId; - #endif - return attributes; +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; } -#endif//FRAGMENT_SHADER -layout (location = 0) out vec4 out_color; // Better, temporally stable box filtering // [Jimenez14] http://goo.gl/eomGso // . . . . . . . @@ -334,17 +191,26 @@ vec4 Combine(vec3 bloom, in vec2 uv) { vec4 UpsamplePass(in vec2 uv) { return Combine(UpsampleTent(uv), uv); } +#define GROUP_SIZE_DEFAULT 8 +layout (local_size_x = GROUP_SIZE_DEFAULT, local_size_y = GROUP_SIZE_DEFAULT, local_size_z = 1) in; void main() { - const InoutAttributes attributes = ReadInoutAttributes(); + const uvec2 gid = gl_GlobalInvocationID.xy; + const ivec2 size = imageSize(Result); + const vec2 uv = vec2(gid) / vec2(size); + if (gid.x >= size.x || gid.y >= size.y) { + return; + } + vec4 outColor; #ifdef BLOOM_DOWNSAMPLE_PREFILTER - out_color = DownsamplePrefilterPass(attributes.uv[0]); + outColor = DownsamplePrefilterPass(uv); #endif #ifdef BLOOM_DOWNSAMPLE - out_color = DownsamplePass(attributes.uv[0]); + outColor = DownsamplePass(uv); #endif #ifdef BLOOM_UPSAMPLE - out_color = UpsamplePass(attributes.uv[0]); + outColor = UpsamplePass(uv); #endif + imageStore(Result, ivec2(gid), outColor); } )"; diff --git a/engine/shaders/generated/auto_canvas_gl410_frag.hpp b/engine/shaders/generated/auto_canvas_gl410_frag.hpp index f9adbf1d3..b9347daa7 100644 --- a/engine/shaders/generated/auto_canvas_gl410_frag.hpp +++ b/engine/shaders/generated/auto_canvas_gl410_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -50,6 +50,7 @@ int _dc_pad1; int _dc_pad2; }; + #define MAX_CANVAS_IMAGES (4) uniform sampler2D CanvasImage0; @@ -60,6 +61,8 @@ uniform sampler2D CanvasImage2; uniform sampler2D CanvasImage3; + + layout (std140) uniform Params { mat4 ClipProjView; float InverseGamma; @@ -90,6 +93,29 @@ DrawCmdData DrawCmds[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { return pow(color, vec3(gamma)); } @@ -114,29 +140,6 @@ vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) color *= max(rq, br - threshold) / max(br, EPSILON); return color; } -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} #ifdef VERTEX_SHADER #define INOUT out #endif diff --git a/engine/shaders/generated/auto_canvas_gl410_vert.hpp b/engine/shaders/generated/auto_canvas_gl410_vert.hpp index 9adea157d..cfd0f3086 100644 --- a/engine/shaders/generated/auto_canvas_gl410_vert.hpp +++ b/engine/shaders/generated/auto_canvas_gl410_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -50,6 +50,7 @@ int _dc_pad1; int _dc_pad2; }; + #define MAX_CANVAS_IMAGES (4) uniform sampler2D CanvasImage0; @@ -60,6 +61,8 @@ uniform sampler2D CanvasImage2; uniform sampler2D CanvasImage3; + + layout (std140) uniform Params { mat4 ClipProjView; float InverseGamma; @@ -90,30 +93,6 @@ DrawCmdData DrawCmds[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN diff --git a/engine/shaders/generated/auto_canvas_pass.hpp b/engine/shaders/generated/auto_canvas_pass.hpp index 070320760..3c5f20301 100644 --- a/engine/shaders/generated/auto_canvas_pass.hpp +++ b/engine/shaders/generated/auto_canvas_pass.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_canvas_reflection.hpp b/engine/shaders/generated/auto_canvas_reflection.hpp index f9715154c..b84bfbe0f 100644 --- a/engine/shaders/generated/auto_canvas_reflection.hpp +++ b/engine/shaders/generated/auto_canvas_reflection.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_canvas_vk450_frag.hpp b/engine/shaders/generated/auto_canvas_vk450_frag.hpp index 190101563..806fd188c 100644 --- a/engine/shaders/generated/auto_canvas_vk450_frag.hpp +++ b/engine/shaders/generated/auto_canvas_vk450_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -50,6 +50,7 @@ int _dc_pad1; int _dc_pad2; }; + #define MAX_CANVAS_IMAGES (4) layout (set = 1, binding = 0) uniform sampler2D CanvasImage0; @@ -60,6 +61,8 @@ layout (set = 1, binding = 2) uniform sampler2D CanvasImage2; layout (set = 1, binding = 3) uniform sampler2D CanvasImage3; + + layout (set = 0, binding = 0, std140) uniform Params { mat4 ClipProjView; float InverseGamma; @@ -90,6 +93,29 @@ DrawCmdData DrawCmds[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { return pow(color, vec3(gamma)); } @@ -114,29 +140,6 @@ vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) color *= max(rq, br - threshold) / max(br, EPSILON); return color; } -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} #ifdef VERTEX_SHADER #define INOUT out #endif diff --git a/engine/shaders/generated/auto_canvas_vk450_vert.hpp b/engine/shaders/generated/auto_canvas_vk450_vert.hpp index 1dde94c11..c8d43806b 100644 --- a/engine/shaders/generated/auto_canvas_vk450_vert.hpp +++ b/engine/shaders/generated/auto_canvas_vk450_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -50,6 +50,7 @@ int _dc_pad1; int _dc_pad2; }; + #define MAX_CANVAS_IMAGES (4) layout (set = 1, binding = 0) uniform sampler2D CanvasImage0; @@ -60,6 +61,8 @@ layout (set = 1, binding = 2) uniform sampler2D CanvasImage2; layout (set = 1, binding = 3) uniform sampler2D CanvasImage3; + + layout (set = 0, binding = 0, std140) uniform Params { mat4 ClipProjView; float InverseGamma; @@ -90,30 +93,6 @@ DrawCmdData DrawCmds[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN diff --git a/engine/shaders/generated/auto_tonemap_gl410_frag.hpp b/engine/shaders/generated/auto_composition_gl410_frag.hpp similarity index 64% rename from engine/shaders/generated/auto_tonemap_gl410_frag.hpp rename to engine/shaders/generated/auto_composition_gl410_frag.hpp index 79f458c51..8c9e05c14 100644 --- a/engine/shaders/generated/auto_tonemap_gl410_frag.hpp +++ b/engine/shaders/generated/auto_composition_gl410_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -38,33 +38,18 @@ namespace wmoge { - static const char source_tonemap_gl410_frag[] = R"( -#define TONEMAP_MODE_EXP (0) + static const char source_composition_gl410_frag[] = R"( -#define TONEMAP_MODE_REINH (1) -#define TONEMAP_MODE_REINH_EXT (2) +uniform sampler2D Color; -#define TONEMAP_MODE_ACES (3) -#define TONEMAP_MODE_UN2 (4) - -uniform sampler2D Image; - -uniform sampler2D Bloom; - -uniform sampler2D BloomDirtMask; layout (std140) uniform Params { mat4 Clip; +uvec2 TargetSize; +float Gamma; float InverseGamma; -float Mode; -float Exposure; -float BloomIntensity; -float BloomDirtMaskIntensity; -float WhitePoint; -float _pd_pad0; -float _pd_pad1; }; @@ -85,53 +70,6 @@ float _pd_pad1; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} #ifdef VERTEX_SHADER #define INOUT out #endif @@ -279,66 +217,13 @@ InoutAttributes ReadInoutAttributes() { return attributes; } #endif//FRAGMENT_SHADER -vec3 TonemapReinhard(in vec3 color) { - return color / (color + vec3(1,1,1)); -} -vec3 TonemapReinhardExtended(in vec3 color, in float maxWhite) { - return (color * (vec3(1,1,1) + color / sqrt(maxWhite)) ) / (vec3(1,1,1) + color); -} -vec3 TonemapExp(in vec3 color, in float exposure) { - return vec3(1,1,1) - exp(-color * exposure); -} -vec3 TonemapACES(vec3 color) { - const float A = 2.51; - const float B = 0.03; - const float C = 2.43; - const float D = 0.59; - const float E = 0.14; - - return (color * (A * color + B)) / (color * (C * color + D) + E); -} -vec3 TonemapUncharted2(in vec3 color) { - const float A = 0.15; - const float B = 0.50; - const float C = 0.10; - const float D = 0.20; - const float E = 0.02; - const float F = 0.30; - const float W = 11.2; - return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F) ) - E / F; -} layout (location = 0) out vec4 out_color; void main() { const InoutAttributes attributes = ReadInoutAttributes(); const vec2 uv = attributes.uv[0]; - const vec3 hdrSrcColor = texture(Image, uv).rgb; - const vec3 hdrBloom = texture(Bloom, uv).rgb * BloomIntensity; - const vec3 hdrBloomDirt = texture(BloomDirtMask, uv).rgb * BloomDirtMaskIntensity; - const vec3 hdrColor = hdrSrcColor + hdrBloom + hdrBloom * hdrBloomDirt; - vec3 ldrColor = hdrColor; - const int tonemapMode = int(Mode); - switch (tonemapMode) { - case TONEMAP_MODE_EXP: - ldrColor = TonemapExp(hdrColor, Exposure); - break; - case TONEMAP_MODE_REINH: - ldrColor = TonemapReinhard(hdrColor); - break; - case TONEMAP_MODE_REINH_EXT: - ldrColor = TonemapReinhardExtended(hdrColor, WhitePoint); - break; - case TONEMAP_MODE_ACES: - ldrColor = TonemapACES(hdrColor); - break; - case TONEMAP_MODE_UN2: - ldrColor = TonemapUncharted2(hdrColor); - break; - default: - break; - } - const vec3 gammaColor = ColorLinearToSrgb(ldrColor, InverseGamma); - out_color = vec4(gammaColor, 1.0f); + const vec4 ldrColor = texture(Color, uv).rgba; + out_color = ldrColor; } )"; diff --git a/engine/shaders/generated/auto_bloom_gl410_vert.hpp b/engine/shaders/generated/auto_composition_gl410_vert.hpp similarity index 89% rename from engine/shaders/generated/auto_bloom_gl410_vert.hpp rename to engine/shaders/generated/auto_composition_gl410_vert.hpp index aab048f75..6f3768d6e 100644 --- a/engine/shaders/generated/auto_bloom_gl410_vert.hpp +++ b/engine/shaders/generated/auto_composition_gl410_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -38,18 +38,18 @@ namespace wmoge { - static const char source_bloom_gl410_vert[] = R"( -uniform sampler2D Source; + static const char source_composition_gl410_vert[] = R"( + + +uniform sampler2D Color; + -uniform sampler2D SourcePrev; layout (std140) uniform Params { mat4 Clip; -vec4 ThresholdKnee; -float UpsampleRadius; -float UpsampleWeight; -float _pr_pad0; -float _pr_pad1; +uvec2 TargetSize; +float Gamma; +float InverseGamma; }; @@ -70,30 +70,6 @@ float _pr_pad1; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN diff --git a/engine/shaders/generated/auto_composition_pass.hpp b/engine/shaders/generated/auto_composition_pass.hpp new file mode 100644 index 000000000..08aab199a --- /dev/null +++ b/engine/shaders/generated/auto_composition_pass.hpp @@ -0,0 +1,120 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify + +#pragma once + +#include "core/string_id.hpp" +#include "core/string_utf.hpp" +#include "core/string_utils.hpp" +#include "gfx/gfx_defs.hpp" +#include "math/mat.hpp" +#include "math/vec.hpp" +#include "render/shader_pass.hpp" + +#include "auto_composition_gl410_frag.hpp" +#include "auto_composition_gl410_vert.hpp" +#include "auto_composition_vk450_frag.hpp" +#include "auto_composition_vk450_vert.hpp" + +namespace wmoge { + /** @brief Auto generated pass for 'composition' shader */ + class ShaderPassComposition final : public ShaderPass { + public: + ShaderPassComposition() = default; + ~ShaderPassComposition() override = default; + StringId get_name() override { return SID("composition"); } + void fill_layout(GfxDescSetLayoutDescs& layouts_desc, Shader* shader) override { + // fill set num = 0 + { + auto& layout = layouts_desc.emplace_back(); + auto& binding_Params = layout.emplace_back(); + binding_Params.name = SID("Params"); + binding_Params.binding = 0; + binding_Params.count = 1; + binding_Params.type = GfxBindingType::UniformBuffer; + auto& binding_Color = layout.emplace_back(); + binding_Color.name = SID("Color"); + binding_Color.binding = 1; + binding_Color.count = 1; + binding_Color.type = GfxBindingType::SampledTexture; + } + } + Status reload_sources(const std::string& folder, FileSystem* file_system) override { + // lang is vk450 + { + const auto file_path = folder + '/' + "auto_composition_vk450_vert.glsl"; + if (file_system->read_file(file_path, m_vertex[0])) { + WG_LOG_INFO("reload shader from file " << file_path); + } + } + // lang is gl410 + { + const auto file_path = folder + '/' + "auto_composition_gl410_vert.glsl"; + if (file_system->read_file(file_path, m_vertex[1])) { + WG_LOG_INFO("reload shader from file " << file_path); + } + } + // lang is vk450 + { + const auto file_path = folder + '/' + "auto_composition_vk450_frag.glsl"; + if (file_system->read_file(file_path, m_fragment[0])) { + WG_LOG_INFO("reload shader from file " << file_path); + } + } + // lang is gl410 + { + const auto file_path = folder + '/' + "auto_composition_gl410_frag.glsl"; + if (file_system->read_file(file_path, m_fragment[1])) { + WG_LOG_INFO("reload shader from file " << file_path); + } + } + // lang is vk450 + { + const auto file_path = folder + '/' + "auto_composition_vk450_vert.glsl"; + if (file_system->read_file(file_path, m_compute[0])) { + WG_LOG_INFO("reload shader from file " << file_path); + } + } + // lang is gl410 + { + const auto file_path = folder + '/' + "auto_composition_gl410_vert.glsl"; + if (file_system->read_file(file_path, m_compute[1])) { + WG_LOG_INFO("reload shader from file " << file_path); + } + } + return StatusCode::Ok; + } + const std::string& get_vertex(GfxShaderLang lang) override { return m_vertex[int(lang)]; } + std::string m_vertex[2] = {source_composition_vk450_vert, source_composition_gl410_vert}; + const std::string& get_fragment(GfxShaderLang lang) override { return m_fragment[int(lang)]; } + std::string m_fragment[2] = {source_composition_vk450_frag, source_composition_gl410_frag}; + const std::string& get_compute(GfxShaderLang lang) override { return m_compute[int(lang)]; } + std::string m_compute[2] = {source_composition_vk450_vert, source_composition_gl410_vert}; + }; +}// namespace wmoge diff --git a/engine/shaders/generated/auto_composition_reflection.hpp b/engine/shaders/generated/auto_composition_reflection.hpp new file mode 100644 index 000000000..fd3fefe09 --- /dev/null +++ b/engine/shaders/generated/auto_composition_reflection.hpp @@ -0,0 +1,68 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify + +#pragma once + +#include "core/string_id.hpp" +#include "core/string_utf.hpp" +#include "core/string_utils.hpp" +#include "gfx/gfx_defs.hpp" +#include "math/mat.hpp" +#include "math/vec.hpp" + +namespace wmoge { + + /** @brief Auto generated reflection for 'composition' shader */ + struct ShaderComposition { + static constexpr const char NAME[] = "composition"; + static constexpr const char CLS[] = "Composition"; + static constexpr int NUM_FILES = 2; + static constexpr int NUM_CONSTS = 0; + static constexpr int NUM_SAMPLERS = 1; + static constexpr int NUM_BUFFERS = 1; + + static constexpr const int COLOR_SET = 0; + static constexpr const int COLOR_SLOT = 1; + static constexpr const auto COLOR_LOC = GfxLocation{0, 1}; + static constexpr const char COLOR_NAME[] = "Color"; + + struct Params { + Mat4x4f Clip; + Vec2u TargetSize; + float Gamma; + float InverseGamma; + }; + + static constexpr const int PARAMS_SET = 0; + static constexpr const int PARAMS_SLOT = 0; + static constexpr const auto PARAMS_LOC = GfxLocation{0, 0}; + static constexpr const char PARAMS_NAME[] = "Params"; + }; + +}// namespace wmoge diff --git a/engine/shaders/generated/auto_tonemap_vk450_frag.hpp b/engine/shaders/generated/auto_composition_vk450_frag.hpp similarity index 64% rename from engine/shaders/generated/auto_tonemap_vk450_frag.hpp rename to engine/shaders/generated/auto_composition_vk450_frag.hpp index e2a6c8c40..8bdd3ed66 100644 --- a/engine/shaders/generated/auto_tonemap_vk450_frag.hpp +++ b/engine/shaders/generated/auto_composition_vk450_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -38,33 +38,18 @@ namespace wmoge { - static const char source_tonemap_vk450_frag[] = R"( -#define TONEMAP_MODE_EXP (0) + static const char source_composition_vk450_frag[] = R"( -#define TONEMAP_MODE_REINH (1) -#define TONEMAP_MODE_REINH_EXT (2) +layout (set = 0, binding = 1) uniform sampler2D Color; -#define TONEMAP_MODE_ACES (3) -#define TONEMAP_MODE_UN2 (4) - -layout (set = 0, binding = 1) uniform sampler2D Image; - -layout (set = 0, binding = 2) uniform sampler2D Bloom; - -layout (set = 0, binding = 3) uniform sampler2D BloomDirtMask; layout (set = 0, binding = 0, std140) uniform Params { mat4 Clip; +uvec2 TargetSize; +float Gamma; float InverseGamma; -float Mode; -float Exposure; -float BloomIntensity; -float BloomDirtMaskIntensity; -float WhitePoint; -float _pd_pad0; -float _pd_pad1; }; @@ -85,53 +70,6 @@ float _pd_pad1; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} #ifdef VERTEX_SHADER #define INOUT out #endif @@ -279,66 +217,13 @@ InoutAttributes ReadInoutAttributes() { return attributes; } #endif//FRAGMENT_SHADER -vec3 TonemapReinhard(in vec3 color) { - return color / (color + vec3(1,1,1)); -} -vec3 TonemapReinhardExtended(in vec3 color, in float maxWhite) { - return (color * (vec3(1,1,1) + color / sqrt(maxWhite)) ) / (vec3(1,1,1) + color); -} -vec3 TonemapExp(in vec3 color, in float exposure) { - return vec3(1,1,1) - exp(-color * exposure); -} -vec3 TonemapACES(vec3 color) { - const float A = 2.51; - const float B = 0.03; - const float C = 2.43; - const float D = 0.59; - const float E = 0.14; - - return (color * (A * color + B)) / (color * (C * color + D) + E); -} -vec3 TonemapUncharted2(in vec3 color) { - const float A = 0.15; - const float B = 0.50; - const float C = 0.10; - const float D = 0.20; - const float E = 0.02; - const float F = 0.30; - const float W = 11.2; - return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F) ) - E / F; -} layout (location = 0) out vec4 out_color; void main() { const InoutAttributes attributes = ReadInoutAttributes(); const vec2 uv = attributes.uv[0]; - const vec3 hdrSrcColor = texture(Image, uv).rgb; - const vec3 hdrBloom = texture(Bloom, uv).rgb * BloomIntensity; - const vec3 hdrBloomDirt = texture(BloomDirtMask, uv).rgb * BloomDirtMaskIntensity; - const vec3 hdrColor = hdrSrcColor + hdrBloom + hdrBloom * hdrBloomDirt; - vec3 ldrColor = hdrColor; - const int tonemapMode = int(Mode); - switch (tonemapMode) { - case TONEMAP_MODE_EXP: - ldrColor = TonemapExp(hdrColor, Exposure); - break; - case TONEMAP_MODE_REINH: - ldrColor = TonemapReinhard(hdrColor); - break; - case TONEMAP_MODE_REINH_EXT: - ldrColor = TonemapReinhardExtended(hdrColor, WhitePoint); - break; - case TONEMAP_MODE_ACES: - ldrColor = TonemapACES(hdrColor); - break; - case TONEMAP_MODE_UN2: - ldrColor = TonemapUncharted2(hdrColor); - break; - default: - break; - } - const vec3 gammaColor = ColorLinearToSrgb(ldrColor, InverseGamma); - out_color = vec4(gammaColor, 1.0f); + const vec4 ldrColor = texture(Color, uv).rgba; + out_color = ldrColor; } )"; diff --git a/engine/shaders/generated/auto_bloom_vk450_vert.hpp b/engine/shaders/generated/auto_composition_vk450_vert.hpp similarity index 89% rename from engine/shaders/generated/auto_bloom_vk450_vert.hpp rename to engine/shaders/generated/auto_composition_vk450_vert.hpp index 8ada755d3..8246342aa 100644 --- a/engine/shaders/generated/auto_bloom_vk450_vert.hpp +++ b/engine/shaders/generated/auto_composition_vk450_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -38,18 +38,18 @@ namespace wmoge { - static const char source_bloom_vk450_vert[] = R"( -layout (set = 0, binding = 1) uniform sampler2D Source; + static const char source_composition_vk450_vert[] = R"( + + +layout (set = 0, binding = 1) uniform sampler2D Color; + -layout (set = 0, binding = 2) uniform sampler2D SourcePrev; layout (set = 0, binding = 0, std140) uniform Params { mat4 Clip; -vec4 ThresholdKnee; -float UpsampleRadius; -float UpsampleWeight; -float _pr_pad0; -float _pr_pad1; +uvec2 TargetSize; +float Gamma; +float InverseGamma; }; @@ -70,30 +70,6 @@ float _pr_pad1; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN diff --git a/engine/shaders/generated/auto_material_gl410_frag.hpp b/engine/shaders/generated/auto_material_gl410_frag.hpp index 101bb5574..0e1c927df 100644 --- a/engine/shaders/generated/auto_material_gl410_frag.hpp +++ b/engine/shaders/generated/auto_material_gl410_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -48,6 +48,10 @@ vec4 AabbPos; vec4 AabbSizeHalf; }; + + + + layout (std140) uniform FrameData { float time; float timeDelta; @@ -101,30 +105,6 @@ RenderObjectData RenderObjects[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN @@ -313,6 +293,30 @@ vec3 TransformLocalToWorld(in vec3 posLocal, in int primitiveId) { vec3 TransformLocalToWorldNormal(in vec3 normLocal, in int primitiveId) { return TransformLocalToWorldNormal(normLocal, GetRenderObjectDataById(primitiveId).NormalMatrix); } +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); +} +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; +} struct MaterialAttributes { vec4 baseColor; vec3 worldNorm; diff --git a/engine/shaders/generated/auto_material_gl410_vert.hpp b/engine/shaders/generated/auto_material_gl410_vert.hpp index efc4cbe32..b935c76ee 100644 --- a/engine/shaders/generated/auto_material_gl410_vert.hpp +++ b/engine/shaders/generated/auto_material_gl410_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -48,6 +48,10 @@ vec4 AabbPos; vec4 AabbSizeHalf; }; + + + + layout (std140) uniform FrameData { float time; float timeDelta; @@ -101,30 +105,6 @@ RenderObjectData RenderObjects[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN @@ -393,6 +373,30 @@ vec3 TransformLocalToWorld(in vec3 posLocal, in int primitiveId) { vec3 TransformLocalToWorldNormal(in vec3 normLocal, in int primitiveId) { return TransformLocalToWorldNormal(normLocal, GetRenderObjectDataById(primitiveId).NormalMatrix); } +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); +} +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; +} struct ShaderInoutVs { VertexAttributes attributes; InoutAttributes result; diff --git a/engine/shaders/generated/auto_material_pass.hpp b/engine/shaders/generated/auto_material_pass.hpp index 3b832d658..a312e6d7f 100644 --- a/engine/shaders/generated/auto_material_pass.hpp +++ b/engine/shaders/generated/auto_material_pass.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_material_reflection.hpp b/engine/shaders/generated/auto_material_reflection.hpp index a1a2005e8..827f329b3 100644 --- a/engine/shaders/generated/auto_material_reflection.hpp +++ b/engine/shaders/generated/auto_material_reflection.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_material_vk450_frag.hpp b/engine/shaders/generated/auto_material_vk450_frag.hpp index 8d5e35a09..cd2bff3c7 100644 --- a/engine/shaders/generated/auto_material_vk450_frag.hpp +++ b/engine/shaders/generated/auto_material_vk450_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -48,6 +48,10 @@ vec4 AabbPos; vec4 AabbSizeHalf; }; + + + + layout (set = 0, binding = 0, std140) uniform FrameData { float time; float timeDelta; @@ -101,30 +105,6 @@ RenderObjectData RenderObjects[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN @@ -313,6 +293,30 @@ vec3 TransformLocalToWorld(in vec3 posLocal, in int primitiveId) { vec3 TransformLocalToWorldNormal(in vec3 normLocal, in int primitiveId) { return TransformLocalToWorldNormal(normLocal, GetRenderObjectDataById(primitiveId).NormalMatrix); } +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); +} +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; +} struct MaterialAttributes { vec4 baseColor; vec3 worldNorm; diff --git a/engine/shaders/generated/auto_material_vk450_vert.hpp b/engine/shaders/generated/auto_material_vk450_vert.hpp index faf0c2367..6b57a314b 100644 --- a/engine/shaders/generated/auto_material_vk450_vert.hpp +++ b/engine/shaders/generated/auto_material_vk450_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -48,6 +48,10 @@ vec4 AabbPos; vec4 AabbSizeHalf; }; + + + + layout (set = 0, binding = 0, std140) uniform FrameData { float time; float timeDelta; @@ -101,30 +105,6 @@ RenderObjectData RenderObjects[]; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN @@ -393,6 +373,30 @@ vec3 TransformLocalToWorld(in vec3 posLocal, in int primitiveId) { vec3 TransformLocalToWorldNormal(in vec3 normLocal, in int primitiveId) { return TransformLocalToWorldNormal(normLocal, GetRenderObjectDataById(primitiveId).NormalMatrix); } +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); +} +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; +} struct ShaderInoutVs { VertexAttributes attributes; InoutAttributes result; diff --git a/engine/shaders/generated/auto_text_gl410_frag.hpp b/engine/shaders/generated/auto_text_gl410_frag.hpp index 57a54e98b..240af06a4 100644 --- a/engine/shaders/generated/auto_text_gl410_frag.hpp +++ b/engine/shaders/generated/auto_text_gl410_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,8 +39,12 @@ namespace wmoge { static const char source_text_gl410_frag[] = R"( + + uniform sampler2D FontTexture; + + layout (std140) uniform Params { mat4 mat_clip_proj_screen; float inverse_gamma; @@ -67,6 +71,29 @@ float __pad_3; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { return pow(color, vec3(gamma)); } @@ -91,36 +118,13 @@ vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) color *= max(rq, br - threshold) / max(br, EPSILON); return color; } -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} layout (location = 0) out vec4 out_color; LAYOUT_LOCATION(0) in vec4 fsCol04f; LAYOUT_LOCATION(1) in vec2 fsUv02f; void main() { vec4 result_color = vec4(fsCol04f.rgb, fsCol04f.a * texture(FontTexture, fsUv02f).r); #ifdef OUT_SRGB - result_color.rgb = ColorLinearToSrgb(result_color.rgb, inverse_gamma); + result_color.rgb = ColorLinearToSrgb(result_color.rgb, inverse_gamma); #endif out_color = result_color; } diff --git a/engine/shaders/generated/auto_text_gl410_vert.hpp b/engine/shaders/generated/auto_text_gl410_vert.hpp index 4323cac32..19e2e0a83 100644 --- a/engine/shaders/generated/auto_text_gl410_vert.hpp +++ b/engine/shaders/generated/auto_text_gl410_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,8 +39,12 @@ namespace wmoge { static const char source_text_gl410_vert[] = R"( + + uniform sampler2D FontTexture; + + layout (std140) uniform Params { mat4 mat_clip_proj_screen; float inverse_gamma; @@ -67,30 +71,6 @@ float __pad_3; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN diff --git a/engine/shaders/generated/auto_text_pass.hpp b/engine/shaders/generated/auto_text_pass.hpp index 3ebab9c9d..b3b1f3a57 100644 --- a/engine/shaders/generated/auto_text_pass.hpp +++ b/engine/shaders/generated/auto_text_pass.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_text_reflection.hpp b/engine/shaders/generated/auto_text_reflection.hpp index 5cdd5999d..27e3c17eb 100644 --- a/engine/shaders/generated/auto_text_reflection.hpp +++ b/engine/shaders/generated/auto_text_reflection.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once diff --git a/engine/shaders/generated/auto_text_vk450_frag.hpp b/engine/shaders/generated/auto_text_vk450_frag.hpp index 6c7458d13..007d19ee2 100644 --- a/engine/shaders/generated/auto_text_vk450_frag.hpp +++ b/engine/shaders/generated/auto_text_vk450_frag.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,8 +39,12 @@ namespace wmoge { static const char source_text_vk450_frag[] = R"( + + layout (set = 0, binding = 1) uniform sampler2D FontTexture; + + layout (set = 0, binding = 0, std140) uniform Params { mat4 mat_clip_proj_screen; float inverse_gamma; @@ -67,6 +71,29 @@ float __pad_3; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { return pow(color, vec3(gamma)); } @@ -91,36 +118,13 @@ vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) color *= max(rq, br - threshold) / max(br, EPSILON); return color; } -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} layout (location = 0) out vec4 out_color; LAYOUT_LOCATION(0) in vec4 fsCol04f; LAYOUT_LOCATION(1) in vec2 fsUv02f; void main() { vec4 result_color = vec4(fsCol04f.rgb, fsCol04f.a * texture(FontTexture, fsUv02f).r); #ifdef OUT_SRGB - result_color.rgb = ColorLinearToSrgb(result_color.rgb, inverse_gamma); + result_color.rgb = ColorLinearToSrgb(result_color.rgb, inverse_gamma); #endif out_color = result_color; } diff --git a/engine/shaders/generated/auto_text_vk450_vert.hpp b/engine/shaders/generated/auto_text_vk450_vert.hpp index 575ca3cb0..7ec898677 100644 --- a/engine/shaders/generated/auto_text_vk450_vert.hpp +++ b/engine/shaders/generated/auto_text_vk450_vert.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -39,8 +39,12 @@ namespace wmoge { static const char source_text_vk450_vert[] = R"( + + layout (set = 0, binding = 1) uniform sampler2D FontTexture; + + layout (set = 0, binding = 0, std140) uniform Params { mat4 mat_clip_proj_screen; float inverse_gamma; @@ -67,30 +71,6 @@ float __pad_3; #else #define LAYOUT_SAMPLER(set_idx, binding_idx) #endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} // Flip optionally UV (for GL or VK to work uniformly) vec2 UnpackUv(in vec2 uv) { #ifdef TARGET_VULKAN diff --git a/engine/shaders/generated/auto_tonemap_gl410_comp.hpp b/engine/shaders/generated/auto_tonemap_gl410_comp.hpp new file mode 100644 index 000000000..d26c545e3 --- /dev/null +++ b/engine/shaders/generated/auto_tonemap_gl410_comp.hpp @@ -0,0 +1,201 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify + +#pragma once + +#include "core/string_id.hpp" +#include "core/string_utf.hpp" +#include "core/string_utils.hpp" +#include "gfx/gfx_defs.hpp" +#include "math/mat.hpp" +#include "math/vec.hpp" + +namespace wmoge { + + static const char source_tonemap_gl410_comp[] = R"( + +#define TONEMAP_MODE_EXP (0) +#define TONEMAP_MODE_REINH (1) +#define TONEMAP_MODE_REINH_EXT (2) +#define TONEMAP_MODE_ACES (3) +#define TONEMAP_MODE_UN2 (4) + +uniform sampler2D Image; + +uniform sampler2D Bloom; + +uniform sampler2D BloomDirtMask; + + +layout (rgba8) uniform writeonly image2D Result; + + +layout (std140) uniform Params { +uvec2 TargetSize; +float InverseGamma; +float Mode; +float Exposure; +float BloomIntensity; +float BloomDirtMaskIntensity; +float WhitePoint; +}; + + +#define TARGET_VULKAN +#define EPSILON 0.00001f +#if defined(TARGET_VULKAN) +#define LAYOUT_LOCATION(idx) layout(location = idx) +#else +#define LAYOUT_LOCATION(idx) +#endif +#if defined(TARGET_VULKAN) +#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(set = set_idx, binding = binding_idx, fields_layout) +#else +#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(fields_layout) +#endif +#if defined(TARGET_VULKAN) +#define LAYOUT_SAMPLER(set_idx, binding_idx) layout(set = set_idx, binding = binding_idx) +#else +#define LAYOUT_SAMPLER(set_idx, binding_idx) +#endif +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); +} +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; +} +vec3 TonemapReinhard(in vec3 color) { + return color / (color + vec3(1,1,1)); +} +vec3 TonemapReinhardExtended(in vec3 color, in float maxWhite) { + return (color * (vec3(1,1,1) + color / sqrt(maxWhite)) ) / (vec3(1,1,1) + color); +} +vec3 TonemapExp(in vec3 color, in float exposure) { + return vec3(1,1,1) - exp(-color * exposure); +} +vec3 TonemapACES(vec3 color) { + const float A = 2.51; + const float B = 0.03; + const float C = 2.43; + const float D = 0.59; + const float E = 0.14; + + return (color * (A * color + B)) / (color * (C * color + D) + E); +} +vec3 TonemapUncharted2(in vec3 color) { + const float A = 0.15; + const float B = 0.50; + const float C = 0.10; + const float D = 0.20; + const float E = 0.02; + const float F = 0.30; + const float W = 11.2; + return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F) ) - E / F; +} +#define GROUP_SIZE_DEFAULT 16 +layout (local_size_x = GROUP_SIZE_DEFAULT, local_size_y = GROUP_SIZE_DEFAULT, local_size_z = 1) in; +void main() { + const uvec2 gid = gl_GlobalInvocationID.xy; + if (gid.x >= TargetSize.x || gid.y >= TargetSize.y) { + return; + } + const vec2 uv = vec2(gid) / vec2(TargetSize); + + const vec3 hdrSrcColor = textureLod(Image, uv, 0).rgb; + const vec3 hdrBloom = textureLod(Bloom, uv, 0).rgb * BloomIntensity; + const vec3 hdrBloomDirt = textureLod(BloomDirtMask, uv, 0).rgb * BloomDirtMaskIntensity; + const vec3 hdrColor = hdrSrcColor + hdrBloom + hdrBloom * hdrBloomDirt; + vec3 ldrColor = hdrColor; + const int tonemapMode = int(Mode); + switch (tonemapMode) { + case TONEMAP_MODE_EXP: + ldrColor = TonemapExp(hdrColor, Exposure); + break; + case TONEMAP_MODE_REINH: + ldrColor = TonemapReinhard(hdrColor); + break; + case TONEMAP_MODE_REINH_EXT: + ldrColor = TonemapReinhardExtended(hdrColor, WhitePoint); + break; + case TONEMAP_MODE_ACES: + ldrColor = TonemapACES(hdrColor); + break; + case TONEMAP_MODE_UN2: + ldrColor = TonemapUncharted2(hdrColor); + break; + default: + break; + } + const vec3 gammaColor = ColorLinearToSrgb(ldrColor, InverseGamma); + imageStore(Result, ivec2(gid), vec4(gammaColor, 1.0f)); +} + +)"; +} diff --git a/engine/shaders/generated/auto_tonemap_gl410_vert.hpp b/engine/shaders/generated/auto_tonemap_gl410_vert.hpp deleted file mode 100644 index 65f5da73d..000000000 --- a/engine/shaders/generated/auto_tonemap_gl410_vert.hpp +++ /dev/null @@ -1,372 +0,0 @@ -/**********************************************************************************/ -/* Wmoge game engine */ -/* Available at github https://github.com/EgorOrachyov/wmoge */ -/**********************************************************************************/ -/* MIT License */ -/* */ -/* Copyright (c) 2023 Egor Orachyov */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining a copy */ -/* of this software and associated documentation files (the "Software"), to deal */ -/* in the Software without restriction, including without limitation the rights */ -/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ -/* copies of the Software, and to permit persons to whom the Software is */ -/* furnished to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be included in all */ -/* copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ -/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ -/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ -/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ -/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ -/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/**********************************************************************************/ - -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify - -#pragma once - -#include "core/string_id.hpp" -#include "core/string_utf.hpp" -#include "core/string_utils.hpp" -#include "gfx/gfx_defs.hpp" -#include "math/mat.hpp" -#include "math/vec.hpp" - -namespace wmoge { - - static const char source_tonemap_gl410_vert[] = R"( -#define TONEMAP_MODE_EXP (0) - -#define TONEMAP_MODE_REINH (1) - -#define TONEMAP_MODE_REINH_EXT (2) - -#define TONEMAP_MODE_ACES (3) - -#define TONEMAP_MODE_UN2 (4) - -uniform sampler2D Image; - -uniform sampler2D Bloom; - -uniform sampler2D BloomDirtMask; - -layout (std140) uniform Params { -mat4 Clip; -float InverseGamma; -float Mode; -float Exposure; -float BloomIntensity; -float BloomDirtMaskIntensity; -float WhitePoint; -float _pd_pad0; -float _pd_pad1; -}; - - -#define TARGET_VULKAN -#define EPSILON 0.00001f -#if defined(TARGET_VULKAN) -#define LAYOUT_LOCATION(idx) layout(location = idx) -#else -#define LAYOUT_LOCATION(idx) -#endif -#if defined(TARGET_VULKAN) -#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(set = set_idx, binding = binding_idx, fields_layout) -#else -#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(fields_layout) -#endif -#if defined(TARGET_VULKAN) -#define LAYOUT_SAMPLER(set_idx, binding_idx) layout(set = set_idx, binding = binding_idx) -#else -#define LAYOUT_SAMPLER(set_idx, binding_idx) -#endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} -struct VertexAttributes { - vec3 pos3; - vec2 pos2; - vec3 norm; - vec3 tang; - ivec4 boneIds; - vec4 boneWeigths; - vec4 col[4]; - vec2 uv[4]; - int primitiveId; -}; -VertexAttributes GetVertexAttributesDefault() { - VertexAttributes attributes; - attributes.pos3 = vec3(0,0,0); - attributes.pos2 = vec2(0,0); - attributes.norm = vec3(0,0,0); - attributes.tang = vec3(0,0,0); - attributes.boneIds = ivec4(0,0,0,0); - attributes.boneWeigths = vec4(0,0,0,0); - attributes.col[0] = vec4(0,0,0,0); - attributes.col[1] = vec4(0,0,0,0); - attributes.col[2] = vec4(0,0,0,0); - attributes.col[3] = vec4(0,0,0,0); - attributes.uv[0] = vec2(0,0); - attributes.uv[1] = vec2(0,0); - attributes.uv[2] = vec2(0,0); - attributes.uv[3] = vec2(0,0); - attributes.primitiveId = -1; - - return attributes; -} -VertexAttributes ReadVertexAttributes() { - VertexAttributes attributes = GetVertexAttributesDefault(); - #ifdef ATTRIB_Pos3f - attributes.pos3 = inPos3f; - #endif - #ifdef ATTRIB_Pos2f - attributes.pos2 = inPos2f; - #endif - #ifdef ATTRIB_Norm3f - attributes.norm = inNorm3f; - #endif - #ifdef ATTRIB_Tang3f - attributes.tang = inTang3f; - #endif - #ifdef ATTRIB_BoneIds4i - attributes.boneIds = inBoneIds4i; - #endif - #ifdef ATTRIB_BoneWeights4f - attributes.boneWeigths = inBoneWeights4f; - #endif - #ifdef ATTRIB_Col04f - attributes.col[0] = inCol04f; - #endif - #ifdef ATTRIB_Col14f - attributes.col[1] = inCol14f; - #endif - #ifdef ATTRIB_Col24f - attributes.col[2] = inCol24f; - #endif - #ifdef ATTRIB_Col34f - attributes.col[3] = inCol34f; - #endif - #ifdef ATTRIB_Uv02f - attributes.uv[0] = inUv02f; - #endif - #ifdef ATTRIB_Uv12f - attributes.uv[1] = inUv12f; - #endif - #ifdef ATTRIB_Uv22f - attributes.uv[2] = inUv22f; - #endif - #ifdef ATTRIB_Uv32f - attributes.uv[3] = inUv32f; - #endif - #ifdef ATTRIB_PrimitiveIdi - attributes.primitiveId = inPrimitiveIdi; - #endif - return attributes; -} -#ifdef VERTEX_SHADER - #define INOUT out -#endif -#ifdef FRAGMENT_SHADER - #define INOUT in -#endif -#ifndef INOUT - #error "Must be defined" -#endif -#if !defined(INOUT_DISABLE_POS) && (defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f)) - LAYOUT_LOCATION( 0) INOUT vec3 inout_worldPos; -#endif -#if !defined(INOUT_DISABLE_NORM) && defined(ATTRIB_Norm3f) - LAYOUT_LOCATION( 1) INOUT vec3 inout_worldNorm; -#endif -#ifdef ATTRIB_Tang3f - LAYOUT_LOCATION( 2) INOUT vec3 inout_worldTang; -#endif -#ifdef ATTRIB_Col04f - LAYOUT_LOCATION( 3) INOUT vec4 inout_col0; -#endif -#ifdef ATTRIB_Col14f - LAYOUT_LOCATION( 4) INOUT vec4 inout_col1; -#endif -#ifdef ATTRIB_Col24f - LAYOUT_LOCATION( 5) INOUT vec4 inout_col2; -#endif -#ifdef ATTRIB_Col34f - LAYOUT_LOCATION( 6) INOUT vec4 inout_col3; -#endif -#ifdef ATTRIB_Uv02f - LAYOUT_LOCATION( 7) INOUT vec2 inout_uv0; -#endif -#ifdef ATTRIB_Uv12f - LAYOUT_LOCATION( 8) INOUT vec2 inout_uv1; -#endif -#ifdef ATTRIB_Uv22f - LAYOUT_LOCATION( 9) INOUT vec2 inout_uv2; -#endif -#ifdef ATTRIB_Uv32f - LAYOUT_LOCATION(10) INOUT vec2 inout_uv3; -#endif -#ifdef ATTRIB_PrimitiveIdi - LAYOUT_LOCATION(11) flat INOUT int inout_primitiveId; -#endif -struct InoutAttributes { - vec3 worldPos; - vec3 worldNorm; - vec3 worldTang; - vec4 col[4]; - vec2 uv[4]; - int primitiveId; -}; -#ifdef VERTEX_SHADER -void StoreInoutAttributes(in InoutAttributes attributes) { - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - inout_worldPos = attributes.worldPos; - #endif - #ifdef ATTRIB_Norm3f - inout_worldNorm = attributes.worldNorm; - #endif - #ifdef ATTRIB_Tang3f - inout_worldTang = attributes.worldTang; - #endif - #ifdef ATTRIB_Col04f - inout_col0 = attributes.col[0]; - #endif - #ifdef ATTRIB_Col14f - inout_col1 = attributes.col[1]; - #endif - #ifdef ATTRIB_Col24f - inout_col2 = attributes.col[2]; - #endif - #ifdef ATTRIB_Col34f - inout_col3 = attributes.col[3]; - #endif - #ifdef ATTRIB_Uv02f - inout_uv0 = attributes.uv[0]; - #endif - #ifdef ATTRIB_Uv12f - inout_uv1 = attributes.uv[1]; - #endif - #ifdef ATTRIB_Uv22f - inout_uv2 = attributes.uv[2]; - #endif - #ifdef ATTRIB_Uv32f - inout_uv3 = attributes.uv[3]; - #endif - #ifdef ATTRIB_PrimitiveIdi - inout_primitiveId = attributes.primitiveId; - #endif -} -#endif//VERTEX_SHADER -#ifdef FRAGMENT_SHADER -InoutAttributes ReadInoutAttributes() { - InoutAttributes attributes; - attributes.worldPos = vec3(0,0,0); - attributes.worldNorm = vec3(0,0,0); - attributes.worldTang = vec3(0,0,0); - attributes.col[0] = vec4(0,0,0,0); - attributes.col[1] = vec4(0,0,0,0); - attributes.col[2] = vec4(0,0,0,0); - attributes.col[3] = vec4(0,0,0,0); - attributes.uv[0] = vec2(0,0); - attributes.uv[1] = vec2(0,0); - attributes.uv[2] = vec2(0,0); - attributes.uv[3] = vec2(0,0); - attributes.primitiveId = -1; - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - attributes.worldPos = inout_worldPos; - #endif - #ifdef ATTRIB_Norm3f - attributes.worldNorm = inout_worldNorm; - #endif - #ifdef ATTRIB_Tang3f - attributes.worldTang = inout_worldTang; - #endif - #ifdef ATTRIB_Col04f - attributes.col[0] = inout_col0; - #endif - #ifdef ATTRIB_Col14f - attributes.col[1] = inout_col1; - #endif - #ifdef ATTRIB_Col24f - attributes.col[2] = inout_col2; - #endif - #ifdef ATTRIB_Col34f - attributes.col[3] = inout_col3; - #endif - #ifdef ATTRIB_Uv02f - attributes.uv[0] = inout_uv0; - #endif - #ifdef ATTRIB_Uv12f - attributes.uv[1] = inout_uv1; - #endif - #ifdef ATTRIB_Uv22f - attributes.uv[2] = inout_uv2; - #endif - #ifdef ATTRIB_Uv32f - attributes.uv[3] = inout_uv3; - #endif - #ifdef ATTRIB_PrimitiveIdi - attributes.primitiveId = inout_primitiveId; - #endif - return attributes; -} -#endif//FRAGMENT_SHADER -void main() { - const VertexAttributes vertex = ReadVertexAttributes(); - - InoutAttributes result; - result.uv[0] = UnpackUv(vertex.uv[0]); - StoreInoutAttributes(result); - gl_Position = Clip * vec4(vertex.pos2, 0.0f, 1.0f); -} - -)"; -} diff --git a/engine/shaders/generated/auto_tonemap_pass.hpp b/engine/shaders/generated/auto_tonemap_pass.hpp index d05575de2..b51cabdfe 100644 --- a/engine/shaders/generated/auto_tonemap_pass.hpp +++ b/engine/shaders/generated/auto_tonemap_pass.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -37,10 +37,8 @@ #include "math/vec.hpp" #include "render/shader_pass.hpp" -#include "auto_tonemap_gl410_frag.hpp" -#include "auto_tonemap_gl410_vert.hpp" -#include "auto_tonemap_vk450_frag.hpp" -#include "auto_tonemap_vk450_vert.hpp" +#include "auto_tonemap_gl410_comp.hpp" +#include "auto_tonemap_vk450_comp.hpp" namespace wmoge { /** @brief Auto generated pass for 'tonemap' shader */ @@ -73,44 +71,35 @@ namespace wmoge { binding_BloomDirtMask.binding = 3; binding_BloomDirtMask.count = 1; binding_BloomDirtMask.type = GfxBindingType::SampledTexture; + auto& binding_Result = layout.emplace_back(); + binding_Result.name = SID("Result"); + binding_Result.binding = 4; + binding_Result.count = 1; + binding_Result.type = GfxBindingType::StorageImage; } } Status reload_sources(const std::string& folder, FileSystem* file_system) override { // lang is vk450 { - const auto file_path = folder + '/' + "auto_tonemap_vk450_vert.glsl"; - if (file_system->read_file(file_path, m_vertex[0])) { + const auto file_path = folder + '/' + "auto_tonemap_vk450_comp.glsl"; + if (file_system->read_file(file_path, m_compute[0])) { WG_LOG_INFO("reload shader from file " << file_path); } } // lang is gl410 { - const auto file_path = folder + '/' + "auto_tonemap_gl410_vert.glsl"; - if (file_system->read_file(file_path, m_vertex[1])) { - WG_LOG_INFO("reload shader from file " << file_path); - } - } - // lang is vk450 - { - const auto file_path = folder + '/' + "auto_tonemap_vk450_frag.glsl"; - if (file_system->read_file(file_path, m_fragment[0])) { - WG_LOG_INFO("reload shader from file " << file_path); - } - } - // lang is gl410 - { - const auto file_path = folder + '/' + "auto_tonemap_gl410_frag.glsl"; - if (file_system->read_file(file_path, m_fragment[1])) { + const auto file_path = folder + '/' + "auto_tonemap_gl410_comp.glsl"; + if (file_system->read_file(file_path, m_compute[1])) { WG_LOG_INFO("reload shader from file " << file_path); } } return StatusCode::Ok; } const std::string& get_vertex(GfxShaderLang lang) override { return m_vertex[int(lang)]; } - std::string m_vertex[2] = {source_tonemap_vk450_vert, source_tonemap_gl410_vert}; + std::string m_vertex[2]; const std::string& get_fragment(GfxShaderLang lang) override { return m_fragment[int(lang)]; } - std::string m_fragment[2] = {source_tonemap_vk450_frag, source_tonemap_gl410_frag}; + std::string m_fragment[2]; const std::string& get_compute(GfxShaderLang lang) override { return m_compute[int(lang)]; } - std::string m_compute[2]; + std::string m_compute[2] = {source_tonemap_vk450_comp, source_tonemap_gl410_comp}; }; }// namespace wmoge diff --git a/engine/shaders/generated/auto_tonemap_reflection.hpp b/engine/shaders/generated/auto_tonemap_reflection.hpp index f4c609353..a0fa56abb 100644 --- a/engine/shaders/generated/auto_tonemap_reflection.hpp +++ b/engine/shaders/generated/auto_tonemap_reflection.hpp @@ -25,7 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify #pragma once @@ -42,20 +42,16 @@ namespace wmoge { struct ShaderTonemap { static constexpr const char NAME[] = "tonemap"; static constexpr const char CLS[] = "Tonemap"; - static constexpr int NUM_FILES = 2; + static constexpr int NUM_FILES = 1; static constexpr int NUM_CONSTS = 5; static constexpr int NUM_SAMPLERS = 3; static constexpr int NUM_BUFFERS = 1; - static constexpr const auto TONEMAP_MODE_EXP = 0; - - static constexpr const auto TONEMAP_MODE_REINH = 1; - + static constexpr const auto TONEMAP_MODE_EXP = 0; + static constexpr const auto TONEMAP_MODE_REINH = 1; static constexpr const auto TONEMAP_MODE_REINH_EXT = 2; - - static constexpr const auto TONEMAP_MODE_ACES = 3; - - static constexpr const auto TONEMAP_MODE_UN2 = 4; + static constexpr const auto TONEMAP_MODE_ACES = 3; + static constexpr const auto TONEMAP_MODE_UN2 = 4; static constexpr const int IMAGE_SET = 0; static constexpr const int IMAGE_SLOT = 1; @@ -72,16 +68,21 @@ namespace wmoge { static constexpr const auto BLOOMDIRTMASK_LOC = GfxLocation{0, 3}; static constexpr const char BLOOMDIRTMASK_NAME[] = "BloomDirtMask"; + static constexpr const int RESULT_SET = 0; + static constexpr const int RESULT_SLOT = 4; + static constexpr const auto RESULT_LOC = GfxLocation{0, 4}; + static constexpr const char RESULT_NAME[] = "Result"; + static constexpr const char RESULT_FORMAT[] = "rgba8"; + static constexpr const char RESULT_QUALIFIER[] = "writeonly"; + struct Params { - Mat4x4f Clip; - float InverseGamma; - float Mode; - float Exposure; - float BloomIntensity; - float BloomDirtMaskIntensity; - float WhitePoint; - float _pd_pad0; - float _pd_pad1; + Vec2u TargetSize; + float InverseGamma; + float Mode; + float Exposure; + float BloomIntensity; + float BloomDirtMaskIntensity; + float WhitePoint; }; static constexpr const int PARAMS_SET = 0; diff --git a/engine/shaders/generated/auto_tonemap_vk450_comp.hpp b/engine/shaders/generated/auto_tonemap_vk450_comp.hpp new file mode 100644 index 000000000..bb10d191b --- /dev/null +++ b/engine/shaders/generated/auto_tonemap_vk450_comp.hpp @@ -0,0 +1,201 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +// Autogenerated file by 'generator.py' on 2023-10-31 12:47:38.064896, do not modify + +#pragma once + +#include "core/string_id.hpp" +#include "core/string_utf.hpp" +#include "core/string_utils.hpp" +#include "gfx/gfx_defs.hpp" +#include "math/mat.hpp" +#include "math/vec.hpp" + +namespace wmoge { + + static const char source_tonemap_vk450_comp[] = R"( + +#define TONEMAP_MODE_EXP (0) +#define TONEMAP_MODE_REINH (1) +#define TONEMAP_MODE_REINH_EXT (2) +#define TONEMAP_MODE_ACES (3) +#define TONEMAP_MODE_UN2 (4) + +layout (set = 0, binding = 1) uniform sampler2D Image; + +layout (set = 0, binding = 2) uniform sampler2D Bloom; + +layout (set = 0, binding = 3) uniform sampler2D BloomDirtMask; + + +layout (set = 0, binding = 4, rgba8) uniform writeonly image2D Result; + + +layout (set = 0, binding = 0, std140) uniform Params { +uvec2 TargetSize; +float InverseGamma; +float Mode; +float Exposure; +float BloomIntensity; +float BloomDirtMaskIntensity; +float WhitePoint; +}; + + +#define TARGET_VULKAN +#define EPSILON 0.00001f +#if defined(TARGET_VULKAN) +#define LAYOUT_LOCATION(idx) layout(location = idx) +#else +#define LAYOUT_LOCATION(idx) +#endif +#if defined(TARGET_VULKAN) +#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(set = set_idx, binding = binding_idx, fields_layout) +#else +#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(fields_layout) +#endif +#if defined(TARGET_VULKAN) +#define LAYOUT_SAMPLER(set_idx, binding_idx) layout(set = set_idx, binding = binding_idx) +#else +#define LAYOUT_SAMPLER(set_idx, binding_idx) +#endif +// Flip optionally UV (for GL or VK to work uniformly) +vec2 UnpackUv(in vec2 uv) { + #ifdef TARGET_VULKAN + return vec2(uv.x, 1.0f - uv.y); + #else + return uv; + #endif +} +mat4 GetIdentity4x4() { + mat4 matrix = mat4( + vec4(1,0,0,0), + vec4(0,1,0,0), + vec4(0,0,1,0), + vec4(0,0,0,1)); + + return matrix; +} +vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { + return (localToWorld * vec4(posLocal, 1.0f)).xyz; +} +vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { + return (normalMatrix * vec4(normLocal, 0.0f)).xyz; +} +vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { + return pow(color, vec3(gamma)); +} +vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { + return pow(color, vec3(inverse_gamma)); +} +// Convert rgb to luminance with rgb in linear space +// with sRGB primaries and D65 white point +float Luminance(in vec3 color) { + return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); +} +// Quadratic color thresholding +// curve = (threshold - knee, knee * 2, 0.25 / knee) +vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) +{ + // Pixel brightness + float br = max(color.r, max(color.g, color.b)); + // Under-threshold part: quadratic curve + float rq = clamp(br - curve.x, 0.0, curve.y); + rq = curve.z * rq * rq; + // Combine and apply the brightness response curve. + color *= max(rq, br - threshold) / max(br, EPSILON); + return color; +} +vec3 TonemapReinhard(in vec3 color) { + return color / (color + vec3(1,1,1)); +} +vec3 TonemapReinhardExtended(in vec3 color, in float maxWhite) { + return (color * (vec3(1,1,1) + color / sqrt(maxWhite)) ) / (vec3(1,1,1) + color); +} +vec3 TonemapExp(in vec3 color, in float exposure) { + return vec3(1,1,1) - exp(-color * exposure); +} +vec3 TonemapACES(vec3 color) { + const float A = 2.51; + const float B = 0.03; + const float C = 2.43; + const float D = 0.59; + const float E = 0.14; + + return (color * (A * color + B)) / (color * (C * color + D) + E); +} +vec3 TonemapUncharted2(in vec3 color) { + const float A = 0.15; + const float B = 0.50; + const float C = 0.10; + const float D = 0.20; + const float E = 0.02; + const float F = 0.30; + const float W = 11.2; + return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F) ) - E / F; +} +#define GROUP_SIZE_DEFAULT 16 +layout (local_size_x = GROUP_SIZE_DEFAULT, local_size_y = GROUP_SIZE_DEFAULT, local_size_z = 1) in; +void main() { + const uvec2 gid = gl_GlobalInvocationID.xy; + if (gid.x >= TargetSize.x || gid.y >= TargetSize.y) { + return; + } + const vec2 uv = vec2(gid) / vec2(TargetSize); + + const vec3 hdrSrcColor = textureLod(Image, uv, 0).rgb; + const vec3 hdrBloom = textureLod(Bloom, uv, 0).rgb * BloomIntensity; + const vec3 hdrBloomDirt = textureLod(BloomDirtMask, uv, 0).rgb * BloomDirtMaskIntensity; + const vec3 hdrColor = hdrSrcColor + hdrBloom + hdrBloom * hdrBloomDirt; + vec3 ldrColor = hdrColor; + const int tonemapMode = int(Mode); + switch (tonemapMode) { + case TONEMAP_MODE_EXP: + ldrColor = TonemapExp(hdrColor, Exposure); + break; + case TONEMAP_MODE_REINH: + ldrColor = TonemapReinhard(hdrColor); + break; + case TONEMAP_MODE_REINH_EXT: + ldrColor = TonemapReinhardExtended(hdrColor, WhitePoint); + break; + case TONEMAP_MODE_ACES: + ldrColor = TonemapACES(hdrColor); + break; + case TONEMAP_MODE_UN2: + ldrColor = TonemapUncharted2(hdrColor); + break; + default: + break; + } + const vec3 gammaColor = ColorLinearToSrgb(ldrColor, InverseGamma); + imageStore(Result, ivec2(gid), vec4(gammaColor, 1.0f)); +} + +)"; +} diff --git a/engine/shaders/generated/auto_tonemap_vk450_vert.hpp b/engine/shaders/generated/auto_tonemap_vk450_vert.hpp deleted file mode 100644 index ff054201d..000000000 --- a/engine/shaders/generated/auto_tonemap_vk450_vert.hpp +++ /dev/null @@ -1,372 +0,0 @@ -/**********************************************************************************/ -/* Wmoge game engine */ -/* Available at github https://github.com/EgorOrachyov/wmoge */ -/**********************************************************************************/ -/* MIT License */ -/* */ -/* Copyright (c) 2023 Egor Orachyov */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining a copy */ -/* of this software and associated documentation files (the "Software"), to deal */ -/* in the Software without restriction, including without limitation the rights */ -/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ -/* copies of the Software, and to permit persons to whom the Software is */ -/* furnished to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be included in all */ -/* copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ -/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ -/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ -/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ -/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ -/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/**********************************************************************************/ - -// Autogenerated file by 'generator.py' on 2023-10-29 11:44:54.133601, do not modify - -#pragma once - -#include "core/string_id.hpp" -#include "core/string_utf.hpp" -#include "core/string_utils.hpp" -#include "gfx/gfx_defs.hpp" -#include "math/mat.hpp" -#include "math/vec.hpp" - -namespace wmoge { - - static const char source_tonemap_vk450_vert[] = R"( -#define TONEMAP_MODE_EXP (0) - -#define TONEMAP_MODE_REINH (1) - -#define TONEMAP_MODE_REINH_EXT (2) - -#define TONEMAP_MODE_ACES (3) - -#define TONEMAP_MODE_UN2 (4) - -layout (set = 0, binding = 1) uniform sampler2D Image; - -layout (set = 0, binding = 2) uniform sampler2D Bloom; - -layout (set = 0, binding = 3) uniform sampler2D BloomDirtMask; - -layout (set = 0, binding = 0, std140) uniform Params { -mat4 Clip; -float InverseGamma; -float Mode; -float Exposure; -float BloomIntensity; -float BloomDirtMaskIntensity; -float WhitePoint; -float _pd_pad0; -float _pd_pad1; -}; - - -#define TARGET_VULKAN -#define EPSILON 0.00001f -#if defined(TARGET_VULKAN) -#define LAYOUT_LOCATION(idx) layout(location = idx) -#else -#define LAYOUT_LOCATION(idx) -#endif -#if defined(TARGET_VULKAN) -#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(set = set_idx, binding = binding_idx, fields_layout) -#else -#define LAYOUT_BUFFER(set_idx, binding_idx, fields_layout) layout(fields_layout) -#endif -#if defined(TARGET_VULKAN) -#define LAYOUT_SAMPLER(set_idx, binding_idx) layout(set = set_idx, binding = binding_idx) -#else -#define LAYOUT_SAMPLER(set_idx, binding_idx) -#endif -vec3 ColorSrgbToLinear(in vec3 color, in float gamma) { - return pow(color, vec3(gamma)); -} -vec3 ColorLinearToSrgb(in vec3 color, in float inverse_gamma) { - return pow(color, vec3(inverse_gamma)); -} -// Convert rgb to luminance with rgb in linear space -// with sRGB primaries and D65 white point -float Luminance(in vec3 color) { - return dot(color, vec3(0.2126729, 0.7151522, 0.0721750)); -} -// Quadratic color thresholding -// curve = (threshold - knee, knee * 2, 0.25 / knee) -vec3 QuadraticThreshold(vec3 color, float threshold, vec3 curve) -{ - // Pixel brightness - float br = max(color.r, max(color.g, color.b)); - // Under-threshold part: quadratic curve - float rq = clamp(br - curve.x, 0.0, curve.y); - rq = curve.z * rq * rq; - // Combine and apply the brightness response curve. - color *= max(rq, br - threshold) / max(br, EPSILON); - return color; -} -// Flip optionally UV (for GL or VK to work uniformly) -vec2 UnpackUv(in vec2 uv) { - #ifdef TARGET_VULKAN - return vec2(uv.x, 1.0f - uv.y); - #else - return uv; - #endif -} -mat4 GetIdentity4x4() { - mat4 matrix = mat4( - vec4(1,0,0,0), - vec4(0,1,0,0), - vec4(0,0,1,0), - vec4(0,0,0,1)); - - return matrix; -} -vec3 TransformLocalToWorld(in vec3 posLocal, in mat4 localToWorld) { - return (localToWorld * vec4(posLocal, 1.0f)).xyz; -} -vec3 TransformLocalToWorldNormal(in vec3 normLocal, in mat4 normalMatrix) { - return (normalMatrix * vec4(normLocal, 0.0f)).xyz; -} -struct VertexAttributes { - vec3 pos3; - vec2 pos2; - vec3 norm; - vec3 tang; - ivec4 boneIds; - vec4 boneWeigths; - vec4 col[4]; - vec2 uv[4]; - int primitiveId; -}; -VertexAttributes GetVertexAttributesDefault() { - VertexAttributes attributes; - attributes.pos3 = vec3(0,0,0); - attributes.pos2 = vec2(0,0); - attributes.norm = vec3(0,0,0); - attributes.tang = vec3(0,0,0); - attributes.boneIds = ivec4(0,0,0,0); - attributes.boneWeigths = vec4(0,0,0,0); - attributes.col[0] = vec4(0,0,0,0); - attributes.col[1] = vec4(0,0,0,0); - attributes.col[2] = vec4(0,0,0,0); - attributes.col[3] = vec4(0,0,0,0); - attributes.uv[0] = vec2(0,0); - attributes.uv[1] = vec2(0,0); - attributes.uv[2] = vec2(0,0); - attributes.uv[3] = vec2(0,0); - attributes.primitiveId = -1; - - return attributes; -} -VertexAttributes ReadVertexAttributes() { - VertexAttributes attributes = GetVertexAttributesDefault(); - #ifdef ATTRIB_Pos3f - attributes.pos3 = inPos3f; - #endif - #ifdef ATTRIB_Pos2f - attributes.pos2 = inPos2f; - #endif - #ifdef ATTRIB_Norm3f - attributes.norm = inNorm3f; - #endif - #ifdef ATTRIB_Tang3f - attributes.tang = inTang3f; - #endif - #ifdef ATTRIB_BoneIds4i - attributes.boneIds = inBoneIds4i; - #endif - #ifdef ATTRIB_BoneWeights4f - attributes.boneWeigths = inBoneWeights4f; - #endif - #ifdef ATTRIB_Col04f - attributes.col[0] = inCol04f; - #endif - #ifdef ATTRIB_Col14f - attributes.col[1] = inCol14f; - #endif - #ifdef ATTRIB_Col24f - attributes.col[2] = inCol24f; - #endif - #ifdef ATTRIB_Col34f - attributes.col[3] = inCol34f; - #endif - #ifdef ATTRIB_Uv02f - attributes.uv[0] = inUv02f; - #endif - #ifdef ATTRIB_Uv12f - attributes.uv[1] = inUv12f; - #endif - #ifdef ATTRIB_Uv22f - attributes.uv[2] = inUv22f; - #endif - #ifdef ATTRIB_Uv32f - attributes.uv[3] = inUv32f; - #endif - #ifdef ATTRIB_PrimitiveIdi - attributes.primitiveId = inPrimitiveIdi; - #endif - return attributes; -} -#ifdef VERTEX_SHADER - #define INOUT out -#endif -#ifdef FRAGMENT_SHADER - #define INOUT in -#endif -#ifndef INOUT - #error "Must be defined" -#endif -#if !defined(INOUT_DISABLE_POS) && (defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f)) - LAYOUT_LOCATION( 0) INOUT vec3 inout_worldPos; -#endif -#if !defined(INOUT_DISABLE_NORM) && defined(ATTRIB_Norm3f) - LAYOUT_LOCATION( 1) INOUT vec3 inout_worldNorm; -#endif -#ifdef ATTRIB_Tang3f - LAYOUT_LOCATION( 2) INOUT vec3 inout_worldTang; -#endif -#ifdef ATTRIB_Col04f - LAYOUT_LOCATION( 3) INOUT vec4 inout_col0; -#endif -#ifdef ATTRIB_Col14f - LAYOUT_LOCATION( 4) INOUT vec4 inout_col1; -#endif -#ifdef ATTRIB_Col24f - LAYOUT_LOCATION( 5) INOUT vec4 inout_col2; -#endif -#ifdef ATTRIB_Col34f - LAYOUT_LOCATION( 6) INOUT vec4 inout_col3; -#endif -#ifdef ATTRIB_Uv02f - LAYOUT_LOCATION( 7) INOUT vec2 inout_uv0; -#endif -#ifdef ATTRIB_Uv12f - LAYOUT_LOCATION( 8) INOUT vec2 inout_uv1; -#endif -#ifdef ATTRIB_Uv22f - LAYOUT_LOCATION( 9) INOUT vec2 inout_uv2; -#endif -#ifdef ATTRIB_Uv32f - LAYOUT_LOCATION(10) INOUT vec2 inout_uv3; -#endif -#ifdef ATTRIB_PrimitiveIdi - LAYOUT_LOCATION(11) flat INOUT int inout_primitiveId; -#endif -struct InoutAttributes { - vec3 worldPos; - vec3 worldNorm; - vec3 worldTang; - vec4 col[4]; - vec2 uv[4]; - int primitiveId; -}; -#ifdef VERTEX_SHADER -void StoreInoutAttributes(in InoutAttributes attributes) { - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - inout_worldPos = attributes.worldPos; - #endif - #ifdef ATTRIB_Norm3f - inout_worldNorm = attributes.worldNorm; - #endif - #ifdef ATTRIB_Tang3f - inout_worldTang = attributes.worldTang; - #endif - #ifdef ATTRIB_Col04f - inout_col0 = attributes.col[0]; - #endif - #ifdef ATTRIB_Col14f - inout_col1 = attributes.col[1]; - #endif - #ifdef ATTRIB_Col24f - inout_col2 = attributes.col[2]; - #endif - #ifdef ATTRIB_Col34f - inout_col3 = attributes.col[3]; - #endif - #ifdef ATTRIB_Uv02f - inout_uv0 = attributes.uv[0]; - #endif - #ifdef ATTRIB_Uv12f - inout_uv1 = attributes.uv[1]; - #endif - #ifdef ATTRIB_Uv22f - inout_uv2 = attributes.uv[2]; - #endif - #ifdef ATTRIB_Uv32f - inout_uv3 = attributes.uv[3]; - #endif - #ifdef ATTRIB_PrimitiveIdi - inout_primitiveId = attributes.primitiveId; - #endif -} -#endif//VERTEX_SHADER -#ifdef FRAGMENT_SHADER -InoutAttributes ReadInoutAttributes() { - InoutAttributes attributes; - attributes.worldPos = vec3(0,0,0); - attributes.worldNorm = vec3(0,0,0); - attributes.worldTang = vec3(0,0,0); - attributes.col[0] = vec4(0,0,0,0); - attributes.col[1] = vec4(0,0,0,0); - attributes.col[2] = vec4(0,0,0,0); - attributes.col[3] = vec4(0,0,0,0); - attributes.uv[0] = vec2(0,0); - attributes.uv[1] = vec2(0,0); - attributes.uv[2] = vec2(0,0); - attributes.uv[3] = vec2(0,0); - attributes.primitiveId = -1; - #if defined(ATTRIB_Pos3f) || defined(ATTRIB_Pos2f) - attributes.worldPos = inout_worldPos; - #endif - #ifdef ATTRIB_Norm3f - attributes.worldNorm = inout_worldNorm; - #endif - #ifdef ATTRIB_Tang3f - attributes.worldTang = inout_worldTang; - #endif - #ifdef ATTRIB_Col04f - attributes.col[0] = inout_col0; - #endif - #ifdef ATTRIB_Col14f - attributes.col[1] = inout_col1; - #endif - #ifdef ATTRIB_Col24f - attributes.col[2] = inout_col2; - #endif - #ifdef ATTRIB_Col34f - attributes.col[3] = inout_col3; - #endif - #ifdef ATTRIB_Uv02f - attributes.uv[0] = inout_uv0; - #endif - #ifdef ATTRIB_Uv12f - attributes.uv[1] = inout_uv1; - #endif - #ifdef ATTRIB_Uv22f - attributes.uv[2] = inout_uv2; - #endif - #ifdef ATTRIB_Uv32f - attributes.uv[3] = inout_uv3; - #endif - #ifdef ATTRIB_PrimitiveIdi - attributes.primitiveId = inout_primitiveId; - #endif - return attributes; -} -#endif//FRAGMENT_SHADER -void main() { - const VertexAttributes vertex = ReadVertexAttributes(); - - InoutAttributes result; - result.uv[0] = UnpackUv(vertex.uv[0]); - StoreInoutAttributes(result); - gl_Position = Clip * vec4(vertex.pos2, 0.0f, 1.0f); -} - -)"; -} diff --git a/engine/shaders/hdr.glsl b/engine/shaders/hdr.glsl index 0c15df777..6658dd6af 100644 --- a/engine/shaders/hdr.glsl +++ b/engine/shaders/hdr.glsl @@ -21,22 +21,22 @@ vec3 TonemapExp(in vec3 color, in float exposure) { vec3 TonemapACES(vec3 color) { const float A = 2.51; - const float B = 0.03; - const float C = 2.43; - const float D = 0.59; - const float E = 0.14; + const float B = 0.03; + const float C = 2.43; + const float D = 0.59; + const float E = 0.14; - return (color * (A * color + B)) / (color * (C * color + D) + E); + return (color * (A * color + B)) / (color * (C * color + D) + E); } vec3 TonemapUncharted2(in vec3 color) { const float A = 0.15; - const float B = 0.50; - const float C = 0.10; - const float D = 0.20; - const float E = 0.02; - const float F = 0.30; - const float W = 11.2; + const float B = 0.50; + const float C = 0.10; + const float D = 0.20; + const float E = 0.02; + const float F = 0.30; + const float W = 11.2; - return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F) ) - E / F; + return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F) ) - E / F; } \ No newline at end of file diff --git a/engine/shaders/material_fs.glsl b/engine/shaders/material_fs.glsl index 493d92d6b..711ab23e9 100644 --- a/engine/shaders/material_fs.glsl +++ b/engine/shaders/material_fs.glsl @@ -9,6 +9,7 @@ #include "inout_attributes.glsl" #include "scene_data.glsl" +#include "color.glsl" struct MaterialAttributes { vec4 baseColor; diff --git a/engine/shaders/material_vs.glsl b/engine/shaders/material_vs.glsl index 4f7667540..4b4a0c5a1 100644 --- a/engine/shaders/material_vs.glsl +++ b/engine/shaders/material_vs.glsl @@ -10,6 +10,7 @@ #include "inout_attributes.glsl" #include "vertex_attributes.glsl" #include "scene_data.glsl" +#include "color.glsl" struct ShaderInoutVs { VertexAttributes attributes; diff --git a/engine/shaders/scripts/bloom.py b/engine/shaders/scripts/bloom.py index 73dd43d4f..a2deacd3e 100644 --- a/engine/shaders/scripts/bloom.py +++ b/engine/shaders/scripts/bloom.py @@ -3,7 +3,6 @@ BINDINGS = BindingAllocator() Params = [ - StructField(TYPE_MAT4, "Clip"), StructField(TYPE_VEC4, "ThresholdKnee"), StructField(TYPE_FLOAT, "UpsampleRadius"), StructField(TYPE_FLOAT, "UpsampleWeight"), @@ -28,5 +27,6 @@ Sampler2d("Source", BINDINGS.next()), Sampler2d("SourcePrev", BINDINGS.next()), ], - files=["bloom.vert", "bloom.frag"], + images=[Image2D("Result", BINDINGS.next(), "rgba16f", "writeonly")], + files=["bloom.comp"], ) diff --git a/engine/shaders/scripts/composition.py b/engine/shaders/scripts/composition.py new file mode 100644 index 000000000..97676cba5 --- /dev/null +++ b/engine/shaders/scripts/composition.py @@ -0,0 +1,30 @@ +from reflection import * + +BINDINGS = BindingAllocator() + +Params = [ + StructField(TYPE_MAT4, "Clip"), + StructField(TYPE_UVEC2, "TargetSize"), + StructField(TYPE_FLOAT, "Gamma"), + StructField(TYPE_FLOAT, "InverseGamma"), +] + +SHADER = Shader( + name="composition", + cls="Composition", + constants=[], + structs=[], + buffers=[ + UniformBuffer( + "Params", + "std140", + BINDINGS.next(), + Params, + ) + ], + samplers=[ + Sampler2d("Color", BINDINGS.next()), + ], + images=[], + files=["composition.vert", "composition.frag"], +) diff --git a/engine/shaders/scripts/generator.py b/engine/shaders/scripts/generator.py index 26cd8e503..1605dcad1 100644 --- a/engine/shaders/scripts/generator.py +++ b/engine/shaders/scripts/generator.py @@ -82,6 +82,9 @@ def __init__(self, shader): def emit_sampler(self, sampler): raise Exception("not implemented") + def emit_image(self, image): + raise Exception("not implemented") + def emit_const(self, const): raise Exception("not implemented") @@ -97,6 +100,8 @@ def emit_buffer(self, buffer): def emit(self, element): if isinstance(element, reflection.Sampler): return self.emit_sampler(element) + if isinstance(element, reflection.Image): + return self.emit_image(element) if isinstance(element, reflection.Constant): return self.emit_const(element) if isinstance(element, reflection.Struct): @@ -112,14 +117,26 @@ def run(self): result += self.emit_struct(struct) result += "\n" + result += "\n" + for const in self.shader.constants: result += self.emit_const(const) result += "\n" + result += "\n" + for sampler in self.shader.samplers: result += self.emit_sampler(sampler) result += "\n" + result += "\n" + + for image in self.shader.images: + result += self.emit_image(image) + result += "\n" + + result += "\n" + for buffer in self.shader.buffers: result += self.emit_buffer(buffer) result += "\n" @@ -134,6 +151,9 @@ def __init__(self, shader): def sampler_layout(self, binding): raise Exception("not implemented") + def image_layout(self, binding, format): + raise Exception("not implemented") + def buffer_layout(self, binding, layout): raise Exception("not implemented") @@ -145,10 +165,18 @@ def emit_sampler(self, sampler): + f"uniform {sampler.decl_type.name} {sampler.name};\n" ) + def emit_image(self, image): + assert isinstance(image, reflection.Image) + + return ( + self.image_layout(image.binding, image.format) + + f"uniform {image.qualifier} {image.decl_type.name} {image.name};\n" + ) + def emit_const(self, const): assert isinstance(const, reflection.Constant) - return f"#define {const.name} ({const.value})\n" + return f"#define {const.name} ({const.value})" def emit_type_decl(self, element): if element == reflection.TYPE_FLOAT: @@ -223,6 +251,11 @@ def __init__(self, shader): def sampler_layout(self, binding): return f"layout (set = {binding.set_num}, binding = {binding.slot_num}) " + def image_layout(self, binding, format): + return ( + f"layout (set = {binding.set_num}, binding = {binding.slot_num}, {format}) " + ) + def buffer_layout(self, binding, layout): return ( f"layout (set = {binding.set_num}, binding = {binding.slot_num}, {layout}) " @@ -236,6 +269,9 @@ def __init__(self, shader): def sampler_layout(self, binding): return f"" + def image_layout(self, binding, format): + return f"layout ({format}) " + def buffer_layout(self, binding, layout): return f"layout ({layout}) " @@ -256,10 +292,24 @@ def emit_sampler(self, sampler): f'static constexpr const char {name}_NAME[] = "{sampler.name}";\n' ) + def emit_image(self, image): + assert isinstance(image, reflection.Image) + + name = image.name.upper() + binding = image.binding + return ( + f"static constexpr const int {name}_SET = {binding.set_num};\n" + f"static constexpr const int {name}_SLOT = {binding.slot_num};\n" + f"static constexpr const auto {name}_LOC = {binding.to_gfx_loc()};\n" + f'static constexpr const char {name}_NAME[] = "{image.name}";\n' + f'static constexpr const char {name}_FORMAT[] = "{image.format}";\n' + f'static constexpr const char {name}_QUALIFIER[] = "{image.qualifier}";\n' + ) + def emit_const(self, const): assert isinstance(const, reflection.Constant) - return f"static constexpr const auto {const.name.upper()} = {const.value};\n" + return f"static constexpr const auto {const.name.upper()} = {const.value};" def emit_type_decl(self, element): if element == reflection.TYPE_FLOAT: @@ -377,6 +427,9 @@ def emit_layouts(self): if isinstance(resource, reflection.Sampler): var = f"binding_{resource.name}" resource_type = "SampledTexture" + if isinstance(resource, reflection.Image): + var = f"binding_{resource.name}" + resource_type = "StorageImage" if isinstance(resource, reflection.UniformBuffer): var = f"binding_{resource.name}" resource_type = "UniformBuffer" diff --git a/engine/shaders/scripts/reflection.py b/engine/shaders/scripts/reflection.py index 6322b3378..9398a1903 100644 --- a/engine/shaders/scripts/reflection.py +++ b/engine/shaders/scripts/reflection.py @@ -33,6 +33,11 @@ def __init__(self, name): Type.__init__(self, name) +class TypeImage(Type): + def __init__(self, name): + Type.__init__(self, name) + + class ArrayQualifier: def __init__(self, size=None): self.size = size @@ -99,6 +104,8 @@ def __init__(self, name, fields: list[StructField]): TYPE_SAMPLER_3D = TypeSampler("sampler3D") TYPE_SAMPLER_CUBE = TypeSampler("samplerCube") +TYPE_IMAGE_2D = TypeSampler("image2D") + class Binding: def __init__(self, set_num, slot_num): @@ -171,16 +178,31 @@ def __init__(self, name, binding): Sampler.__init__(self, name, binding, TYPE_SAMPLER_CUBE) +class Image: + def __init__(self, name, binding, format, qualifier, decl_type): + self.name = name + self.binding = binding + self.format = format + self.qualifier = qualifier + self.decl_type = decl_type + + +class Image2D(Image): + def __init__(self, name, binding, format, qualifier=""): + Image.__init__(self, name, binding, format, qualifier, TYPE_IMAGE_2D) + + class Shader: def __init__( self, name: str, cls: str, - constants: list[Constant], - structs: list[Struct], - buffers: list[Buffer], - samplers: list[Sampler], - files: list[str], + constants: list[Constant] = [], + structs: list[Struct] = [], + buffers: list[Buffer] = [], + samplers: list[Sampler] = [], + images: list[Image] = [], + files: list[str] = [], material_set=None, ): self.name = name @@ -189,6 +211,7 @@ def __init__( self.constants = constants self.buffers = buffers self.samplers = samplers + self.images = images self.files = files self.material_set = material_set @@ -196,6 +219,12 @@ def filter_files(self, filter_string): return [file for file in self.files if filter_string in file] def set_resources(self, set_num): - return [ - buffer for buffer in self.buffers if buffer.binding.set_num == set_num - ] + [sampler for sampler in self.samplers if sampler.binding.set_num == set_num] + return ( + [buffer for buffer in self.buffers if buffer.binding.set_num == set_num] + + [ + sampler + for sampler in self.samplers + if sampler.binding.set_num == set_num + ] + + [image for image in self.images if image.binding.set_num == set_num] + ) diff --git a/engine/shaders/scripts/shaders.py b/engine/shaders/scripts/shaders.py index 6af9aee82..dffd7effb 100644 --- a/engine/shaders/scripts/shaders.py +++ b/engine/shaders/scripts/shaders.py @@ -4,6 +4,7 @@ import canvas import bloom import tonemap +import composition SHADERS_LIST = [ base.SHADER, @@ -12,4 +13,5 @@ canvas.SHADER, bloom.SHADER, tonemap.SHADER, + composition.SHADER, ] diff --git a/engine/shaders/scripts/tonemap.py b/engine/shaders/scripts/tonemap.py index d51c3a414..dafd4043b 100644 --- a/engine/shaders/scripts/tonemap.py +++ b/engine/shaders/scripts/tonemap.py @@ -3,15 +3,13 @@ BINDINGS = BindingAllocator() Params = [ - StructField(TYPE_MAT4, "Clip"), + StructField(TYPE_UVEC2, "TargetSize"), StructField(TYPE_FLOAT, "InverseGamma"), StructField(TYPE_FLOAT, "Mode"), StructField(TYPE_FLOAT, "Exposure"), StructField(TYPE_FLOAT, "BloomIntensity"), StructField(TYPE_FLOAT, "BloomDirtMaskIntensity"), StructField(TYPE_FLOAT, "WhitePoint"), - StructField(TYPE_FLOAT, "_pd_pad0"), - StructField(TYPE_FLOAT, "_pd_pad1"), ] SHADER = Shader( @@ -38,5 +36,6 @@ Sampler2d("Bloom", BINDINGS.next()), Sampler2d("BloomDirtMask", BINDINGS.next()), ], - files=["tonemap.vert", "tonemap.frag"], + images=[Image2D("Result", BINDINGS.next(), "rgba8", "writeonly")], + files=["tonemap.comp"], ) diff --git a/engine/shaders/text.frag b/engine/shaders/text.frag index a2a187aea..297854d7e 100644 --- a/engine/shaders/text.frag +++ b/engine/shaders/text.frag @@ -8,6 +8,7 @@ /**********************************************************************************/ #include "common_funcs.glsl" +#include "color.glsl" layout (location = 0) out vec4 out_color; @@ -18,7 +19,7 @@ void main() { vec4 result_color = vec4(fsCol04f.rgb, fsCol04f.a * texture(FontTexture, fsUv02f).r); #ifdef OUT_SRGB - result_color.rgb = ColorLinearToSrgb(result_color.rgb, inverse_gamma); + result_color.rgb = ColorLinearToSrgb(result_color.rgb, inverse_gamma); #endif out_color = result_color; diff --git a/engine/shaders/tonemap.frag b/engine/shaders/tonemap.comp similarity index 68% rename from engine/shaders/tonemap.frag rename to engine/shaders/tonemap.comp index a87a8347f..bc506e370 100644 --- a/engine/shaders/tonemap.frag +++ b/engine/shaders/tonemap.comp @@ -8,19 +8,27 @@ /**********************************************************************************/ #include "common_funcs.glsl" -#include "inout_attributes.glsl" +#include "color.glsl" #include "hdr.glsl" -layout (location = 0) out vec4 out_color; +#define GROUP_SIZE_DEFAULT 16 + +layout (local_size_x = GROUP_SIZE_DEFAULT, local_size_y = GROUP_SIZE_DEFAULT, local_size_z = 1) in; void main() { - const InoutAttributes attributes = ReadInoutAttributes(); - const vec2 uv = attributes.uv[0]; + const uvec2 gid = gl_GlobalInvocationID.xy; + + if (gid.x >= TargetSize.x || gid.y >= TargetSize.y) { + return; + } + + const vec2 uv = vec2(gid) / vec2(TargetSize); - const vec3 hdrSrcColor = texture(Image, uv).rgb; - const vec3 hdrBloom = texture(Bloom, uv).rgb * BloomIntensity; - const vec3 hdrBloomDirt = texture(BloomDirtMask, uv).rgb * BloomDirtMaskIntensity; - const vec3 hdrColor = hdrSrcColor + hdrBloom + hdrBloom * hdrBloomDirt; + const vec3 hdrSrcColor = textureLod(Image, uv, 0).rgb; + const vec3 hdrBloom = textureLod(Bloom, uv, 0).rgb * BloomIntensity; + const vec3 hdrBloomDirt = textureLod(BloomDirtMask, uv, 0).rgb * BloomDirtMaskIntensity; + + const vec3 hdrColor = hdrSrcColor + hdrBloom + hdrBloom * hdrBloomDirt; vec3 ldrColor = hdrColor; const int tonemapMode = int(Mode); @@ -47,5 +55,5 @@ void main() { const vec3 gammaColor = ColorLinearToSrgb(ldrColor, InverseGamma); - out_color = vec4(gammaColor, 1.0f); + imageStore(Result, ivec2(gid), vec4(gammaColor, 1.0f)); } \ No newline at end of file diff --git a/template/config/engine.cfg b/template/config/engine.cfg index 37addc9e6..8641a2a97 100644 --- a/template/config/engine.cfg +++ b/template/config/engine.cfg @@ -42,14 +42,14 @@ screen_width = 1280 screen_height = 720 [render.shader_manager] -save_cache = true +save_cache = false [ecs] chunk_size = 16 expand_size = 2 [debug] -profiler = true +profiler = false [debug.console] font = "res://fonts/anonymous_pro" diff --git a/template/resources/materials/test_material_1.material b/template/resources/materials/test_material_1.material index fc23c675f..6baf7bace 100644 --- a/template/resources/materials/test_material_1.material +++ b/template/resources/materials/test_material_1.material @@ -1,5 +1,5 @@ parameters: - name: "color" - value: "1 0 0 1" + value: "1 0.1 0.1 1" textures: [] shader: "res://shaders/test_shader" \ No newline at end of file diff --git a/template/resources/materials/test_material_2.material b/template/resources/materials/test_material_2.material index 93b56a86f..89161f2b2 100644 --- a/template/resources/materials/test_material_2.material +++ b/template/resources/materials/test_material_2.material @@ -1,5 +1,5 @@ parameters: - name: "color" - value: "0 1 0 1" + value: "0.1 1 0.1 1" textures: [] shader: "res://shaders/test_shader" \ No newline at end of file diff --git a/template/resources/materials/test_material_3.material b/template/resources/materials/test_material_3.material index 7f475cb3c..83760b3ac 100644 --- a/template/resources/materials/test_material_3.material +++ b/template/resources/materials/test_material_3.material @@ -1,5 +1,5 @@ parameters: - name: "color" - value: "0 0 1 1" + value: "0.1 0.1 1 1" textures: [] shader: "res://shaders/test_shader" \ No newline at end of file diff --git a/template/resources/shaders/test_shader.shader b/template/resources/shaders/test_shader.shader index 2c81d288f..8db23f33d 100644 --- a/template/resources/shaders/test_shader.shader +++ b/template/resources/shaders/test_shader.shader @@ -20,7 +20,7 @@ fragment: > float mixing = 0.5f; if ((fs.attributes.primitiveId % 3) == 0) { - mixing = 4.0f; + mixing = 20.0f; } fs.result.baseColor = mixing * color * max(0.1f, dot(-Direction.xyz, fs.attributes.worldNorm));