From 64d789498149b82668d81d2e7edaeb16b08d4802 Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Tue, 5 Nov 2024 18:36:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=81=E8=AE=B8=E6=B7=BB=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=91=BD=E4=BB=A4=E5=88=B0=E7=9D=80=E8=89=B2?= =?UTF-8?q?=E5=99=A8=E7=BC=96=E8=AF=91=E5=87=BD=E6=95=B0=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96dx=5Fpipeline=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmake/compile_shaders.cmake | 9 ++-- src/renderer/CMakeLists.txt | 6 +-- src/renderer/backend/dx/dx_pipeline.cpp | 18 +++----- src/renderer/backend/dx/dx_pipeline.h | 9 ++-- src/renderer/backend/dx/dx_window.cpp | 43 ++++++++++-------- src/renderer/backend/dx/dx_window.h | 1 - src/renderer/core/pipeline/pipeline.h | 6 +++ .../core/renderer/renderer_context.cpp | 24 ++++++++++ src/renderer/core/renderer/renderer_context.h | 10 ++++- src/renderer/shader/default_shader.slang | 44 +++++++++---------- 10 files changed, 101 insertions(+), 69 deletions(-) diff --git a/cmake/compile_shaders.cmake b/cmake/compile_shaders.cmake index 54bb379..eb86907 100644 --- a/cmake/compile_shaders.cmake +++ b/cmake/compile_shaders.cmake @@ -1,4 +1,3 @@ - function(compile_slang_shaders input_file stage entry_point) # 保证输出目录存在 if (NOT DEFINED SHADER_OUTPUT_DIR) @@ -28,7 +27,7 @@ function(compile_slang_shaders input_file stage entry_point) set(output_file ${output_dir}/${filename}_${entry_point}.glsl) add_custom_command( OUTPUT ${output_file} - COMMAND slangc -target glsl -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + COMMAND slangc -target glsl -entry ${entry_point} -stage ${stage} ${ARGN} -o ${output_file} ${input_file} DEPENDS ${input_file} COMMENT "Compiling ${input_file} to GLSL (${stage}, ${entry_point})" ) @@ -39,7 +38,7 @@ function(compile_slang_shaders input_file stage entry_point) set(output_file ${output_dir}/${filename}_${entry_point}.dxbc) add_custom_command( OUTPUT ${output_file} - COMMAND slangc -target dxbc -profile ${profile} -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + COMMAND slangc -target dxbc -profile ${profile} -entry ${entry_point} -stage ${stage} ${ARGN} -o ${output_file} ${input_file} DEPENDS ${input_file} COMMENT "Compiling ${input_file} to DXBC (${stage}, ${entry_point}) with profile ${profile}" ) @@ -50,7 +49,7 @@ function(compile_slang_shaders input_file stage entry_point) set(output_file ${output_dir}/${filename}_${entry_point}.spirv) add_custom_command( OUTPUT ${output_file} - COMMAND slangc -target spirv -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + COMMAND slangc -target spirv -entry ${entry_point} -stage ${stage} ${ARGN} -o ${output_file} ${input_file} DEPENDS ${input_file} COMMENT "Compiling ${input_file} to SPIR-V (${stage}, ${entry_point})" ) @@ -61,7 +60,7 @@ function(compile_slang_shaders input_file stage entry_point) set(output_file ${output_dir}/${filename}_${entry_point}.metal) add_custom_command( OUTPUT ${output_file} - COMMAND slangc -target msl -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file} + COMMAND slangc -target msl -entry ${entry_point} -stage ${stage} ${ARGN} -o ${output_file} ${input_file} DEPENDS ${input_file} COMMENT "Compiling ${input_file} to Metal Shading Language (${stage}, ${entry_point})" ) diff --git a/src/renderer/CMakeLists.txt b/src/renderer/CMakeLists.txt index 562fd14..f9c4f9a 100644 --- a/src/renderer/CMakeLists.txt +++ b/src/renderer/CMakeLists.txt @@ -58,7 +58,7 @@ if (NOT DEFINED SHADER_OUTPUT_DIR) set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/shaders CACHE PATH "Output directory for compiled shaders") message(STATUS "SHADER_OUTPUT_DIR not defined, using default: ${SHADER_OUTPUT_DIR}") endif () -compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang vertex vertex_main) -compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang pixel pixel_main) -compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang pixel rounded_rect_pixel_main) +compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang" "vertex" "vertex_main") +compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang" "pixel" "pixel_main") +compile_slang_shaders("${CMAKE_CURRENT_SOURCE_DIR}/shader/default_shader.slang" "pixel" "rounded_rect_pixel_main" -D IS_ROUNDED_RECT) add_compile_shaders_target("compile_aorii_shaders" ${PROJECT_NAME}) diff --git a/src/renderer/backend/dx/dx_pipeline.cpp b/src/renderer/backend/dx/dx_pipeline.cpp index 5d3bae9..64d42b1 100644 --- a/src/renderer/backend/dx/dx_pipeline.cpp +++ b/src/renderer/backend/dx/dx_pipeline.cpp @@ -32,6 +32,7 @@ void dx_pipeline::draw() { d3d_context->IASetVertexBuffers(0, 1, &v_buffer, &stride, &offset); d3d_context->IASetIndexBuffer(i_buffer, DXGI_FORMAT_R32_UINT, 0); d3d_context->VSSetConstantBuffers(0, 1, &c_buffer); + d3d_context->PSSetConstantBuffers(0, 1, &c_buffer); // 设置图元拓扑 d3d_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); @@ -40,9 +41,10 @@ void dx_pipeline::draw() { d3d_context->Draw(vertex_buffer->get_size(), 0); } -void dx_pipeline::load_pixel_shader() { +void dx_pipeline::load_pixel_shader(const char* shader_name) { + if (pixel_shader) { pixel_shader->Release(); } const auto d3d_device = aorii::get_renderer()->get_d3d_device(); - const auto& shader_code = load_shader(AORII_DEFAULT_PIXEL_SHADER_NAME); + const auto& shader_code = load_shader(shader_name); const auto hr = d3d_device->CreatePixelShader(shader_code.data(), shader_code.size(), nullptr, &pixel_shader); if (FAILED(hr)) { spdlog::critical("无法创建像素着色器: {0}", hr); } } @@ -64,16 +66,8 @@ void dx_pipeline::load_vertex_shader() { spdlog::critical("无法创建输入布局: {0}", hr); return; } -} - -void dx_pipeline::build_vertex_buffer(int vertex_count) { - delete vertex_buffer; - vertex_buffer = new dx_buffer(buffer_type::vertex, vertex_count); -} - -void dx_pipeline::build_index_buffer(int triangle_count) { - delete triangle_buffer; - triangle_buffer = new dx_buffer(buffer_type::index, triangle_count); + vertex_buffer = new dx_buffer(buffer_type::vertex, 4); + triangle_buffer = new dx_buffer(buffer_type::index, 2); } void dx_pipeline::build_constant_buffer() { diff --git a/src/renderer/backend/dx/dx_pipeline.h b/src/renderer/backend/dx/dx_pipeline.h index 206cf3b..2e65a6f 100644 --- a/src/renderer/backend/dx/dx_pipeline.h +++ b/src/renderer/backend/dx/dx_pipeline.h @@ -14,16 +14,15 @@ public: void use() override; void draw() override; - void load_pixel_shader(); + void load_pixel_shader(const char* shader_name); void load_vertex_shader(); - void build_vertex_buffer(int vertex_count); - void build_index_buffer(int triangle_count); + void build_constant_buffer(); void set_triangle(const std::span& in_vertexes, const std::span& in_triangles) override; - aorii_constant_buffer_type* lock_constant_buffer(); - void unlock_constant_buffer(); + aorii_constant_buffer_type* lock_constant_buffer() override; + void unlock_constant_buffer() override; private: static std::vector load_shader(const std::string& shader_name); diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp index 9ac3e7a..cc1c5f8 100644 --- a/src/renderer/backend/dx/dx_window.cpp +++ b/src/renderer/backend/dx/dx_window.cpp @@ -8,14 +8,8 @@ #include using namespace aorii; -dx_pipeline pipeline; - -void dx_pipeline_begin_frame(const Eigen::Matrix4f& projection_matrix) { - auto constant_buffer = pipeline.lock_constant_buffer(); - constant_buffer->projection_matrix = projection_matrix; - pipeline.unlock_constant_buffer(); - pipeline.use(); -} +dx_pipeline default_pipeline; +dx_pipeline rounded_rect_pipeline; bool dx_window::create_surface(GLFWwindow* in_window) { const auto d3d_device = aorii::get_renderer()->get_d3d_device(); @@ -68,9 +62,8 @@ bool dx_window::create_surface(GLFWwindow* in_window) { return false; } - pipeline.build_vertex_buffer(4); - pipeline.build_index_buffer(2); - pipeline.build_constant_buffer(); + default_pipeline.build_constant_buffer(); + rounded_rect_pipeline.build_constant_buffer(); hr = build_render_target_view(); if (FAILED(hr)) { @@ -78,9 +71,14 @@ bool dx_window::create_surface(GLFWwindow* in_window) { return false; } - pipeline.load_pixel_shader(); - pipeline.load_vertex_shader(); - context.set_default_pipeline(&pipeline); + default_pipeline.load_pixel_shader(AORII_DEFAULT_PIXEL_SHADER_NAME); + default_pipeline.load_vertex_shader(); + + rounded_rect_pipeline.load_pixel_shader(AORII_DEFAULT_ROUNDED_RECT_PIXEL_SHADER_NAME); + rounded_rect_pipeline.load_vertex_shader(); + + context.set_default_pipeline(&default_pipeline); + context.set_rounded_rectangular_pipeline(&rounded_rect_pipeline); return true; } @@ -94,9 +92,7 @@ void dx_window::begin_frame() { d3d_context->OMSetRenderTargets(1, &render_target_view, nullptr); d3d_context->ClearRenderTargetView(render_target_view, clear_color); - dx_pipeline_begin_frame(projection_matrix); - - { + if constexpr (false) { static std::chrono::duration timer = {}; static linear_color random_color = { 0, 0, 0, 1 }; static bool is_white = false; @@ -117,7 +113,6 @@ void dx_window::begin_frame() { is_white = false; random_color = {0.0f, 0.0f, 0.0f, 1.0f}; } - } else { if (random_color.r < 1) { @@ -141,6 +136,7 @@ void dx_window::begin_frame() { } } + context.draw_rounded_rectangle({ 100, 100 }, { 100, 100 }, { 1, 0, 0, 1 }, 10); context.flush(); swap_chain->Present(1, 0); @@ -197,7 +193,16 @@ HRESULT dx_window::build_render_target_view() { viewport.TopLeftY = 0.0f; d3d_context->RSSetViewports(1, &viewport); - projection_matrix = get_projection_matrix().transpose(); + const auto& projection_matrix = get_projection_matrix().transpose(); + + // 更新常量缓冲区 + const auto constant_buffer = default_pipeline.lock_constant_buffer(); + constant_buffer->projection_matrix = projection_matrix; + default_pipeline.unlock_constant_buffer(); + + const auto rounded_rect_constant_buffer = rounded_rect_pipeline.lock_constant_buffer(); + rounded_rect_constant_buffer->projection_matrix = projection_matrix; + rounded_rect_pipeline.unlock_constant_buffer(); return hr; } diff --git a/src/renderer/backend/dx/dx_window.h b/src/renderer/backend/dx/dx_window.h index 232fb30..b710bdb 100644 --- a/src/renderer/backend/dx/dx_window.h +++ b/src/renderer/backend/dx/dx_window.h @@ -19,5 +19,4 @@ private: renderer_context context; IDXGISwapChain1* swap_chain = nullptr; ID3D11RenderTargetView* render_target_view = nullptr; - Eigen::Matrix4f projection_matrix; }; diff --git a/src/renderer/core/pipeline/pipeline.h b/src/renderer/core/pipeline/pipeline.h index 6f27dd6..9931c11 100644 --- a/src/renderer/core/pipeline/pipeline.h +++ b/src/renderer/core/pipeline/pipeline.h @@ -6,6 +6,7 @@ #include "misc/color.h" #define AORII_DEFAULT_PIXEL_SHADER_NAME "default_shader_pixel_main" +#define AORII_DEFAULT_ROUNDED_RECT_PIXEL_SHADER_NAME "default_shader_rounded_rect_pixel_main" #define AORII_DEFAULT_VERTEX_SHADER_NAME "default_shader_vertex_main" struct aorii_vertex { @@ -17,6 +18,8 @@ struct aorii_triangle { }; struct aorii_constant_buffer { Eigen::Matrix4f projection_matrix; + Eigen::Vector2f size; + float radius; }; using aorii_vertex_type = aorii_vertex; using aorii_triangle_type = aorii_triangle; @@ -31,6 +34,9 @@ public: virtual void draw() = 0; virtual void set_triangle(const std::span& in_vertexes, const std::span& in_triangles) = 0; + + virtual aorii_constant_buffer_type* lock_constant_buffer() = 0; + virtual void unlock_constant_buffer() = 0; }; class custom_pipeline : public pipeline { diff --git a/src/renderer/core/renderer/renderer_context.cpp b/src/renderer/core/renderer/renderer_context.cpp index e397245..b0413f8 100644 --- a/src/renderer/core/renderer/renderer_context.cpp +++ b/src/renderer/core/renderer/renderer_context.cpp @@ -23,8 +23,32 @@ void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen } void renderer_context::draw_rounded_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color, float in_radius) { + auto constant_buffer = rounded_rectangular_pipeline->lock_constant_buffer(); + constant_buffer->size = in_size.cast(); + constant_buffer->radius = in_radius; + rounded_rectangular_pipeline->unlock_constant_buffer(); + switch_pipeline(rounded_rectangular_pipeline); + const aorii_vertex_type v1{ { in_pos.x(), in_pos.y() }, in_color }; // 左上角 + const aorii_vertex_type v2{ { in_pos.x() + in_size.x(), in_pos.y() }, in_color }; // 右上角 + const aorii_vertex_type v3{ { in_pos.x(), in_pos.y() + in_size.y() }, in_color }; // 左下角 + const aorii_vertex_type v4{ { in_pos.x() + in_size.x(), in_pos.y() + in_size.y() }, in_color }; // 右下角 + + const uint32_t index1 = vertices.size(); + vertices.push_back(v1); + const uint32_t index2 = vertices.size(); + vertices.push_back(v2); + const uint32_t index3 = vertices.size(); + vertices.push_back(v3); + const uint32_t index4 = vertices.size(); + vertices.push_back(v4); + + const aorii_triangle_type t1 = { index1, index2, index3 }; + const aorii_triangle_type t2 = { index2, index3, index4 }; + triangles.push_back(t1); + triangles.push_back(t2); + // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批 flush(); } diff --git a/src/renderer/core/renderer/renderer_context.h b/src/renderer/core/renderer/renderer_context.h index 7152b18..2d8a76a 100644 --- a/src/renderer/core/renderer/renderer_context.h +++ b/src/renderer/core/renderer/renderer_context.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "core/pipeline/pipeline.h" @@ -34,6 +34,9 @@ public: void set_default_pipeline(pipeline* in_pipeline) { default_pipeline = in_pipeline; } + void set_rounded_rectangular_pipeline(pipeline* in_pipeline) { + rounded_rectangular_pipeline = in_pipeline; + } void clear() { vertices.clear(); @@ -56,9 +59,14 @@ public: } protected: void switch_pipeline(pipeline* in_pipeline) { +#if DEBUG + if (!in_pipeline) + spdlog::critical("尝试切换到空管线"); +#endif if (current_pipeline != in_pipeline) { flush(); current_pipeline = in_pipeline; + current_pipeline->use(); } } private: diff --git a/src/renderer/shader/default_shader.slang b/src/renderer/shader/default_shader.slang index 5256210..09a13c9 100644 --- a/src/renderer/shader/default_shader.slang +++ b/src/renderer/shader/default_shader.slang @@ -1,14 +1,10 @@ -struct MatrixBuffer +struct ParamBuffer { matrix transform; -}; -struct RoundedRectBuffer -{ float2 size; // 像素单位 float radius; // 像素单位 }; -ParameterBlock matrix_buffer : register(b0); -ParameterBlock rounded_rect_buffer : register(b1); +ParameterBlock param_buffer : register(b0); SamplerState texture_sampler : register(s0); struct VSInput { @@ -22,20 +18,6 @@ struct PSInput { float2 uv : TEXCOORD0; }; -PSInput vertex_main(VSInput input) -{ - PSInput output; - output.position = mul(float4(input.position, 0.0, 1.0), matrix_buffer.transform); - output.color = input.color; - output.uv = input.position + 0.5; - return output; -} - -float4 pixel_main(PSInput input) : SV_TARGET -{ - return input.color; -} - // 计算点到矩形边的最小距离 float rounded_box_SDF(float2 center_position, float2 size, float radius) { @@ -43,11 +25,21 @@ float rounded_box_SDF(float2 center_position, float2 size, float radius) return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius; } +PSInput vertex_main(VSInput input) +{ + PSInput output; + output.position = mul(float4(input.position, 0.0, 1.0), param_buffer.transform); + output.color = input.color; + output.uv = (input.position + float2(1.0, 1.0)) * 0.5; // 将 [-1, 1] 映射到 [0, 1] + return output; +} + +#ifdef IS_ROUNDED_RECT // 圆角矩形像素着色器 float4 rounded_rect_pixel_main(PSInput input) : SV_TARGET { - float2 size = rounded_rect_buffer.size; - float radius = rounded_rect_buffer.radius; + float2 size = param_buffer.size; + float radius = param_buffer.radius; // 将UV坐标转换为中心坐标系统 float2 center_position = (input.uv - 0.5) * size; @@ -59,5 +51,11 @@ float4 rounded_rect_pixel_main(PSInput input) : SV_TARGET float alpha = 1.0 - smoothstep(-1.0, 1.0, distance); // 返回最终颜色 - return float4(input.color.xyz, input.color.a * alpha); + return float4(float3(1, 1, 1), input.color.a * alpha); } +#else +float4 pixel_main(PSInput input) : SV_TARGET +{ + return input.color; +} +#endif