封装着色器编译代码命令

编写部分注释
This commit is contained in:
Nanako 2024-11-05 16:48:15 +08:00
parent 498a75c95f
commit f73e7e4a50
13 changed files with 241 additions and 164 deletions

View File

@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 3.10)
project(aorii) project(aorii)
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/shader)
include(cmake/retrieve_files.cmake) include(cmake/retrieve_files.cmake)
include(cmake/detect_os.cmake) include(cmake/detect_os.cmake)
include(cmake/configure_glfw_native.cmake) include(cmake/configure_glfw_native.cmake)
@ -29,8 +27,3 @@ if (BUILD_EXAMPLE)
add_subdirectory(example) add_subdirectory(example)
endif () endif ()
set(SHADER_STAGES
"vertex"
"pixel"
)
compile_slang_shaders(${CMAKE_CURRENT_SOURCE_DIR}/resource/shader/default_shader.slang SHADER_STAGES)

View File

@ -1,87 +1,84 @@
function(compile_slang_shaders input_shaders shader_stages)
# Ensure the output directory exists function(compile_slang_shaders input_file stage entry_point)
#
if (NOT DEFINED SHADER_OUTPUT_DIR)
message(FATAL_ERROR "SHADER_OUTPUT_DIR not defined")
endif ()
set(output_dir ${SHADER_OUTPUT_DIR}) set(output_dir ${SHADER_OUTPUT_DIR})
file(MAKE_DIRECTORY ${output_dir})
foreach(input_file IN LISTS input_shaders) #
# Get the base name for the output file get_filename_component(filename ${input_file} NAME_WE)
get_filename_component(filename ${input_file} NAME_WE)
# Initialize a list to hold all the output files for this shader #
set(output_files) if(stage STREQUAL "vertex")
set(profile "vs_5_0")
elseif(stage STREQUAL "pixel")
set(profile "ps_5_0")
elseif (stage STREQUAL "comp")
set(profile "cs_5_0")
else()
message(FATAL_ERROR "Unsupported shader stage: ${stage}")
endif()
# Use a set to track processed stages to avoid duplication #
set(processed_stages) set(output_files)
foreach(stage IN LISTS ${shader_stages}) #
# Check if the stage has already been processed if(GL_BACKEND)
if(NOT stage IN_LIST processed_stages) set(output_file ${output_dir}/${filename}_${entry_point}.glsl)
list(APPEND processed_stages ${stage}) add_custom_command(
OUTPUT ${output_file}
# Define the entry point based on the stage COMMAND slangc -target glsl -entry ${entry_point} -stage ${stage} -o ${output_file} ${input_file}
if(stage STREQUAL "vertex") DEPENDS ${input_file}
set(entry_point "vertex_main") COMMENT "Compiling ${input_file} to GLSL (${stage}, ${entry_point})"
set(profile "vs_5_0")
elseif(stage STREQUAL "pixel")
set(entry_point "pixel_main")
set(profile "ps_5_0")
elseif (stage STREQUAL "comp")
set(entry_point "compute_main")
set(profile "cs_5_0")
else()
message(FATAL_ERROR "Unsupported shader stage: ${stage}")
endif()
# Check and compile for each backend
if(GL_BACKEND)
list(APPEND output_files ${output_dir}/${filename}_${stage}.glsl)
add_custom_command(
OUTPUT ${output_dir}/${filename}_${stage}.glsl
COMMAND slangc -target glsl -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.glsl ${input_file}
DEPENDS ${input_file}
COMMENT "Compiling ${input_file} to GLSL (${stage})"
)
endif()
if(DX_BACKEND)
list(APPEND output_files ${output_dir}/${filename}_${stage}.dxbc)
add_custom_command(
OUTPUT ${output_dir}/${filename}_${stage}.dxbc
COMMAND slangc -target dxbc -profile ${profile} -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.dxbc ${input_file}
DEPENDS ${input_file}
COMMENT "Compiling ${input_file} to DXBC (${stage})"
)
endif()
if(VK_BACKEND)
list(APPEND output_files ${output_dir}/${filename}_${stage}.spirv)
add_custom_command(
OUTPUT ${output_dir}/${filename}_${stage}.spirv
COMMAND slangc -target spirv -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.spirv ${input_file}
DEPENDS ${input_file}
COMMENT "Compiling ${input_file} to SPIR-V (${stage})"
)
endif()
if(METAL_BACKEND)
list(APPEND output_files ${output_dir}/${filename}_${stage}.metal)
add_custom_command(
OUTPUT ${output_dir}/${filename}_${stage}.metal
COMMAND slangc -target msl -entry ${entry_point} -stage ${stage} -o ${output_dir}/${filename}_${stage}.metal ${input_file}
DEPENDS ${input_file}
COMMENT "Compiling ${input_file} to Metal Shading Language (${stage})"
)
endif()
else()
message(WARNING "The stage '${stage}' has already been processed for entry point '${entry_point}'. Skipping duplicate.")
endif()
endforeach()
# Add the custom command outputs to the compile_shader target
add_custom_target(
compile_shader
DEPENDS ${output_files}
) )
endforeach() list(APPEND output_files ${output_file})
endif()
if(DX_BACKEND)
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}
DEPENDS ${input_file}
COMMENT "Compiling ${input_file} to DXBC (${stage}, ${entry_point}) with profile ${profile}"
)
list(APPEND output_files ${output_file})
endif()
if(VK_BACKEND)
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}
DEPENDS ${input_file}
COMMENT "Compiling ${input_file} to SPIR-V (${stage}, ${entry_point})"
)
list(APPEND output_files ${output_file})
endif()
if(METAL_BACKEND)
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}
DEPENDS ${input_file}
COMMENT "Compiling ${input_file} to Metal Shading Language (${stage}, ${entry_point})"
)
list(APPEND output_files ${output_file})
endif()
#
set_property(GLOBAL APPEND PROPERTY ALL_SHADER_OUTPUTS ${output_files})
endfunction() endfunction()
function(add_compile_shaders_target target_name before_target)
file(MAKE_DIRECTORY ${SHADER_OUTPUT_DIR})
get_property(ALL_SHADER_OUTPUTS GLOBAL PROPERTY ALL_SHADER_OUTPUTS)
add_custom_target(${target_name} ALL DEPENDS ${ALL_SHADER_OUTPUTS})
#
add_dependencies(${before_target} ${target_name})
# ALL_SHADER_OUTPUTS
set_property(GLOBAL PROPERTY ALL_SHADER_OUTPUTS "")
endfunction()

