From 7c8b11e28a711278b6fb9bdf58d750527130af36 Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Wed, 24 May 2023 18:33:55 +0100 Subject: [PATCH] Implement render ordering --- include/gfx.h | 8 +++ include/resources/shader.h | 15 +++++- src/application.cpp | 29 ++++++++--- src/gfx_device_vulkan.cpp | 15 +++++- src/resources/font.cpp | 2 +- src/resources/shader.cpp | 101 ++++++++++++++++++------------------- src/systems/render.cpp | 50 ++++++++++++------ 7 files changed, 143 insertions(+), 77 deletions(-) diff --git a/include/gfx.h b/include/gfx.h index 0606178..7a9972c 100644 --- a/include/gfx.h +++ b/include/gfx.h @@ -66,6 +66,13 @@ enum class Primitive { kTriangleStrip, }; +enum class CullMode { + kCullNone, + kCullFront, + kCullBack, + kCullFrontAndBack +}; + enum class VertexAttribFormat { kFloat2, kFloat3, kFloat4 }; enum class Filter : int { @@ -106,6 +113,7 @@ struct PipelineInfo { VertexFormat vertex_format; bool alpha_blending; bool backface_culling; + bool write_z; std::vector descriptor_set_layouts; }; diff --git a/include/resources/shader.h b/include/resources/shader.h index 2659204..1a08a26 100644 --- a/include/resources/shader.h +++ b/include/resources/shader.h @@ -18,18 +18,29 @@ class Shader { bool has_uv0; // vec2 }; + struct ShaderSettings { + VertexParams vertexParams; + bool alpha_blending; + bool cull_backface; + bool write_z; + int render_order; + }; + + static constexpr int kHighestRenderOrder = 1; + Shader(RenderData* render_data, const char* vert_path, const char* frag_path, - const VertexParams& vertex_params, bool alpha_blending, - bool cull_backface); + const ShaderSettings& settings); ~Shader(); Shader(const Shader&) = delete; Shader& operator=(const Shader&) = delete; const gfx::Pipeline* GetPipeline(); + int GetRenderOrder() { return render_order_; } private: GFXDevice* const gfx_; const gfx::Pipeline* pipeline_; + const int render_order_; }; } // namespace resources diff --git a/src/application.cpp b/src/application.cpp index e4cbfb0..dc451b9 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -139,10 +139,16 @@ Application::Application(const char* appName, const char* appVersion, resources::Shader::VertexParams vertParams{}; vertParams.has_normal = true; vertParams.has_uv0 = true; + resources::Shader::ShaderSettings shaderSettings{}; + shaderSettings.vertexParams = vertParams; + shaderSettings.alpha_blending = false; + shaderSettings.cull_backface = true; + shaderSettings.write_z = true; + shaderSettings.render_order = 0; auto texturedShader = std::make_unique( &render_data_, GetResourcePath("engine/shaders/standard.vert").c_str(), - GetResourcePath("engine/shaders/standard.frag").c_str(), vertParams, - false, true); + GetResourcePath("engine/shaders/standard.frag").c_str(), + shaderSettings); GetResourceManager()->AddPersistent( "builtin.standard", std::move(texturedShader)); } @@ -150,10 +156,15 @@ Application::Application(const char* appName, const char* appVersion, resources::Shader::VertexParams vertParams{}; vertParams.has_normal = true; vertParams.has_uv0 = true; + resources::Shader::ShaderSettings shaderSettings{}; + shaderSettings.vertexParams = vertParams; + shaderSettings.alpha_blending = false; + shaderSettings.cull_backface = true; + shaderSettings.write_z = true; + shaderSettings.render_order = 0; auto skyboxShader = std::make_unique( &render_data_, GetResourcePath("engine/shaders/skybox.vert").c_str(), - GetResourcePath("engine/shaders/skybox.frag").c_str(), vertParams, - false, true); + GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings); GetResourceManager()->AddPersistent( "builtin.skybox", std::move(skyboxShader)); } @@ -161,15 +172,19 @@ Application::Application(const char* appName, const char* appVersion, resources::Shader::VertexParams vertParams{}; vertParams.has_normal = true; vertParams.has_uv0 = true; + resources::Shader::ShaderSettings shaderSettings{}; + shaderSettings.vertexParams = vertParams; + shaderSettings.alpha_blending = true; + shaderSettings.cull_backface = true; + shaderSettings.write_z = false; + shaderSettings.render_order = 1; auto quadShader = std::make_unique( &render_data_, GetResourcePath("engine/shaders/quad.vert").c_str(), - GetResourcePath("engine/shaders/quad.frag").c_str(), vertParams, - true, true); + GetResourcePath("engine/shaders/quad.frag").c_str(), shaderSettings); GetResourceManager()->AddPersistent( "builtin.quad", std::move(quadShader)); } - /* default textures */ { auto whiteTexture = std::make_unique( diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 1a530c9..f58ffa6 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -214,6 +214,19 @@ namespace engine { return out; } + [[maybe_unused]] static VkCullModeFlags getCullModeFlags(gfx::CullMode mode) { + switch (mode) { + case gfx::CullMode::kCullNone: + return VK_CULL_MODE_NONE; + case gfx::CullMode::kCullFront: + return VK_CULL_MODE_FRONT_BIT; + case gfx::CullMode::kCullBack: + return VK_CULL_MODE_BACK_BIT; + case gfx::CullMode::kCullFrontAndBack: + return VK_CULL_MODE_FRONT_AND_BACK; + } + } + } // functions @@ -974,7 +987,7 @@ namespace engine { VkPipelineDepthStencilStateCreateInfo depthStencil{}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.depthTestEnable = VK_TRUE; - depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthWriteEnable = info.write_z ? VK_TRUE : VK_FALSE; depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; depthStencil.depthBoundsTestEnable = VK_FALSE; depthStencil.minDepthBounds = 0.0f; diff --git a/src/resources/font.cpp b/src/resources/font.cpp index 1c5e120..137d8b6 100644 --- a/src/resources/font.cpp +++ b/src/resources/font.cpp @@ -102,7 +102,7 @@ std::unique_ptr> Font::GetTextBitmap( (*bitmap)[out_index + 0] = pixel; (*bitmap)[out_index + 1] = pixel; (*bitmap)[out_index + 2] = pixel; - (*bitmap)[out_index + 3] = 0xFF; + (*bitmap)[out_index + 3] = (pixel == 0x00) ? 0x00 : 0xFF; } } diff --git a/src/resources/shader.cpp b/src/resources/shader.cpp index 13ba7ca..c3f49b1 100644 --- a/src/resources/shader.cpp +++ b/src/resources/shader.cpp @@ -8,60 +8,59 @@ namespace engine::resources { +Shader::Shader(RenderData* renderData, const char* vertPath, + const char* fragPath, const ShaderSettings& settings) + : gfx_(renderData->gfxdev.get()), render_order_(settings.render_order) { + assert(settings.render_order <= kHighestRenderOrder && settings.render_order >= 0); + uint32_t index = 0; + uint32_t stride = 0; + gfx::VertexFormat vertFormat{}; - Shader::Shader(RenderData* renderData, const char* vertPath, const char* fragPath, const VertexParams& vertexParams, bool alphaBlending, bool cullBackFace) - : gfx_(renderData->gfxdev.get()) - { + vertFormat.attribute_descriptions.emplace_back( + index++, gfx::VertexAttribFormat::kFloat3, stride); + stride += 3 * sizeof(float); - uint32_t index = 0; - uint32_t stride = 0; - gfx::VertexFormat vertFormat{}; + if (settings.vertexParams.has_normal) { + vertFormat.attribute_descriptions.emplace_back( + index++, gfx::VertexAttribFormat::kFloat3, stride); + stride += 3 * sizeof(float); + } + if (settings.vertexParams.has_tangent) { + vertFormat.attribute_descriptions.emplace_back( + index++, gfx::VertexAttribFormat::kFloat4, stride); + stride += 4 * sizeof(float); + } + if (settings.vertexParams.has_color) { + vertFormat.attribute_descriptions.emplace_back( + index++, gfx::VertexAttribFormat::kFloat4, stride); + stride += 4 * sizeof(float); + } + if (settings.vertexParams.has_uv0) { + vertFormat.attribute_descriptions.emplace_back( + index++, gfx::VertexAttribFormat::kFloat2, stride); + stride += 2 * sizeof(float); + } + vertFormat.stride = stride; - vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat3, stride); - stride += 3 * sizeof(float); + gfx::PipelineInfo info{}; + info.vert_shader_path = vertPath; + info.frag_shader_path = fragPath; + info.vertex_format = vertFormat; + info.alpha_blending = settings.alpha_blending; + info.backface_culling = settings.cull_backface; + info.write_z = settings.write_z; + info.descriptor_set_layouts.push_back(renderData->global_set_layout); + info.descriptor_set_layouts.push_back(renderData->frame_set_layout); + info.descriptor_set_layouts.push_back(renderData->material_set_layout); - if (vertexParams.has_normal) { - vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat3, stride); - stride += 3 * sizeof(float); - } - if (vertexParams.has_tangent) { - vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat4, stride); - stride += 4 * sizeof(float); - } - if (vertexParams.has_color) { - vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat4, stride); - stride += 4 * sizeof(float); - } - if (vertexParams.has_uv0) { - vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat2, stride); - stride += 2 * sizeof(float); - } - vertFormat.stride = stride; - - gfx::PipelineInfo info{}; - info.vert_shader_path = vertPath; - info.frag_shader_path = fragPath; - info.vertex_format = vertFormat; - info.alpha_blending = alphaBlending; - info.backface_culling = cullBackFace; - info.descriptor_set_layouts.push_back(renderData->global_set_layout); - info.descriptor_set_layouts.push_back(renderData->frame_set_layout); - info.descriptor_set_layouts.push_back(renderData->material_set_layout); - - pipeline_ = gfx_->CreatePipeline(info); - - LOG_INFO("Loaded shader: {}, vertex attribs: {}", vertPath, vertFormat.attribute_descriptions.size()); - - } - - Shader::~Shader() - { - gfx_->DestroyPipeline(pipeline_); - } - - const gfx::Pipeline* Shader::GetPipeline() - { - return pipeline_; - } + pipeline_ = gfx_->CreatePipeline(info); + LOG_INFO("Loaded shader: {}, vertex attribs: {}", vertPath, + vertFormat.attribute_descriptions.size()); } + +Shader::~Shader() { gfx_->DestroyPipeline(pipeline_); } + +const gfx::Pipeline* Shader::GetPipeline() { return pipeline_; } + +} // namespace engine::resources diff --git a/src/systems/render.cpp b/src/systems/render.cpp index 40ca754..fd63153 100644 --- a/src/systems/render.cpp +++ b/src/systems/render.cpp @@ -71,8 +71,8 @@ void RenderSystem::OnUpdate(float ts) { uint32_t index_count; PushConstants push_constants; }; - std::unordered_map> - pipeline_draw_calls{}; + std::vector> + unsorted_draw_calls{}; for (uint32_t entity : entities_) { auto r = scene_->GetComponent(entity); @@ -85,7 +85,10 @@ void RenderSystem::OnUpdate(float ts) { auto t = scene_->GetComponent(entity); assert(t != nullptr); + int render_order = r->material->GetShader()->GetRenderOrder(); + const gfx::Pipeline* pipeline = r->material->GetShader()->GetPipeline(); + DrawCallData data{}; data.vb = r->mesh->GetVB(); data.ib = r->mesh->GetIB(); @@ -93,31 +96,48 @@ void RenderSystem::OnUpdate(float ts) { data.index_count = r->mesh->GetCount(); data.push_constants.model = t->world_matrix; - pipeline_draw_calls[pipeline].push_back(data); + unsorted_draw_calls.emplace_back( + std::make_tuple(render_order, pipeline, data)); + } + + std::vector> draw_calls{}; + draw_calls.reserve(unsorted_draw_calls.size()); + + /* sort the draw calls */ + for (int i = 0; i <= resources::Shader::kHighestRenderOrder; i++) { + for (const auto& [render_order, pipeline, data] : unsorted_draw_calls) { + if (render_order == i) { + draw_calls.emplace_back(std::make_pair(pipeline, data)); + } + } } /* begin rendering */ render_data.draw_buffer = gfx_->BeginRender(); /* these descriptor set bindings should persist across pipeline changes */ - const gfx::Pipeline* first_pipeline = pipeline_draw_calls.begin()->first; + const gfx::Pipeline* const first_pipeline = draw_calls.begin()->first; gfx_->CmdBindDescriptorSet(render_data.draw_buffer, first_pipeline, render_data.global_set, 0); gfx_->CmdBindDescriptorSet(render_data.draw_buffer, first_pipeline, render_data.frame_set, 1); - for (const auto& [pipeline, draw_calls] : pipeline_draw_calls) { - gfx_->CmdBindPipeline(render_data.draw_buffer, pipeline); - for (const auto& draw_call : draw_calls) { - gfx_->CmdBindDescriptorSet(render_data.draw_buffer, pipeline, - draw_call.material_set, 2); - gfx_->CmdPushConstants(render_data.draw_buffer, pipeline, 0, - sizeof(PushConstants), &draw_call.push_constants); - gfx_->CmdBindVertexBuffer(render_data.draw_buffer, 0, draw_call.vb); - gfx_->CmdBindIndexBuffer(render_data.draw_buffer, draw_call.ib); - gfx_->CmdDrawIndexed(render_data.draw_buffer, draw_call.index_count, 1, 0, - 0, 0); + gfx_->CmdBindPipeline(render_data.draw_buffer, first_pipeline); + const gfx::Pipeline* last_bound_pipeline = first_pipeline; + + for (const auto& [pipeline, draw_call] : draw_calls) { + if (pipeline != last_bound_pipeline) { + gfx_->CmdBindPipeline(render_data.draw_buffer, pipeline); + last_bound_pipeline = pipeline; } + gfx_->CmdBindDescriptorSet(render_data.draw_buffer, pipeline, + draw_call.material_set, 2); + gfx_->CmdPushConstants(render_data.draw_buffer, pipeline, 0, + sizeof(PushConstants), &draw_call.push_constants); + gfx_->CmdBindVertexBuffer(render_data.draw_buffer, 0, draw_call.vb); + gfx_->CmdBindIndexBuffer(render_data.draw_buffer, draw_call.ib); + gfx_->CmdDrawIndexed(render_data.draw_buffer, draw_call.index_count, 1, 0, + 0, 0); } /* draw */