rhi: Repurpose Renderbuffer for depth-stencil

This commit is contained in:
Eidolon 2023-03-24 16:05:25 -05:00
parent 28f5afac40
commit c31df8a0bb
10 changed files with 281 additions and 161 deletions

View file

@ -111,10 +111,15 @@ void BlitRectPass::prepass(Rhi& rhi)
if (!render_pass_) if (!render_pass_)
{ {
render_pass_ = rhi.create_render_pass( render_pass_ = rhi.create_render_pass(
{std::nullopt, {
PixelFormat::kRGBA8, false,
output_clear_ ? AttachmentLoadOp::kClear : AttachmentLoadOp::kLoad, output_clear_ ? AttachmentLoadOp::kClear : AttachmentLoadOp::kLoad,
AttachmentStoreOp::kStore} AttachmentStoreOp::kStore,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare
}
); );
} }
} }

View file

@ -25,7 +25,7 @@ static const PipelineDesc kPipelineDesc = {
{VertexAttributeName::kColor, 0, 24}}}, {VertexAttributeName::kColor, 0, 24}}},
{{{{UniformName::kProjection}}, {{UniformName::kModelView, UniformName::kTexCoord0Transform}}}}, {{{{UniformName::kProjection}}, {{UniformName::kModelView, UniformName::kTexCoord0Transform}}}},
{{SamplerName::kSampler0}}, {{SamplerName::kSampler0}},
PipelineDepthAttachmentDesc {PixelFormat::kDepth16, CompareFunc::kAlways, true}, PipelineDepthStencilStateDesc {true, true, CompareFunc::kAlways, false, {}, {}},
{PixelFormat::kRGBA8, {PixelFormat::kRGBA8,
BlendDesc { BlendDesc {
BlendFactor::kSourceAlpha, BlendFactor::kSourceAlpha,

View file

@ -67,7 +67,15 @@ void PostprocessWipePass::prepass(Rhi& rhi)
if (!render_pass_) if (!render_pass_)
{ {
render_pass_ = rhi.create_render_pass( render_pass_ = rhi.create_render_pass(
{std::nullopt, PixelFormat::kRGBA8, AttachmentLoadOp::kLoad, AttachmentStoreOp::kStore} {
false,
AttachmentLoadOp::kLoad,
AttachmentStoreOp::kStore,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare
}
); );
} }

View file

@ -75,7 +75,7 @@ void FramebufferManager::prepass(Rhi& rhi)
} }
if (main_depth_ == kNullHandle) if (main_depth_ == kNullHandle)
{ {
main_depth_ = rhi.create_renderbuffer({PixelFormat::kDepth16, current_width, current_height}); main_depth_ = rhi.create_renderbuffer({current_width, current_height});
} }
if (post_colors_[0] == kNullHandle) if (post_colors_[0] == kNullHandle)

View file

@ -26,10 +26,13 @@ void ScreenshotPass::prepass(Rhi& rhi)
{ {
render_pass_ = rhi.create_render_pass( render_pass_ = rhi.create_render_pass(
{ {
std::nullopt, false,
PixelFormat::kRGBA8,
AttachmentLoadOp::kLoad, AttachmentLoadOp::kLoad,
AttachmentStoreOp::kStore AttachmentStoreOp::kStore,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare
} }
); );
} }

View file

@ -512,7 +512,15 @@ void TwodeePass::prepass(Rhi& rhi)
if (!render_pass_) if (!render_pass_)
{ {
render_pass_ = rhi.create_render_pass( render_pass_ = rhi.create_render_pass(
{std::nullopt, PixelFormat::kRGBA8, AttachmentLoadOp::kLoad, AttachmentStoreOp::kStore} {
false,
AttachmentLoadOp::kLoad,
AttachmentStoreOp::kStore,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare
}
); );
} }

View file

@ -524,15 +524,15 @@ rhi::Handle<rhi::Texture> GlCoreRhi::create_texture(const rhi::TextureDesc& desc
gl_->BindTexture(GL_TEXTURE_2D, name); gl_->BindTexture(GL_TEXTURE_2D, name);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GL_ASSERT GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GL_ASSERT GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
GL_ASSERT GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
GL_ASSERT GL_ASSERT;
gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.width, desc.height, 0, format, GL_UNSIGNED_BYTE, nullptr); gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.width, desc.height, 0, format, GL_UNSIGNED_BYTE, nullptr);
GL_ASSERT GL_ASSERT;
GlCoreTexture texture; GlCoreTexture texture;
texture.texture = name; texture.texture = name;
@ -586,9 +586,9 @@ void GlCoreRhi::update_texture(
SRB2_ASSERT(region.x + region.w <= t.desc.width && region.y + region.h <= t.desc.height); SRB2_ASSERT(region.x + region.w <= t.desc.width && region.y + region.h <= t.desc.height);
gl_->ActiveTexture(GL_TEXTURE0); gl_->ActiveTexture(GL_TEXTURE0);
GL_ASSERT GL_ASSERT;
gl_->BindTexture(GL_TEXTURE_2D, t.texture); gl_->BindTexture(GL_TEXTURE_2D, t.texture);
GL_ASSERT GL_ASSERT;
gl_->TexSubImage2D( gl_->TexSubImage2D(
GL_TEXTURE_2D, GL_TEXTURE_2D,
0, 0,
@ -600,7 +600,7 @@ void GlCoreRhi::update_texture(
type, type,
reinterpret_cast<const void*>(data.data()) reinterpret_cast<const void*>(data.data())
); );
GL_ASSERT GL_ASSERT;
} }
rhi::Handle<rhi::Buffer> GlCoreRhi::create_buffer(const rhi::BufferDesc& desc) rhi::Handle<rhi::Buffer> GlCoreRhi::create_buffer(const rhi::BufferDesc& desc)
@ -615,13 +615,13 @@ rhi::Handle<rhi::Buffer> GlCoreRhi::create_buffer(const rhi::BufferDesc& desc)
GLuint name = 0; GLuint name = 0;
gl_->GenBuffers(1, &name); gl_->GenBuffers(1, &name);
GL_ASSERT GL_ASSERT;
gl_->BindBuffer(target, name); gl_->BindBuffer(target, name);
GL_ASSERT GL_ASSERT;
gl_->BufferData(target, desc.size, nullptr, usage); gl_->BufferData(target, desc.size, nullptr, usage);
GL_ASSERT GL_ASSERT;
GlCoreBuffer buffer; GlCoreBuffer buffer;
buffer.buffer = name; buffer.buffer = name;
@ -674,9 +674,9 @@ void GlCoreRhi::update_buffer(
} }
gl_->BindBuffer(target, b.buffer); gl_->BindBuffer(target, b.buffer);
GL_ASSERT GL_ASSERT;
gl_->BufferSubData(target, offset, data.size(), data.data()); gl_->BufferSubData(target, offset, data.size(), data.data());
GL_ASSERT GL_ASSERT;
} }
rhi::Handle<rhi::UniformSet> rhi::Handle<rhi::UniformSet>
@ -715,9 +715,9 @@ rhi::Handle<rhi::BindingSet> GlCoreRhi::create_binding_set(
GLuint vao = 0; GLuint vao = 0;
gl_->GenVertexArrays(1, &vao); gl_->GenVertexArrays(1, &vao);
GL_ASSERT GL_ASSERT;
gl_->BindVertexArray(vao); gl_->BindVertexArray(vao);
GL_ASSERT GL_ASSERT;
for (auto& attr_layout : pl.desc.vertex_input.attr_layouts) for (auto& attr_layout : pl.desc.vertex_input.attr_layouts)
{ {
@ -728,7 +728,7 @@ rhi::Handle<rhi::BindingSet> GlCoreRhi::create_binding_set(
auto& buffer_layout = pl.desc.vertex_input.buffer_layouts[attr_layout.buffer_index]; auto& buffer_layout = pl.desc.vertex_input.buffer_layouts[attr_layout.buffer_index];
gl_->BindBuffer(GL_ARRAY_BUFFER, buf.buffer); gl_->BindBuffer(GL_ARRAY_BUFFER, buf.buffer);
GL_ASSERT GL_ASSERT;
GLuint attrib_location = pl.attrib_locations[attr_layout.name]; GLuint attrib_location = pl.attrib_locations[attr_layout.name];
VertexAttributeFormat vert_attr_format = rhi::vertex_attribute_format(attr_layout.name); VertexAttributeFormat vert_attr_format = rhi::vertex_attribute_format(attr_layout.name);
@ -738,7 +738,7 @@ rhi::Handle<rhi::BindingSet> GlCoreRhi::create_binding_set(
SRB2_ASSERT(vertex_attr_size != 0); SRB2_ASSERT(vertex_attr_size != 0);
uint32_t vertex_buffer_offset = 0; // TODO allow binding set to specify uint32_t vertex_buffer_offset = 0; // TODO allow binding set to specify
gl_->EnableVertexAttribArray(pl.attrib_locations[attr_layout.name]); gl_->EnableVertexAttribArray(pl.attrib_locations[attr_layout.name]);
GL_ASSERT GL_ASSERT;
gl_->VertexAttribPointer( gl_->VertexAttribPointer(
attrib_location, attrib_location,
vertex_attr_size, vertex_attr_size,
@ -747,7 +747,7 @@ rhi::Handle<rhi::BindingSet> GlCoreRhi::create_binding_set(
buffer_layout.stride, buffer_layout.stride,
reinterpret_cast<const void*>(vertex_buffer_offset + attr_layout.offset) reinterpret_cast<const void*>(vertex_buffer_offset + attr_layout.offset)
); );
GL_ASSERT GL_ASSERT;
} }
binding_set.vao = vao; binding_set.vao = vao;
@ -776,9 +776,24 @@ rhi::Handle<rhi::Renderbuffer> GlCoreRhi::create_renderbuffer(const rhi::Renderb
// Obtain storage up-front. // Obtain storage up-front.
gl_->BindRenderbuffer(GL_RENDERBUFFER, name); gl_->BindRenderbuffer(GL_RENDERBUFFER, name);
GL_ASSERT GL_ASSERT;
gl_->RenderbufferStorage(GL_RENDERBUFFER, map_pixel_format(desc.format), desc.width, desc.height);
GL_ASSERT // For consistency, while RHI does not specify the bit size of the depth or stencil components,
// nor if they are packed or separate, each backend should be expected to create a packed depth-stencil
// D24S8 format image.
// This is despite modern AMD apparently not supporting this format in hardware. It ensures the
// depth behavior between backends is the same. We should not brush up against performance issues in practice.
// - GL Core requires both D24S8 and D32FS8 format support.
// - GL 2 via ARB_framebuffer_object requires D24S8. Backend must require this extension.
// - GLES 2 via OES_packed_depth_stencil requires D24S8. Backend must require this extension.
// - Vulkan requires **one of** D24S8 or D32FS8. The backend must decide which format to use based on caps.
// (Even if D32FS8 is available, D24S8 should be preferred)
// For reference, D32FS8 at 4k requires 64 MiB of linear memory. D24S8 is 32 MiB.
gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, desc.width, desc.height);
GL_ASSERT;
GlCoreRenderbuffer rb; GlCoreRenderbuffer rb;
rb.renderbuffer = name; rb.renderbuffer = name;
@ -994,9 +1009,9 @@ rhi::Handle<rhi::Pipeline> GlCoreRhi::create_pipeline(const PipelineDesc& desc)
GLenum type = GL_ZERO; GLenum type = GL_ZERO;
char name[256]; char name[256];
gl_->GetActiveAttrib(program, i, 255, &name_len, &size, &type, name); gl_->GetActiveAttrib(program, i, 255, &name_len, &size, &type, name);
GL_ASSERT GL_ASSERT;
GLint location = gl_->GetAttribLocation(program, name); GLint location = gl_->GetAttribLocation(program, name);
GL_ASSERT GL_ASSERT;
active_attributes.insert({std::string(name), GlCoreActiveUniform {type, static_cast<GLuint>(location)}}); active_attributes.insert({std::string(name), GlCoreActiveUniform {type, static_cast<GLuint>(location)}});
} }
@ -1036,9 +1051,9 @@ rhi::Handle<rhi::Pipeline> GlCoreRhi::create_pipeline(const PipelineDesc& desc)
GLenum type = GL_ZERO; GLenum type = GL_ZERO;
char name[256]; char name[256];
gl_->GetActiveUniform(program, i, 255, &name_len, &size, &type, name); gl_->GetActiveUniform(program, i, 255, &name_len, &size, &type, name);
GL_ASSERT GL_ASSERT;
GLint location = gl_->GetUniformLocation(program, name); GLint location = gl_->GetUniformLocation(program, name);
GL_ASSERT GL_ASSERT;
active_uniforms.insert({std::string(name), GlCoreActiveUniform {type, static_cast<GLuint>(location)}}); active_uniforms.insert({std::string(name), GlCoreActiveUniform {type, static_cast<GLuint>(location)}});
} }
@ -1161,7 +1176,7 @@ void GlCoreRhi::end_graphics(rhi::Handle<rhi::GraphicsContext> handle)
graphics_context_generation_ += 1; graphics_context_generation_ += 1;
graphics_context_active_ = false; graphics_context_active_ = false;
gl_->Flush(); gl_->Flush();
GL_ASSERT GL_ASSERT;
} }
rhi::Handle<rhi::TransferContext> GlCoreRhi::begin_transfer() rhi::Handle<rhi::TransferContext> GlCoreRhi::begin_transfer()
@ -1200,11 +1215,11 @@ void GlCoreRhi::begin_default_render_pass(Handle<GraphicsContext> ctx, bool clea
const Rect fb_rect = platform_->get_default_framebuffer_dimensions(); const Rect fb_rect = platform_->get_default_framebuffer_dimensions();
gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
GL_ASSERT GL_ASSERT;
gl_->Disable(GL_SCISSOR_TEST); gl_->Disable(GL_SCISSOR_TEST);
GL_ASSERT GL_ASSERT;
gl_->Viewport(0, 0, fb_rect.w, fb_rect.h); gl_->Viewport(0, 0, fb_rect.w, fb_rect.h);
GL_ASSERT GL_ASSERT;
if (clear) if (clear)
{ {
@ -1212,7 +1227,7 @@ void GlCoreRhi::begin_default_render_pass(Handle<GraphicsContext> ctx, bool clea
gl_->ClearDepth(1.0f); gl_->ClearDepth(1.0f);
gl_->ClearStencil(0); gl_->ClearStencil(0);
gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL_ASSERT GL_ASSERT;
} }
current_render_pass_ = GlCoreRhi::DefaultRenderPassState {}; current_render_pass_ = GlCoreRhi::DefaultRenderPassState {};
@ -1225,65 +1240,73 @@ void GlCoreRhi::begin_render_pass(Handle<GraphicsContext> ctx, const RenderPassB
SRB2_ASSERT(render_pass_slab_.is_valid(info.render_pass) == true); SRB2_ASSERT(render_pass_slab_.is_valid(info.render_pass) == true);
auto& rp = render_pass_slab_[info.render_pass]; auto& rp = render_pass_slab_[info.render_pass];
SRB2_ASSERT(rp.desc.depth_format.has_value() == info.depth_attachment.has_value()); SRB2_ASSERT(rp.desc.use_depth_stencil == info.depth_stencil_attachment.has_value());
auto fb_itr = framebuffers_.find(GlCoreFramebufferKey {info.color_attachment, info.depth_attachment}); auto fb_itr = framebuffers_.find(GlCoreFramebufferKey {info.color_attachment, info.depth_stencil_attachment});
if (fb_itr == framebuffers_.end()) if (fb_itr == framebuffers_.end())
{ {
// Create a new framebuffer for this color-depth pair // Create a new framebuffer for this color-depth pair
GLuint fb_name; GLuint fb_name;
gl_->GenFramebuffers(1, &fb_name); gl_->GenFramebuffers(1, &fb_name);
GL_ASSERT GL_ASSERT;
gl_->BindFramebuffer(GL_FRAMEBUFFER, fb_name); gl_->BindFramebuffer(GL_FRAMEBUFFER, fb_name);
GL_ASSERT GL_ASSERT;
fb_itr = framebuffers_ fb_itr = framebuffers_
.insert( .insert(
{GlCoreFramebufferKey {info.color_attachment, info.depth_attachment}, {GlCoreFramebufferKey {info.color_attachment, info.depth_stencil_attachment},
static_cast<uint32_t>(fb_name)} static_cast<uint32_t>(fb_name)}
) )
.first; .first;
GLuint attachment = GL_COLOR_ATTACHMENT0; SRB2_ASSERT(texture_slab_.is_valid(info.color_attachment));
auto visitor = srb2::Overload { auto& texture = texture_slab_[info.color_attachment];
[&, this](const Handle<Texture>& handle) gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.texture, 0);
{ GL_ASSERT;
SRB2_ASSERT(texture_slab_.is_valid(handle));
auto& texture = texture_slab_[handle]; if (rp.desc.use_depth_stencil && info.depth_stencil_attachment.has_value())
gl_->FramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.texture, 0);
GL_ASSERT
},
[&, this](const Handle<Renderbuffer>& handle)
{
SRB2_ASSERT(renderbuffer_slab_.is_valid(handle));
auto& renderbuffer = renderbuffer_slab_[handle];
gl_->FramebufferRenderbuffer(
GL_FRAMEBUFFER,
attachment,
GL_RENDERBUFFER,
renderbuffer.renderbuffer
);
GL_ASSERT
}};
std::visit(visitor, info.color_attachment);
if (info.depth_attachment)
{ {
attachment = GL_DEPTH_ATTACHMENT; SRB2_ASSERT(renderbuffer_slab_.is_valid(*info.depth_stencil_attachment));
std::visit(visitor, *info.depth_attachment); auto& renderbuffer = renderbuffer_slab_[*info.depth_stencil_attachment];
gl_->FramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
renderbuffer.renderbuffer
);
GL_ASSERT;
} }
} }
auto& fb = *fb_itr; auto& fb = *fb_itr;
gl_->BindFramebuffer(GL_FRAMEBUFFER, fb.second); gl_->BindFramebuffer(GL_FRAMEBUFFER, fb.second);
GL_ASSERT GL_ASSERT;
gl_->Disable(GL_SCISSOR_TEST); gl_->Disable(GL_SCISSOR_TEST);
GL_ASSERT GL_ASSERT;
if (rp.desc.load_op == rhi::AttachmentLoadOp::kClear) GLint clear_bits = 0;
if (rp.desc.color_load_op == rhi::AttachmentLoadOp::kClear)
{ {
gl_->ClearColor(info.clear_color.r, info.clear_color.g, info.clear_color.b, info.clear_color.a); gl_->ClearColor(info.clear_color.r, info.clear_color.g, info.clear_color.b, info.clear_color.a);
gl_->ClearDepth(1.f); clear_bits |= GL_COLOR_BUFFER_BIT;
gl_->ClearStencil(0); }
gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GL_ASSERT if (rp.desc.use_depth_stencil)
{
if (rp.desc.depth_load_op == rhi::AttachmentLoadOp::kClear)
{
gl_->ClearDepth(1.f);
clear_bits |= GL_DEPTH_BUFFER_BIT;
}
if (rp.desc.stencil_load_op == rhi::AttachmentLoadOp::kClear)
{
gl_->ClearStencil(0);
clear_bits |= GL_STENCIL_BUFFER_BIT;
}
}
if (clear_bits != 0)
{
gl_->Clear(clear_bits);
GL_ASSERT;
} }
current_render_pass_ = info; current_render_pass_ = info;
@ -1308,44 +1331,98 @@ void GlCoreRhi::bind_pipeline(Handle<GraphicsContext> ctx, Handle<Pipeline> pipe
auto& desc = pl.desc; auto& desc = pl.desc;
gl_->UseProgram(pl.program); gl_->UseProgram(pl.program);
GL_ASSERT GL_ASSERT;
gl_->Disable(GL_SCISSOR_TEST); gl_->Disable(GL_SCISSOR_TEST);
GL_ASSERT GL_ASSERT;
if (desc.depth_attachment) if (desc.depth_stencil_state)
{ {
gl_->Enable(GL_DEPTH_TEST); if (desc.depth_stencil_state->depth_test)
GL_ASSERT {
GLenum depth_func = map_compare_func(desc.depth_attachment->func); gl_->Enable(GL_DEPTH_TEST);
SRB2_ASSERT(depth_func != GL_ZERO); GL_ASSERT;
gl_->DepthFunc(depth_func); GLenum depth_func = map_compare_func(desc.depth_stencil_state->depth_func);
GL_ASSERT SRB2_ASSERT(depth_func != GL_ZERO);
gl_->DepthMask(desc.depth_attachment->write ? GL_TRUE : GL_FALSE); gl_->DepthFunc(depth_func);
GL_ASSERT GL_ASSERT;
gl_->DepthMask(desc.depth_stencil_state->depth_write ? GL_TRUE : GL_FALSE);
GL_ASSERT;
}
else
{
gl_->Disable(GL_DEPTH_TEST);
GL_ASSERT;
}
if (desc.depth_stencil_state->depth_write)
{
gl_->DepthMask(GL_TRUE);
GL_ASSERT;
}
else
{
gl_->DepthMask(GL_FALSE);
GL_ASSERT;
}
if (desc.depth_stencil_state->stencil_test)
{
gl_->Enable(GL_STENCIL_TEST);
GL_ASSERT;
gl_->StencilFuncSeparate(
GL_FRONT,
map_compare_func(desc.depth_stencil_state->front.stencil_compare),
desc.depth_stencil_state->front.reference,
desc.depth_stencil_state->front.compare_mask
);
GL_ASSERT;
gl_->StencilFuncSeparate(
GL_BACK,
map_compare_func(desc.depth_stencil_state->back.stencil_compare),
desc.depth_stencil_state->back.reference,
desc.depth_stencil_state->back.compare_mask
);
GL_ASSERT;
gl_->StencilMaskSeparate(GL_FRONT, desc.depth_stencil_state->front.write_mask);
GL_ASSERT;
gl_->StencilMaskSeparate(GL_BACK, desc.depth_stencil_state->back.write_mask);
GL_ASSERT;
}
else
{
gl_->Disable(GL_STENCIL_TEST);
GL_ASSERT;
}
} }
else else
{ {
gl_->Disable(GL_DEPTH_TEST); gl_->Disable(GL_DEPTH_TEST);
GL_ASSERT GL_ASSERT;
gl_->Disable(GL_STENCIL_TEST);
GL_ASSERT;
gl_->StencilMask(0);
GL_ASSERT;
} }
if (desc.color_attachment.blend) if (desc.color_state.blend)
{ {
rhi::BlendDesc& bl = *desc.color_attachment.blend; rhi::BlendDesc& bl = *desc.color_state.blend;
gl_->Enable(GL_BLEND); gl_->Enable(GL_BLEND);
GL_ASSERT GL_ASSERT;
gl_->BlendFuncSeparate( gl_->BlendFuncSeparate(
map_blend_factor(bl.source_factor_color), map_blend_factor(bl.source_factor_color),
map_blend_factor(bl.dest_factor_color), map_blend_factor(bl.dest_factor_color),
map_blend_factor(bl.source_factor_alpha), map_blend_factor(bl.source_factor_alpha),
map_blend_factor(bl.dest_factor_alpha) map_blend_factor(bl.dest_factor_alpha)
); );
GL_ASSERT GL_ASSERT;
gl_->BlendEquationSeparate(map_blend_function(bl.color_function), map_blend_function(bl.alpha_function)); gl_->BlendEquationSeparate(map_blend_function(bl.color_function), map_blend_function(bl.alpha_function));
GL_ASSERT GL_ASSERT;
gl_->BlendColor(desc.blend_color.r, desc.blend_color.g, desc.blend_color.b, desc.blend_color.a); gl_->BlendColor(desc.blend_color.r, desc.blend_color.g, desc.blend_color.b, desc.blend_color.a);
GL_ASSERT GL_ASSERT;
} }
else else
{ {
@ -1353,28 +1430,28 @@ void GlCoreRhi::bind_pipeline(Handle<GraphicsContext> ctx, Handle<Pipeline> pipe
} }
gl_->ColorMask( gl_->ColorMask(
desc.color_attachment.color_mask.r ? GL_TRUE : GL_FALSE, desc.color_state.color_mask.r ? GL_TRUE : GL_FALSE,
desc.color_attachment.color_mask.g ? GL_TRUE : GL_FALSE, desc.color_state.color_mask.g ? GL_TRUE : GL_FALSE,
desc.color_attachment.color_mask.b ? GL_TRUE : GL_FALSE, desc.color_state.color_mask.b ? GL_TRUE : GL_FALSE,
desc.color_attachment.color_mask.a ? GL_TRUE : GL_FALSE desc.color_state.color_mask.a ? GL_TRUE : GL_FALSE
); );
GL_ASSERT GL_ASSERT;
GLenum cull_face = map_cull_mode(desc.cull); GLenum cull_face = map_cull_mode(desc.cull);
if (cull_face == GL_NONE) if (cull_face == GL_NONE)
{ {
gl_->Disable(GL_CULL_FACE); gl_->Disable(GL_CULL_FACE);
GL_ASSERT GL_ASSERT;
} }
else else
{ {
gl_->Enable(GL_CULL_FACE); gl_->Enable(GL_CULL_FACE);
GL_ASSERT GL_ASSERT;
gl_->CullFace(cull_face); gl_->CullFace(cull_face);
GL_ASSERT GL_ASSERT;
} }
gl_->FrontFace(map_winding(desc.winding)); gl_->FrontFace(map_winding(desc.winding));
GL_ASSERT GL_ASSERT;
current_pipeline_ = pipeline; current_pipeline_ = pipeline;
current_primitive_type_ = desc.primitive; current_primitive_type_ = desc.primitive;
@ -1419,57 +1496,57 @@ void GlCoreRhi::bind_uniform_set(Handle<GraphicsContext> ctx, uint32_t slot, Han
[&](const float& value) [&](const float& value)
{ {
gl_->Uniform1f(pipeline_uniform, value); gl_->Uniform1f(pipeline_uniform, value);
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::vec2& value) [&](const glm::vec2& value)
{ {
gl_->Uniform2f(pipeline_uniform, value.x, value.y); gl_->Uniform2f(pipeline_uniform, value.x, value.y);
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::vec3& value) [&](const glm::vec3& value)
{ {
gl_->Uniform3f(pipeline_uniform, value.x, value.y, value.z); gl_->Uniform3f(pipeline_uniform, value.x, value.y, value.z);
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::vec4& value) [&](const glm::vec4& value)
{ {
gl_->Uniform4f(pipeline_uniform, value.x, value.y, value.z, value.w); gl_->Uniform4f(pipeline_uniform, value.x, value.y, value.z, value.w);
GL_ASSERT GL_ASSERT;
}, },
[&](const int32_t& value) [&](const int32_t& value)
{ {
gl_->Uniform1i(pipeline_uniform, value); gl_->Uniform1i(pipeline_uniform, value);
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::ivec2& value) [&](const glm::ivec2& value)
{ {
gl_->Uniform2i(pipeline_uniform, value.x, value.y); gl_->Uniform2i(pipeline_uniform, value.x, value.y);
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::ivec3& value) [&](const glm::ivec3& value)
{ {
gl_->Uniform3i(pipeline_uniform, value.x, value.y, value.z); gl_->Uniform3i(pipeline_uniform, value.x, value.y, value.z);
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::ivec4& value) [&](const glm::ivec4& value)
{ {
gl_->Uniform4i(pipeline_uniform, value.x, value.y, value.z, value.w); gl_->Uniform4i(pipeline_uniform, value.x, value.y, value.z, value.w);
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::mat2& value) [&](const glm::mat2& value)
{ {
gl_->UniformMatrix2fv(pipeline_uniform, 1, false, glm::value_ptr(value)); gl_->UniformMatrix2fv(pipeline_uniform, 1, false, glm::value_ptr(value));
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::mat3& value) [&](const glm::mat3& value)
{ {
gl_->UniformMatrix3fv(pipeline_uniform, 1, false, glm::value_ptr(value)); gl_->UniformMatrix3fv(pipeline_uniform, 1, false, glm::value_ptr(value));
GL_ASSERT GL_ASSERT;
}, },
[&](const glm::mat4& value) [&](const glm::mat4& value)
{ {
gl_->UniformMatrix4fv(pipeline_uniform, 1, false, glm::value_ptr(value)); gl_->UniformMatrix4fv(pipeline_uniform, 1, false, glm::value_ptr(value));
GL_ASSERT GL_ASSERT;
}, },
}; };
std::visit(visitor, update_data); std::visit(visitor, update_data);
@ -1524,11 +1601,11 @@ void GlCoreRhi::bind_binding_set(Handle<GraphicsContext> ctx, Handle<BindingSet>
break; break;
} }
gl_->ActiveTexture(active_texture); gl_->ActiveTexture(active_texture);
GL_ASSERT GL_ASSERT;
gl_->BindTexture(GL_TEXTURE_2D, texture_gl_name); gl_->BindTexture(GL_TEXTURE_2D, texture_gl_name);
GL_ASSERT GL_ASSERT;
gl_->Uniform1i(sampler_uniform_loc, uniform_value); gl_->Uniform1i(sampler_uniform_loc, uniform_value);
GL_ASSERT GL_ASSERT;
} }
} }
@ -1571,7 +1648,7 @@ void GlCoreRhi::draw(Handle<GraphicsContext> ctx, uint32_t vertex_count, uint32_
SRB2_ASSERT(current_render_pass_.has_value() == true && current_pipeline_.has_value() == true); SRB2_ASSERT(current_render_pass_.has_value() == true && current_pipeline_.has_value() == true);
gl_->DrawArrays(map_primitive_mode(current_primitive_type_), first_vertex, vertex_count); gl_->DrawArrays(map_primitive_mode(current_primitive_type_), first_vertex, vertex_count);
GL_ASSERT GL_ASSERT;
} }
void GlCoreRhi::draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index) void GlCoreRhi::draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index)
@ -1592,7 +1669,7 @@ void GlCoreRhi::draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count,
GL_UNSIGNED_SHORT, GL_UNSIGNED_SHORT,
(const void*)((size_t)first_index * 2 + index_buffer_offset_) (const void*)((size_t)first_index * 2 + index_buffer_offset_)
); );
GL_ASSERT GL_ASSERT;
} }
void GlCoreRhi::read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out) void GlCoreRhi::read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out)
@ -1617,10 +1694,10 @@ void GlCoreRhi::finish()
for (auto it = binding_set_slab_.cbegin(); it != binding_set_slab_.cend(); it++) for (auto it = binding_set_slab_.cbegin(); it != binding_set_slab_.cend(); it++)
{ {
gl_->BindVertexArray(0); gl_->BindVertexArray(0);
GL_ASSERT GL_ASSERT;
GLuint vao = reinterpret_cast<const GlCoreBindingSet&>(*it).vao; GLuint vao = reinterpret_cast<const GlCoreBindingSet&>(*it).vao;
gl_->DeleteVertexArrays(1, &vao); gl_->DeleteVertexArrays(1, &vao);
GL_ASSERT GL_ASSERT;
} }
binding_set_slab_.clear(); binding_set_slab_.clear();
uniform_set_slab_.clear(); uniform_set_slab_.clear();
@ -1638,5 +1715,5 @@ void GlCoreRhi::finish()
} }
disposal_.clear(); disposal_.clear();
GL_ASSERT GL_ASSERT;
} }