View File

@ -5,3 +5,9 @@ set(SRC_FILES "")
retrieve_files(src SRC_FILES) retrieve_files(src SRC_FILES)
add_executable(${PROJECT_NAME} ${SRC_FILES}) add_executable(${PROJECT_NAME} ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} PRIVATE aorii_renderer) target_link_libraries(${PROJECT_NAME} PRIVATE aorii_renderer)
# ${SHADER_OUTPUT_DIR}${CMAKE_CURRENT_BINARY_DIR}/resource
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${SHADER_OUTPUT_DIR} $<TARGET_FILE_DIR:${PROJECT_NAME}>/resource/shaders
COMMENT "Copying shader files to resource directory after build")

View File

@ -8,7 +8,7 @@ int main(int argc, char* argv[]) {
aorii::create_renderer(renderer_api::dx11); aorii::create_renderer(renderer_api::dx11);
aorii::create_window_manager(); aorii::create_window_manager();
auto window = aorii::create_window({128, 128}, "hello world"); auto window = aorii::create_window({1280, 1280}, "hello world");
auto glfw_window = window->get_glfw_window(); auto glfw_window = window->get_glfw_window();
while (!glfwWindowShouldClose(glfw_window)) { while (!glfwWindowShouldClose(glfw_window)) {
glfwPollEvents(); glfwPollEvents();

View File

@ -1,29 +0,0 @@
struct MatrixBuffer
{
matrix transform;
};
ParameterBlock<MatrixBuffer> matrix_buffer : register(b0);
SamplerState texture_sampler : register(s0);
struct VSInput {
float2 position : POSITION;
float4 color : COLOR;
};
struct PSInput {
float4 position : SV_POSITION;
float4 color : COLOR;
};
PSInput vertex_main(VSInput input)
{
PSInput output;
output.position = mul(float4(input.position, 0.0, 1.0), matrix_buffer.transform);
output.color = input.color;
return output;
}
float4 pixel_main(PSInput input) : SV_TARGET
{
return input.color;
}

View File

@ -54,3 +54,11 @@ foreach(BACKEND ${ALL_BACKENDS})
target_compile_definitions(${PROJECT_NAME} PUBLIC ${BACKEND}=0) target_compile_definitions(${PROJECT_NAME} PUBLIC ${BACKEND}=0)
endforeach() endforeach()
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)
add_compile_shaders_target("compile_aorii_shaders" ${PROJECT_NAME})

View File

@ -20,7 +20,7 @@ public:
void build_index_buffer(int triangle_count); void build_index_buffer(int triangle_count);
void build_constant_buffer(); 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); 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(); aorii_constant_buffer_type* lock_constant_buffer();
void unlock_constant_buffer(); void unlock_constant_buffer();

View File

@ -80,6 +80,7 @@ bool dx_window::create_surface(GLFWwindow* in_window) {
pipeline.load_pixel_shader(); pipeline.load_pixel_shader();
pipeline.load_vertex_shader(); pipeline.load_vertex_shader();
context.set_default_pipeline(&pipeline);
return true; return true;
} }
@ -103,15 +104,7 @@ void dx_window::begin_frame() {
static float pos_y = 0; static float pos_y = 0;
static bool draw_test = true; static bool draw_test = true;
auto delta_time = get_delta_time(); if (draw_test) {
timer += delta_time;
if (draw_test && timer.count() >= 0.01) {
// float random_r = static_cast<float>(rand()) / RAND_MAX;
// float random_g = static_cast<float>(rand()) / RAND_MAX;
// float random_b = static_cast<float>(rand()) / RAND_MAX;
// random_color = { random_r, random_g, random_b, 1.0f };
// 生成渐变色 // 生成渐变色
if (is_white) { if (is_white) {
if (random_color.r > 0) { if (random_color.r > 0) {
@ -139,20 +132,16 @@ void dx_window::begin_frame() {
} }
} }
timer -= std::chrono::duration<double>(0.01); context.draw_rectangle({ pos_x, pos_y }, { 1, 100 }, random_color);
context.draw_rectangle({pos_x, pos_y}, {1, 1000}, random_color); pos_x += 1;
if (pos_x >= 1000) {
pos_x = 0;
draw_test = false;
}
} }
pos_x += delta_time.count() * 100;
if (pos_x >= 1000) {
pos_x = 0;
pos_y += 1;
draw_test = false;
}
pipeline.set_triangle(context.get_vertices(), context.get_triangles());
} }
pipeline.draw();
context.flush();
swap_chain->Present(1, 0); swap_chain->Present(1, 0);
} }

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include <span>
#include <string> #include <string>
#include <Eigen/Eigen> #include <Eigen/Eigen>
#include "misc/color.h" #include "misc/color.h"
#define AORII_DEFAULT_PIXEL_SHADER_NAME "default_shader_pixel" #define AORII_DEFAULT_PIXEL_SHADER_NAME "default_shader_pixel_main"
#define AORII_DEFAULT_VERTEX_SHADER_NAME "default_shader_vertex" #define AORII_DEFAULT_VERTEX_SHADER_NAME "default_shader_vertex_main"
struct aorii_vertex { struct aorii_vertex {
Eigen::Vector2f position; Eigen::Vector2f position;
@ -28,6 +29,8 @@ public:
virtual void use() = 0; virtual void use() = 0;
virtual void draw() = 0; 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;
}; };
class custom_pipeline : public pipeline { class custom_pipeline : public pipeline {

View File

@ -13,10 +13,6 @@ enum class renderer_api {
metal, metal,
}; };
struct vertex_data {
Eigen::Vector3f position;
};
class renderer { class renderer {
friend class window_manager; friend class window_manager;
public: public:
@ -49,7 +45,7 @@ namespace aorii {
const std::chrono::duration<double>& get_delta_time(); const std::chrono::duration<double>& get_delta_time();
inline std::filesystem::path s_shader_relative_path = "resource/shader"; inline std::filesystem::path s_shader_relative_path = "resource/shaders";
inline void set_shader_relative_path(const std::filesystem::path& path) { s_shader_relative_path = path; } inline void set_shader_relative_path(const std::filesystem::path& path) { s_shader_relative_path = path; }
inline std::filesystem::path get_shader_path(const std::string& shader_name) { return std::filesystem::current_path() / s_shader_relative_path / shader_name; } inline std::filesystem::path get_shader_path(const std::string& shader_name) { return std::filesystem::current_path() / s_shader_relative_path / shader_name; }
} }

View File

@ -1,12 +1,11 @@
#include "renderer_context.h" #include "renderer_context.h"
void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color) {
const linear_color& in_color) { switch_pipeline(default_pipeline);
const aorii_vertex_type v1{ { in_pos.x(), in_pos.y() }, in_color }; // 左上角
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 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 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 aorii_vertex_type v4 {{in_pos.x() + in_size.x(), in_pos.y() + in_size.y()}, in_color }; // 右下角
const uint32_t index1 = vertices.size(); const uint32_t index1 = vertices.size();
vertices.push_back(v1); vertices.push_back(v1);
@ -17,22 +16,29 @@ void renderer_context::draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen
const uint32_t index4 = vertices.size(); const uint32_t index4 = vertices.size();
vertices.push_back(v4); vertices.push_back(v4);
const aorii_triangle_type t1 = {index1, index2, index3}; const aorii_triangle_type t1 = { index1, index2, index3 };
const aorii_triangle_type t2 = {index2, index3, index4}; const aorii_triangle_type t2 = { index2, index3, index4 };
triangles.push_back(t1); triangles.push_back(t1);
triangles.push_back(t2); triangles.push_back(t2);
} }
void renderer_context::draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, void renderer_context::draw_rounded_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color, float in_radius) {
const linear_color& in_color, float in_thickness) { switch_pipeline(rounded_rectangular_pipeline);
// 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批
flush();
}
void renderer_context::draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, const linear_color& in_color, float in_thickness) {
switch_pipeline(default_pipeline);
const Eigen::Vector2f direction = (in_pos_p2 - in_pos_p1).cast<float>().normalized(); const Eigen::Vector2f direction = (in_pos_p2 - in_pos_p1).cast<float>().normalized();
const Eigen::Vector2f normal = {-direction.y(), direction.x()}; const Eigen::Vector2f normal = { -direction.y(), direction.x() };
const Eigen::Vector2f offset = normal * in_thickness; const Eigen::Vector2f offset = normal * in_thickness;
const aorii_vertex_type v1 {{in_pos_p1.x() + offset.x(), in_pos_p1.y() + offset.y()}, in_color }; const aorii_vertex_type v1{ { in_pos_p1.x() + offset.x(), in_pos_p1.y() + offset.y() }, in_color };
const aorii_vertex_type v2 {{in_pos_p1.x() - offset.x(), in_pos_p1.y() - offset.y()}, in_color }; const aorii_vertex_type v2{ { in_pos_p1.x() - offset.x(), in_pos_p1.y() - offset.y() }, in_color };
const aorii_vertex_type v3 {{in_pos_p2.x() + offset.x(), in_pos_p2.y() + offset.y()}, in_color }; const aorii_vertex_type v3{ { in_pos_p2.x() + offset.x(), in_pos_p2.y() + offset.y() }, in_color };
const aorii_vertex_type v4 {{in_pos_p2.x() - offset.x(), in_pos_p2.y() - offset.y()}, in_color }; const aorii_vertex_type v4{ { in_pos_p2.x() - offset.x(), in_pos_p2.y() - offset.y() }, in_color };
const uint32_t index1 = vertices.size(); const uint32_t index1 = vertices.size();
vertices.push_back(v1); vertices.push_back(v1);
@ -43,8 +49,8 @@ void renderer_context::draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::
const uint32_t index4 = vertices.size(); const uint32_t index4 = vertices.size();
vertices.push_back(v4); vertices.push_back(v4);
const aorii_triangle_type t1 = {index1, index2, index3}; const aorii_triangle_type t1 = { index1, index2, index3 };
const aorii_triangle_type t2 = {index2, index3, index4}; const aorii_triangle_type t2 = { index2, index3, index4 };
triangles.push_back(t1); triangles.push_back(t1);
triangles.push_back(t2); triangles.push_back(t2);
} }

