允许添加自定义命令到着色器编译函数

优化dx_pipeline代码结构
This commit is contained in:
Nanako 2024-11-05 18:36:50 +08:00
parent 5220ba6e39
commit 64d7894981
10 changed files with 101 additions and 69 deletions

View File

@ -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})"
)

View File

@ -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})

View File

@ -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<dx_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<aorii_vertex_type>(buffer_type::vertex, vertex_count);
}
void dx_pipeline::build_index_buffer(int triangle_count) {
delete triangle_buffer;
triangle_buffer = new dx_buffer<aorii_triangle_type>(buffer_type::index, triangle_count);
vertex_buffer = new dx_buffer<aorii_vertex_type>(buffer_type::vertex, 4);
triangle_buffer = new dx_buffer<aorii_triangle_type>(buffer_type::index, 2);
}
void dx_pipeline::build_constant_buffer() {

View File

@ -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<const aorii_vertex_type>& in_vertexes, const std::span<const aorii_triangle_type>& 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<char> load_shader(const std::string& shader_name);

View File

@ -8,14 +8,8 @@
#include <math.h>
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<dx_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<double> 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;
}

View File

@ -19,5 +19,4 @@ private:
renderer_context context;
IDXGISwapChain1* swap_chain = nullptr;
ID3D11RenderTargetView* render_target_view = nullptr;
Eigen::Matrix4f projection_matrix;
};

View File

@ -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<const aorii_vertex_type>& in_vertexes, const std::span<const aorii_triangle_type>& in_triangles) = 0;
virtual aorii_constant_buffer_type* lock_constant_buffer() = 0;
virtual void unlock_constant_buffer() = 0;
};
class custom_pipeline : public pipeline {

View File

@ -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<float>();
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();
}

View File

@ -1,5 +1,5 @@
#pragma once
#include <Eigen/Eigen>
#include <spdlog/spdlog.h>
#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:

View File

@ -1,14 +1,10 @@
struct MatrixBuffer
struct ParamBuffer
{
matrix transform;
};
struct RoundedRectBuffer
{
float2 size; // 像素单位
float radius; // 像素单位
};
ParameterBlock<MatrixBuffer> matrix_buffer : register(b0);
ParameterBlock<RoundedRectBuffer> rounded_rect_buffer : register(b1);
ParameterBlock<ParamBuffer> 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