View file

@ -25,10 +25,13 @@ namespace srb2::rhi
struct GlCoreFramebufferKey struct GlCoreFramebufferKey
{ {
TextureOrRenderbuffer color; Handle<Texture> color;
std::optional<TextureOrRenderbuffer> depth; std::optional<Handle<Renderbuffer>> depth_stencil;
bool operator==(const GlCoreFramebufferKey& rhs) const noexcept { return color == rhs.color && depth == rhs.depth; } bool operator==(const GlCoreFramebufferKey& rhs) const noexcept
{
return color == rhs.color && depth_stencil == rhs.depth_stencil;
}
bool operator!=(const GlCoreFramebufferKey& rhs) const noexcept { return !(*this == rhs); } bool operator!=(const GlCoreFramebufferKey& rhs) const noexcept { return !(*this == rhs); }
}; };
@ -43,24 +46,13 @@ struct std::hash<srb2::rhi::GlCoreFramebufferKey>
{ {
std::size_t operator()(const srb2::rhi::GlCoreFramebufferKey& key) const std::size_t operator()(const srb2::rhi::GlCoreFramebufferKey& key) const
{ {
struct GetHandleHashVisitor std::size_t color_hash = std::hash<const srb2::rhi::Handle<srb2::rhi::Texture>>()(key.color);
std::size_t depth_stencil_hash = 0;
if (key.depth_stencil)
{ {
uint32_t operator()(const srb2::rhi::Handle<srb2::rhi::Texture>& handle) const noexcept depth_stencil_hash = std::hash<const srb2::rhi::Handle<srb2::rhi::Renderbuffer>>()(*key.depth_stencil);
{
return std::hash<srb2::rhi::Handle<srb2::rhi::Texture>>()(handle);
}
uint32_t operator()(const srb2::rhi::Handle<srb2::rhi::Renderbuffer>& handle) const noexcept
{
return std::hash<srb2::rhi::Handle<srb2::rhi::Renderbuffer>>()(handle);
}
};
std::size_t color_hash = std::visit(GetHandleHashVisitor {}, key.color);
std::size_t depth_hash = 0;
if (key.depth)
{
depth_hash = std::visit(GetHandleHashVisitor {}, *key.depth);
} }
return color_hash ^ (depth_hash << 1); return color_hash ^ (depth_stencil_hash << 1);
} }
}; };