View File

@ -5,9 +5,36 @@
class renderer_context { class renderer_context {
public: public:
/**
*
* @param in_pos
* @param in_size ()
* @param in_color
*/
void draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color); void draw_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color);
/**
*
* @param in_pos
* @param in_size ()
* @param in_color
* @param in_radius ()
*/
void draw_rounded_rectangle(const Eigen::Vector2i& in_pos, const Eigen::Vector2i& in_size, const linear_color& in_color, float in_radius);
/**
* 线
* @param in_pos_p1 1
* @param in_pos_p2 2
* @param in_color 线
* @param in_thickness 线(), 0, 线
*/
void draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, const linear_color& in_color, float in_thickness); void draw_line(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, const linear_color& in_color, float in_thickness);
void set_default_pipeline(pipeline* in_pipeline) {
default_pipeline = in_pipeline;
}
void clear() { void clear() {
vertices.clear(); vertices.clear();
triangles.clear(); triangles.clear();
@ -19,8 +46,26 @@ public:
[[nodiscard]] const std::vector<aorii_triangle_type>& get_triangles() const { [[nodiscard]] const std::vector<aorii_triangle_type>& get_triangles() const {
return triangles; return triangles;
} }
void flush() {
if (default_pipeline) {
default_pipeline->set_triangle(vertices, triangles);
default_pipeline->draw();
}
clear();
}
protected:
void switch_pipeline(pipeline* in_pipeline) {
if (current_pipeline != in_pipeline) {
flush();
current_pipeline = in_pipeline;
}
}
private: private:
std::vector<aorii_vertex_type> vertices; std::vector<aorii_vertex_type> vertices;
std::vector<aorii_triangle_type> triangles; std::vector<aorii_triangle_type> triangles;
void add_triangle(const Eigen::Vector2i& in_pos_p1, const Eigen::Vector2i& in_pos_p2, const Eigen::Vector2i& in_pos_p3);
pipeline* default_pipeline = nullptr;
pipeline* rounded_rectangular_pipeline = nullptr;
pipeline* current_pipeline = nullptr;
}; };

