Implement render ordering

This commit is contained in:
Bailey Harrison 2023-05-24 18:33:55 +01:00
parent 5ddcb90ad2
commit 7c8b11e28a
7 changed files with 143 additions and 77 deletions

View File

@ -66,6 +66,13 @@ enum class Primitive {
kTriangleStrip, kTriangleStrip,
}; };
enum class CullMode {
kCullNone,
kCullFront,
kCullBack,
kCullFrontAndBack
};
enum class VertexAttribFormat { kFloat2, kFloat3, kFloat4 }; enum class VertexAttribFormat { kFloat2, kFloat3, kFloat4 };
enum class Filter : int { enum class Filter : int {
@ -106,6 +113,7 @@ struct PipelineInfo {
VertexFormat vertex_format; VertexFormat vertex_format;
bool alpha_blending; bool alpha_blending;
bool backface_culling; bool backface_culling;
bool write_z;
std::vector<const DescriptorSetLayout*> descriptor_set_layouts; std::vector<const DescriptorSetLayout*> descriptor_set_layouts;
}; };

View File

@ -18,18 +18,29 @@ class Shader {
bool has_uv0; // vec2 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, Shader(RenderData* render_data, const char* vert_path, const char* frag_path,
const VertexParams& vertex_params, bool alpha_blending, const ShaderSettings& settings);
bool cull_backface);
~Shader(); ~Shader();
Shader(const Shader&) = delete; Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete; Shader& operator=(const Shader&) = delete;
const gfx::Pipeline* GetPipeline(); const gfx::Pipeline* GetPipeline();
int GetRenderOrder() { return render_order_; }
private: private:
GFXDevice* const gfx_; GFXDevice* const gfx_;
const gfx::Pipeline* pipeline_; const gfx::Pipeline* pipeline_;
const int render_order_;
}; };
} // namespace resources } // namespace resources

View File