View file

@ -314,7 +314,7 @@ namespace std
{ {
template <typename T> template <typename T>
struct hash<srb2::rhi::Handle<T>> struct hash<const srb2::rhi::Handle<T>>
{ {
std::size_t operator()(const srb2::rhi::Handle<T>& e) const std::size_t operator()(const srb2::rhi::Handle<T>& e) const
{ {

View file

@ -34,6 +34,7 @@ struct Buffer
{ {
}; };
/// @brief Sampler image source or color image attachment.
struct Texture struct Texture
{ {
}; };
@ -46,12 +47,11 @@ struct RenderPass
{ {
}; };
/// @brief Depth-stencil image attachment.
struct Renderbuffer struct Renderbuffer
{ {
}; };
using TextureOrRenderbuffer = std::variant<Handle<Texture>, Handle<Renderbuffer>>;
enum class VertexAttributeFormat enum class VertexAttributeFormat
{ {
kFloat, kFloat,
@ -362,14 +362,40 @@ struct BlendDesc
BlendFunction alpha_function; BlendFunction alpha_function;
}; };
struct PipelineDepthAttachmentDesc enum class StencilOp
{ {
PixelFormat format; kKeep,
CompareFunc func; kZero,
bool write; kReplace,
kIncrementClamp,
kDecrementClamp,
kInvert,
kIncrementWrap,
kDecrementWrap
}; };
struct PipelineColorAttachmentDesc struct PipelineStencilOpStateDesc
{
StencilOp fail;
StencilOp pass;
StencilOp depth_fail;
CompareFunc stencil_compare;
uint32_t compare_mask;
uint32_t write_mask;
uint32_t reference;
};
struct PipelineDepthStencilStateDesc
{
bool depth_test;
bool depth_write;
CompareFunc depth_func;
bool stencil_test;
PipelineStencilOpStateDesc front;
PipelineStencilOpStateDesc back;
};
struct PipelineColorStateDesc
{ {
PixelFormat format; PixelFormat format;
std::optional<BlendDesc> blend; std::optional<BlendDesc> blend;
@ -382,9 +408,8 @@ struct PipelineDesc
VertexInputDesc vertex_input; VertexInputDesc vertex_input;
UniformInputDesc uniform_input; UniformInputDesc uniform_input;
SamplerInputDesc sampler_input; SamplerInputDesc sampler_input;
std::optional<PipelineDepthAttachmentDesc> depth_attachment; std::optional<PipelineDepthStencilStateDesc> depth_stencil_state;
// std::optional<StencilAttachmentDesc> stencil_attachment; PipelineColorStateDesc color_state;
PipelineColorAttachmentDesc color_attachment;
PrimitiveType primitive; PrimitiveType primitive;
CullMode cull; CullMode cull;
FaceWinding winding; FaceWinding winding;
@ -393,15 +418,17 @@ struct PipelineDesc
struct RenderPassDesc struct RenderPassDesc
{ {
std::optional<PixelFormat> depth_format; bool use_depth_stencil;
PixelFormat color_format; AttachmentLoadOp color_load_op;
AttachmentLoadOp load_op; AttachmentStoreOp color_store_op;
AttachmentStoreOp store_op; AttachmentLoadOp depth_load_op;
AttachmentStoreOp depth_store_op;
AttachmentLoadOp stencil_load_op;
AttachmentStoreOp stencil_store_op;
}; };
struct RenderbufferDesc struct RenderbufferDesc
{ {
PixelFormat format;
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
}; };
@ -423,8 +450,8 @@ struct BufferDesc
struct RenderPassBeginInfo struct RenderPassBeginInfo
{ {
Handle<RenderPass> render_pass; Handle<RenderPass> render_pass;
TextureOrRenderbuffer color_attachment; Handle<Texture> color_attachment;
std::optional<TextureOrRenderbuffer> depth_attachment; std::optional<Handle<Renderbuffer>> depth_stencil_attachment;
glm::vec4 clear_color; glm::vec4 clear_color;
}; };