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,
};
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<const DescriptorSetLayout*> descriptor_set_layouts;
};

View File

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

View File

@ -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<resources::Shader>(
&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<resources::Shader>()->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<resources::Shader>(
&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<resources::Shader>()->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<resources::Shader>(
&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<resources::Shader>()->AddPersistent(
"builtin.quad", std::move(quadShader));
}
/* default textures */
{
auto whiteTexture = std::make_unique<resources::Texture>(

View File

@ -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;

View File

@ -102,7 +102,7 @@ std::unique_ptr<std::vector<uint8_t>> 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;
}
}

View File

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

View File

@ -71,8 +71,8 @@ void RenderSystem::OnUpdate(float ts) {
uint32_t index_count;
PushConstants push_constants;
};
std::unordered_map<const gfx::Pipeline*, std::vector<DrawCallData>>
pipeline_draw_calls{};
std::vector<std::tuple<int, const gfx::Pipeline*, DrawCallData>>
unsorted_draw_calls{};
for (uint32_t entity : entities_) {
auto r = scene_->GetComponent<RenderableComponent>(entity);
@ -85,7 +85,10 @@ void RenderSystem::OnUpdate(float ts) {
auto t = scene_->GetComponent<TransformComponent>(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<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 */
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 */