@ -139,10 +139,16 @@ Application::Application(const char* appName, const char* appVersion,
resources::Shader::VertexParams vertParams{}; resources::Shader::VertexParams vertParams{};
vertParams.has_normal = true; vertParams.has_normal = true;
vertParams.has_uv0 = 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<resources::Shader>( auto texturedShader = std::make_unique<resources::Shader>(
&render_data_, GetResourcePath("engine/shaders/standard.vert").c_str(), &render_data_, GetResourcePath("engine/shaders/standard.vert").c_str(),
GetResourcePath("engine/shaders/standard.frag").c_str(), vertParams, GetResourcePath("engine/shaders/standard.frag").c_str(),
false, true); shaderSettings);
GetResourceManager<resources::Shader>()->AddPersistent( GetResourceManager<resources::Shader>()->AddPersistent(
"builtin.standard", std::move(texturedShader)); "builtin.standard", std::move(texturedShader));
} }
@ -150,10 +156,15 @@ Application::Application(const char* appName, const char* appVersion,
resources::Shader::VertexParams vertParams{}; resources::Shader::VertexParams vertParams{};
vertParams.has_normal = true; vertParams.has_normal = true;
vertParams.has_uv0 = 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<resources::Shader>( auto skyboxShader = std::make_unique<resources::Shader>(
&render_data_, GetResourcePath("engine/shaders/skybox.vert").c_str(), &render_data_, GetResourcePath("engine/shaders/skybox.vert").c_str(),
GetResourcePath("engine/shaders/skybox.frag").c_str(), vertParams, GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings);
false, true);
GetResourceManager<resources::Shader>()->AddPersistent( GetResourceManager<resources::Shader>()->AddPersistent(
"builtin.skybox", std::move(skyboxShader)); "builtin.skybox", std::move(skyboxShader));
} }
@ -161,15 +172,19 @@ Application::Application(const char* appName, const char* appVersion,
resources::Shader::VertexParams vertParams{}; resources::Shader::VertexParams vertParams{};
vertParams.has_normal = true; vertParams.has_normal = true;
vertParams.has_uv0 = 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<resources::Shader>( auto quadShader = std::make_unique<resources::Shader>(
&render_data_, GetResourcePath("engine/shaders/quad.vert").c_str(), &render_data_, GetResourcePath("engine/shaders/quad.vert").c_str(),
GetResourcePath("engine/shaders/quad.frag").c_str(), vertParams, GetResourcePath("engine/shaders/quad.frag").c_str(), shaderSettings);
true, true);
GetResourceManager<resources::Shader>()->AddPersistent( GetResourceManager<resources::Shader>()->AddPersistent(
"builtin.quad", std::move(quadShader)); "builtin.quad", std::move(quadShader));
} }
/* default textures */ /* default textures */
{ {
auto whiteTexture = std::make_unique<resources::Texture>( auto whiteTexture = std::make_unique<resources::Texture>(

View File

@ -214,6 +214,19 @@ namespace engine {
return out; 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 // functions
@ -974,7 +987,7 @@ namespace engine {
VkPipelineDepthStencilStateCreateInfo depthStencil{}; VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE; 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.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthStencil.depthBoundsTestEnable = VK_FALSE; depthStencil.depthBoundsTestEnable = VK_FALSE;
depthStencil.minDepthBounds = 0.0f; depthStencil.minDepthBounds = 0.0f;

View File

@ -102,7 +102,7 @@ std::unique_ptr<std::vector<uint8_t>> Font::GetTextBitmap(
(*bitmap)[out_index + 0] = pixel; (*bitmap)[out_index + 0] = pixel;
(*bitmap)[out_index + 1] = pixel; (*bitmap)[out_index + 1] = pixel;
(*bitmap)[out_index + 2] = pixel; (*bitmap)[out_index + 2] = pixel;
(*bitmap)[out_index + 3] = 0xFF; (*bitmap)[out_index + 3] = (pixel == 0x00) ? 0x00 : 0xFF;
} }
} }

View File

@ -8,32 +8,36 @@
namespace engine::resources { namespace engine::resources {
Shader::Shader(RenderData* renderData, const char* vertPath,
Shader::Shader(RenderData* renderData, const char* vertPath, const char* fragPath, const VertexParams& vertexParams, bool alphaBlending, bool cullBackFace) const char* fragPath, const ShaderSettings& settings)
: gfx_(renderData->gfxdev.get()) : gfx_(renderData->gfxdev.get()), render_order_(settings.render_order) {
{ assert(settings.render_order <= kHighestRenderOrder && settings.render_order >= 0);
uint32_t index = 0; uint32_t index = 0;
uint32_t stride = 0; uint32_t stride = 0;
gfx::VertexFormat vertFormat{}; gfx::VertexFormat vertFormat{};
vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat3, stride); vertFormat.attribute_descriptions.emplace_back(
index++, gfx::VertexAttribFormat::kFloat3, stride);
stride += 3 * sizeof(float); stride += 3 * sizeof(float);
if (vertexParams.has_normal) { if (settings.vertexParams.has_normal) {
vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat3, stride); vertFormat.attribute_descriptions.emplace_back(
index++, gfx::VertexAttribFormat::kFloat3, stride);
stride += 3 * sizeof(float); stride += 3 * sizeof(float);
} }
if (vertexParams.has_tangent) { if (settings.vertexParams.has_tangent) {
vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat4, stride); vertFormat.attribute_descriptions.emplace_back(
index++, gfx::VertexAttribFormat::kFloat4, stride);
stride += 4 * sizeof(float); stride += 4 * sizeof(float);
} }
if (vertexParams.has_color) { if (settings.vertexParams.has_color) {
vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat4, stride); vertFormat.attribute_descriptions.emplace_back(
index++, gfx::VertexAttribFormat::kFloat4, stride);
stride += 4 * sizeof(float); stride += 4 * sizeof(float);
} }
if (vertexParams.has_uv0) { if (settings.vertexParams.has_uv0) {
vertFormat.attribute_descriptions.emplace_back(index++, gfx::VertexAttribFormat::kFloat2, stride); vertFormat.attribute_descriptions.emplace_back(
index++, gfx::VertexAttribFormat::kFloat2, stride);
stride += 2 * sizeof(float); stride += 2 * sizeof(float);
} }
vertFormat.stride = stride; vertFormat.stride = stride;
@ -42,26 +46,21 @@ namespace engine::resources {
info.vert_shader_path = vertPath; info.vert_shader_path = vertPath;
info.frag_shader_path = fragPath; info.frag_shader_path = fragPath;
info.vertex_format = vertFormat; info.vertex_format = vertFormat;
info.alpha_blending = alphaBlending; info.alpha_blending = settings.alpha_blending;
info.backface_culling = cullBackFace; 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->global_set_layout);
info.descriptor_set_layouts.push_back(renderData->frame_set_layout); info.descriptor_set_layouts.push_back(renderData->frame_set_layout);
info.descriptor_set_layouts.push_back(renderData->material_set_layout); info.descriptor_set_layouts.push_back(renderData->material_set_layout);
pipeline_ = gfx_->CreatePipeline(info); pipeline_ = gfx_->CreatePipeline(info);
LOG_INFO("Loaded shader: {}, vertex attribs: {}", vertPath, vertFormat.attribute_descriptions.size()); LOG_INFO("Loaded shader: {}, vertex attribs: {}", vertPath,
vertFormat.attribute_descriptions.size());
} }
Shader::~Shader() Shader::~Shader() { gfx_->DestroyPipeline(pipeline_); }
{
gfx_->DestroyPipeline(pipeline_);
}
const gfx::Pipeline* Shader::GetPipeline() const gfx::Pipeline* Shader::GetPipeline() { return pipeline_; }
{
return pipeline_;
}
} } // namespace engine::resources