View File

@ -0,0 +1,63 @@
struct MatrixBuffer
{
matrix transform;
};
struct RoundedRectBuffer
{
float2 size; // 像素单位
float radius; // 像素单位
};
ParameterBlock<MatrixBuffer> matrix_buffer : register(b0);
ParameterBlock<RoundedRectBuffer> rounded_rect_buffer : register(b1);
SamplerState texture_sampler : register(s0);
struct VSInput {
float2 position : POSITION;
float4 color : COLOR;
};
struct PSInput {
float4 position : SV_POSITION;
float4 color : COLOR;
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)
{
float2 q = abs(center_position) - size + radius;
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
}
// 圆角矩形像素着色器
float4 rounded_rect_pixel_main(PSInput input) : SV_TARGET
{
float2 size = rounded_rect_buffer.size;
float radius = rounded_rect_buffer.radius;
// 将UV坐标转换为中心坐标系统
float2 center_position = (input.uv - 0.5) * size;
// 计算到圆角矩形边缘的距离
float distance = rounded_box_SDF(center_position, size * 0.5, radius);
// 使用平滑步进函数创建抗锯齿边缘
float alpha = 1.0 - smoothstep(-1.0, 1.0, distance);
// 返回最终颜色
return float4(input.color.xyz, input.color.a * alpha);
}