View File

@ -71,8 +71,8 @@ void RenderSystem::OnUpdate(float ts) {
uint32_t index_count; uint32_t index_count;
PushConstants push_constants; PushConstants push_constants;
}; };
std::unordered_map<const gfx::Pipeline*, std::vector<DrawCallData>> std::vector<std::tuple<int, const gfx::Pipeline*, DrawCallData>>
pipeline_draw_calls{}; unsorted_draw_calls{};
for (uint32_t entity : entities_) { for (uint32_t entity : entities_) {
auto r = scene_->GetComponent<RenderableComponent>(entity); auto r = scene_->GetComponent<RenderableComponent>(entity);
@ -85,7 +85,10 @@ void RenderSystem::OnUpdate(float ts) {
auto t = scene_->GetComponent<TransformComponent>(entity); auto t = scene_->GetComponent<TransformComponent>(entity);
assert(t != nullptr); assert(t != nullptr);
int render_order = r->material->GetShader()->GetRenderOrder();
const gfx::Pipeline* pipeline = r->material->GetShader()->GetPipeline(); const gfx::Pipeline* pipeline = r->material->GetShader()->GetPipeline();
DrawCallData data{}; DrawCallData data{};
data.vb = r->mesh->GetVB(); data.vb = r->mesh->GetVB();
data.ib = r->mesh->GetIB(); data.ib = r->mesh->GetIB();
@ -93,22 +96,40 @@ void RenderSystem::OnUpdate(float ts) {
data.index_count = r->mesh->GetCount(); data.index_count = r->mesh->GetCount();
data.push_constants.model = t->world_matrix; 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<std::pair<const gfx::Pipeline*, DrawCallData>> 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 */ /* begin rendering */
render_data.draw_buffer = gfx_->BeginRender(); render_data.draw_buffer = gfx_->BeginRender();
/* these descriptor set bindings should persist across pipeline changes */ /* 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, gfx_->CmdBindDescriptorSet(render_data.draw_buffer, first_pipeline,
render_data.global_set, 0); render_data.global_set, 0);
gfx_->CmdBindDescriptorSet(render_data.draw_buffer, first_pipeline, gfx_->CmdBindDescriptorSet(render_data.draw_buffer, first_pipeline,
render_data.frame_set, 1); render_data.frame_set, 1);
for (const auto& [pipeline, draw_calls] : pipeline_draw_calls) { 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); gfx_->CmdBindPipeline(render_data.draw_buffer, pipeline);
for (const auto& draw_call : draw_calls) { last_bound_pipeline = pipeline;
}
gfx_->CmdBindDescriptorSet(render_data.draw_buffer, pipeline, gfx_->CmdBindDescriptorSet(render_data.draw_buffer, pipeline,
draw_call.material_set, 2); draw_call.material_set, 2);
gfx_->CmdPushConstants(render_data.draw_buffer, pipeline, 0, gfx_->CmdPushConstants(render_data.draw_buffer, pipeline, 0,
@ -118,7 +139,6 @@ void RenderSystem::OnUpdate(float ts) {
gfx_->CmdDrawIndexed(render_data.draw_buffer, draw_call.index_count, 1, 0, gfx_->CmdDrawIndexed(render_data.draw_buffer, draw_call.index_count, 1, 0,
0, 0); 0, 0);
} }
}
/* draw */ /* draw */
gfx_->FinishRender(render_data.draw_buffer); gfx_->FinishRender(render_data.draw_buffer);