diff --git a/src/hwr2/pass_blit_rect.cpp b/src/hwr2/pass_blit_rect.cpp index 5ff82b7f7..38f0cf5cf 100644 --- a/src/hwr2/pass_blit_rect.cpp +++ b/src/hwr2/pass_blit_rect.cpp @@ -47,7 +47,7 @@ static const PipelineDesc kPalettedPipelineDescription = { // 256x1 palette texture SamplerName::kSampler1}}, std::nullopt, - {PixelFormat::kRGBA8, std::nullopt, {true, true, true, true}}, + {std::nullopt, {true, true, true, true}}, PrimitiveType::kTriangles, CullMode::kNone, FaceWinding::kCounterClockwise, @@ -61,7 +61,7 @@ static const PipelineDesc kUnshadedPipelineDescription = { {{// RGB/A texture SamplerName::kSampler0}}, std::nullopt, - {PixelFormat::kRGBA8, std::nullopt, {true, true, true, true}}, + {std::nullopt, {true, true, true, true}}, PrimitiveType::kTriangles, CullMode::kNone, FaceWinding::kCounterClockwise, @@ -111,10 +111,15 @@ void BlitRectPass::prepass(Rhi& rhi) if (!render_pass_) { render_pass_ = rhi.create_render_pass( - {std::nullopt, - PixelFormat::kRGBA8, - output_clear_ ? AttachmentLoadOp::kClear : AttachmentLoadOp::kLoad, - AttachmentStoreOp::kStore} + { + false, + output_clear_ ? AttachmentLoadOp::kClear : AttachmentLoadOp::kLoad, + AttachmentStoreOp::kStore, + AttachmentLoadOp::kDontCare, + AttachmentStoreOp::kDontCare, + AttachmentLoadOp::kDontCare, + AttachmentStoreOp::kDontCare + } ); } } @@ -160,7 +165,7 @@ void BlitRectPass::transfer(Rhi& rhi, Handle ctx) glm::mat3( glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, output_flip_ ? -1.f : 1.f, 0.f), - glm::vec3(0.f, 0.f, 1.f) + glm::vec3(0.f, output_flip_ ? 1.f : 0.f, 1.f) ) }; diff --git a/src/hwr2/pass_imgui.cpp b/src/hwr2/pass_imgui.cpp index afa62a882..3707a4a3d 100644 --- a/src/hwr2/pass_imgui.cpp +++ b/src/hwr2/pass_imgui.cpp @@ -25,9 +25,8 @@ static const PipelineDesc kPipelineDesc = { {VertexAttributeName::kColor, 0, 24}}}, {{{{UniformName::kProjection}}, {{UniformName::kModelView, UniformName::kTexCoord0Transform}}}}, {{SamplerName::kSampler0}}, - PipelineDepthAttachmentDesc {PixelFormat::kDepth16, CompareFunc::kAlways, true}, - {PixelFormat::kRGBA8, - BlendDesc { + PipelineDepthStencilStateDesc {true, true, CompareFunc::kAlways, false, {}, {}}, + {BlendDesc { BlendFactor::kSourceAlpha, BlendFactor::kOneMinusSourceAlpha, BlendFunction::kAdd, @@ -65,7 +64,13 @@ void ImguiPass::prepass(Rhi& rhi) uint32_t uwidth = static_cast(width); uint32_t uheight = static_cast(height); - font_atlas_ = rhi.create_texture({TextureFormat::kRGBA, uwidth, uheight}); + font_atlas_ = rhi.create_texture({ + TextureFormat::kRGBA, + uwidth, + uheight, + TextureWrapMode::kRepeat, + TextureWrapMode::kRepeat + }); io.Fonts->SetTexID(font_atlas_); } diff --git a/src/hwr2/pass_postprocess.cpp b/src/hwr2/pass_postprocess.cpp index e75ff2243..a35dea645 100644 --- a/src/hwr2/pass_postprocess.cpp +++ b/src/hwr2/pass_postprocess.cpp @@ -50,7 +50,7 @@ static const PipelineDesc kWipePipelineDesc = { {{{{UniformName::kProjection, UniformName::kWipeColorizeMode, UniformName::kWipeEncoreSwizzle}}}}, {{SamplerName::kSampler0, SamplerName::kSampler1, SamplerName::kSampler2}}, std::nullopt, - {PixelFormat::kRGBA8, std::nullopt, {true, true, true, true}}, + {std::nullopt, {true, true, true, true}}, PrimitiveType::kTriangles, CullMode::kNone, FaceWinding::kCounterClockwise, @@ -67,7 +67,15 @@ void PostprocessWipePass::prepass(Rhi& rhi) if (!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 + } ); } @@ -158,7 +166,13 @@ void PostprocessWipePass::prepass(Rhi& rhi) } } - wipe_tex_ = rhi.create_texture({TextureFormat::kLuminance, mask_w_, mask_h_}); + wipe_tex_ = rhi.create_texture({ + TextureFormat::kLuminance, + mask_w_, + mask_h_, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } void PostprocessWipePass::transfer(Rhi& rhi, Handle ctx) diff --git a/src/hwr2/pass_resource_managers.cpp b/src/hwr2/pass_resource_managers.cpp index fb38dcdf4..58ea993eb 100644 --- a/src/hwr2/pass_resource_managers.cpp +++ b/src/hwr2/pass_resource_managers.cpp @@ -71,29 +71,59 @@ void FramebufferManager::prepass(Rhi& rhi) // Recreate the framebuffer textures if (main_color_ == kNullHandle) { - main_color_ = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height}); + main_color_ = rhi.create_texture({ + TextureFormat::kRGBA, + current_width, + current_height, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } 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) { - post_colors_[0] = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height}); + post_colors_[0] = rhi.create_texture({ + TextureFormat::kRGBA, + current_width, + current_height, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } if (post_colors_[1] == kNullHandle) { - post_colors_[1] = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height}); + post_colors_[1] = rhi.create_texture({ + TextureFormat::kRGBA, + current_width, + current_height, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } if (wipe_start_color_ == kNullHandle) { - wipe_start_color_ = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height}); + wipe_start_color_ = rhi.create_texture({ + TextureFormat::kRGBA, + current_width, + current_height, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } if (wipe_end_color_ == kNullHandle) { - wipe_end_color_ = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height}); + wipe_end_color_ = rhi.create_texture({ + TextureFormat::kRGBA, + current_width, + current_height, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } } @@ -119,7 +149,7 @@ void MainPaletteManager::prepass(Rhi& rhi) { if (!palette_) { - palette_ = rhi.create_texture({TextureFormat::kRGBA, 256, 1}); + palette_ = rhi.create_texture({TextureFormat::kRGBA, 256, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); } } @@ -148,9 +178,15 @@ void CommonResourcesManager::prepass(Rhi& rhi) { if (!init_) { - black_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1}); - white_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1}); - transparent_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1}); + black_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + white_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + transparent_ = rhi.create_texture({ + TextureFormat::kRGBA, + 1, + 1, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } } @@ -266,7 +302,13 @@ Handle FlatTextureManager::find_or_create_indexed(Rhi& rhi, lumpnum_t l } uint32_t flat_size = get_flat_size(lump); - Handle new_tex = rhi.create_texture({TextureFormat::kLuminanceAlpha, flat_size, flat_size}); + Handle new_tex = rhi.create_texture({ + TextureFormat::kLuminanceAlpha, + flat_size, + flat_size, + TextureWrapMode::kRepeat, + TextureWrapMode::kRepeat + }); flats_.insert({lump, new_tex}); to_upload_.push_back(lump); return new_tex; diff --git a/src/hwr2/pass_screenshot.cpp b/src/hwr2/pass_screenshot.cpp index 64ed1e4be..059b07c85 100644 --- a/src/hwr2/pass_screenshot.cpp +++ b/src/hwr2/pass_screenshot.cpp @@ -26,10 +26,13 @@ void ScreenshotPass::prepass(Rhi& rhi) { render_pass_ = rhi.create_render_pass( { - std::nullopt, - PixelFormat::kRGBA8, + false, AttachmentLoadOp::kLoad, - AttachmentStoreOp::kStore + AttachmentStoreOp::kStore, + AttachmentLoadOp::kDontCare, + AttachmentStoreOp::kDontCare, + AttachmentLoadOp::kDontCare, + AttachmentStoreOp::kDontCare } ); } diff --git a/src/hwr2/pass_software.cpp b/src/hwr2/pass_software.cpp index bee9a2234..0a514cd9b 100644 --- a/src/hwr2/pass_software.cpp +++ b/src/hwr2/pass_software.cpp @@ -46,7 +46,13 @@ void SoftwarePass::prepass(Rhi& rhi) if (!screen_texture_) { - screen_texture_ = rhi.create_texture({TextureFormat::kLuminance, width_, height_}); + screen_texture_ = rhi.create_texture({ + TextureFormat::kLuminance, + width_, + height_, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); } // If the screen width won't fit the unpack alignment, we need to copy the screen. diff --git a/src/hwr2/pass_twodee.cpp b/src/hwr2/pass_twodee.cpp index 02a3cac30..8b0f22b71 100644 --- a/src/hwr2/pass_twodee.cpp +++ b/src/hwr2/pass_twodee.cpp @@ -88,7 +88,13 @@ static Rect trimmed_patch_dim(const patch_t* patch); static void create_atlas(Rhi& rhi, TwodeePassData& pass_data) { Atlas new_atlas; - new_atlas.tex = rhi.create_texture({TextureFormat::kLuminanceAlpha, 2048, 2048}); + new_atlas.tex = rhi.create_texture({ + TextureFormat::kLuminanceAlpha, + 2048, + 2048, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); new_atlas.tex_width = 2048; new_atlas.tex_height = 2048; new_atlas.rp_ctx = std::make_unique(); @@ -345,7 +351,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key) {{UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kSampler0IsIndexedAlpha}}}}, {{SamplerName::kSampler0, SamplerName::kSampler1, SamplerName::kSampler2}}, std::nullopt, - {PixelFormat::kRGBA8, blend_desc, {true, true, true, true}}, + {blend_desc, {true, true, true, true}}, key.lines ? PrimitiveType::kLines : PrimitiveType::kTriangles, CullMode::kNone, FaceWinding::kCounterClockwise, @@ -501,18 +507,38 @@ void TwodeePass::prepass(Rhi& rhi) if (!data_->default_tex) { - data_->default_tex = rhi.create_texture({TextureFormat::kLuminanceAlpha, 2, 1}); + data_->default_tex = rhi.create_texture({ + TextureFormat::kLuminanceAlpha, + 2, + 1, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); data_->upload_default_tex = true; } if (!data_->default_colormap_tex) { - data_->default_colormap_tex = rhi.create_texture({TextureFormat::kLuminance, 256, 1}); + data_->default_colormap_tex = rhi.create_texture({ + TextureFormat::kLuminance, + 256, + 1, + TextureWrapMode::kClamp, + TextureWrapMode::kClamp + }); data_->upload_default_tex = true; } if (!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 + } ); } diff --git a/src/rhi/gl3_core/gl3_core_rhi.cpp b/src/rhi/gl3_core/gl3_core_rhi.cpp index 17c7db784..5e82010ac 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.cpp +++ b/src/rhi/gl3_core/gl3_core_rhi.cpp @@ -110,6 +110,21 @@ constexpr GLenum map_texture_format(rhi::TextureFormat format) } } +constexpr GLenum map_texture_wrap(rhi::TextureWrapMode wrap) +{ + switch (wrap) + { + case rhi::TextureWrapMode::kClamp: + return GL_CLAMP_TO_EDGE; + case rhi::TextureWrapMode::kRepeat: + return GL_REPEAT; + case rhi::TextureWrapMode::kMirroredRepeat: + return GL_MIRRORED_REPEAT; + default: + return GL_NEAREST; + } +} + constexpr GLenum map_internal_texture_format(rhi::TextureFormat format) { switch (format) @@ -122,8 +137,6 @@ constexpr GLenum map_internal_texture_format(rhi::TextureFormat format) return GL_R8; case rhi::TextureFormat::kLuminanceAlpha: return GL_RG8; - case rhi::TextureFormat::kDepth: - return GL_DEPTH_COMPONENT24; default: return GL_ZERO; } @@ -519,10 +532,6 @@ rhi::Handle GlCoreRhi::create_texture(const rhi::TextureDesc& desc GLenum internal_format = map_internal_texture_format(desc.format); SRB2_ASSERT(internal_format != GL_ZERO); GLenum format = GL_RGBA; - if (desc.format == TextureFormat::kDepth) - { - format = GL_DEPTH_COMPONENT; - } GLuint name = 0; gl_->GenTextures(1, &name); @@ -530,15 +539,15 @@ rhi::Handle GlCoreRhi::create_texture(const rhi::TextureDesc& desc gl_->BindTexture(GL_TEXTURE_2D, name); 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_ASSERT - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - GL_ASSERT - gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - GL_ASSERT + GL_ASSERT; + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, map_texture_wrap(desc.u_wrap)); + GL_ASSERT; + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, map_texture_wrap(desc.v_wrap)); + GL_ASSERT; gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.width, desc.height, 0, format, GL_UNSIGNED_BYTE, nullptr); - GL_ASSERT + GL_ASSERT; GlCoreTexture texture; texture.texture = name; @@ -592,9 +601,9 @@ void GlCoreRhi::update_texture( SRB2_ASSERT(region.x + region.w <= t.desc.width && region.y + region.h <= t.desc.height); gl_->ActiveTexture(GL_TEXTURE0); - GL_ASSERT + GL_ASSERT; gl_->BindTexture(GL_TEXTURE_2D, t.texture); - GL_ASSERT + GL_ASSERT; gl_->TexSubImage2D( GL_TEXTURE_2D, 0, @@ -606,7 +615,7 @@ void GlCoreRhi::update_texture( type, reinterpret_cast(data.data()) ); - GL_ASSERT + GL_ASSERT; } rhi::Handle GlCoreRhi::create_buffer(const rhi::BufferDesc& desc) @@ -621,13 +630,13 @@ rhi::Handle GlCoreRhi::create_buffer(const rhi::BufferDesc& desc) GLuint name = 0; gl_->GenBuffers(1, &name); - GL_ASSERT + GL_ASSERT; gl_->BindBuffer(target, name); - GL_ASSERT + GL_ASSERT; gl_->BufferData(target, desc.size, nullptr, usage); - GL_ASSERT + GL_ASSERT; GlCoreBuffer buffer; buffer.buffer = name; @@ -680,9 +689,9 @@ void GlCoreRhi::update_buffer( } gl_->BindBuffer(target, b.buffer); - GL_ASSERT + GL_ASSERT; gl_->BufferSubData(target, offset, data.size(), data.data()); - GL_ASSERT + GL_ASSERT; } rhi::Handle @@ -721,9 +730,9 @@ rhi::Handle GlCoreRhi::create_binding_set( GLuint vao = 0; gl_->GenVertexArrays(1, &vao); - GL_ASSERT + GL_ASSERT; gl_->BindVertexArray(vao); - GL_ASSERT + GL_ASSERT; for (auto& attr_layout : pl.desc.vertex_input.attr_layouts) { @@ -734,7 +743,7 @@ rhi::Handle GlCoreRhi::create_binding_set( auto& buffer_layout = pl.desc.vertex_input.buffer_layouts[attr_layout.buffer_index]; gl_->BindBuffer(GL_ARRAY_BUFFER, buf.buffer); - GL_ASSERT + GL_ASSERT; GLuint attrib_location = pl.attrib_locations[attr_layout.name]; VertexAttributeFormat vert_attr_format = rhi::vertex_attribute_format(attr_layout.name); @@ -744,7 +753,7 @@ rhi::Handle GlCoreRhi::create_binding_set( SRB2_ASSERT(vertex_attr_size != 0); uint32_t vertex_buffer_offset = 0; // TODO allow binding set to specify gl_->EnableVertexAttribArray(pl.attrib_locations[attr_layout.name]); - GL_ASSERT + GL_ASSERT; gl_->VertexAttribPointer( attrib_location, vertex_attr_size, @@ -753,7 +762,7 @@ rhi::Handle GlCoreRhi::create_binding_set( buffer_layout.stride, reinterpret_cast(vertex_buffer_offset + attr_layout.offset) ); - GL_ASSERT + GL_ASSERT; } binding_set.vao = vao; @@ -782,9 +791,24 @@ rhi::Handle GlCoreRhi::create_renderbuffer(const rhi::Renderb // Obtain storage up-front. gl_->BindRenderbuffer(GL_RENDERBUFFER, name); - GL_ASSERT - gl_->RenderbufferStorage(GL_RENDERBUFFER, map_pixel_format(desc.format), desc.width, desc.height); - GL_ASSERT + 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; rb.renderbuffer = name; @@ -1000,9 +1024,9 @@ rhi::Handle GlCoreRhi::create_pipeline(const PipelineDesc& desc) GLenum type = GL_ZERO; char name[256]; gl_->GetActiveAttrib(program, i, 255, &name_len, &size, &type, name); - GL_ASSERT + GL_ASSERT; GLint location = gl_->GetAttribLocation(program, name); - GL_ASSERT + GL_ASSERT; active_attributes.insert({std::string(name), GlCoreActiveUniform {type, static_cast(location)}}); } @@ -1042,9 +1066,9 @@ rhi::Handle GlCoreRhi::create_pipeline(const PipelineDesc& desc) GLenum type = GL_ZERO; char name[256]; gl_->GetActiveUniform(program, i, 255, &name_len, &size, &type, name); - GL_ASSERT + GL_ASSERT; GLint location = gl_->GetUniformLocation(program, name); - GL_ASSERT + GL_ASSERT; active_uniforms.insert({std::string(name), GlCoreActiveUniform {type, static_cast(location)}}); } @@ -1167,7 +1191,7 @@ void GlCoreRhi::end_graphics(rhi::Handle handle) graphics_context_generation_ += 1; graphics_context_active_ = false; gl_->Flush(); - GL_ASSERT + GL_ASSERT; } rhi::Handle GlCoreRhi::begin_transfer() @@ -1206,11 +1230,11 @@ void GlCoreRhi::begin_default_render_pass(Handle ctx, bool clea const Rect fb_rect = platform_->get_default_framebuffer_dimensions(); gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); - GL_ASSERT + GL_ASSERT; gl_->Disable(GL_SCISSOR_TEST); - GL_ASSERT + GL_ASSERT; gl_->Viewport(0, 0, fb_rect.w, fb_rect.h); - GL_ASSERT + GL_ASSERT; if (clear) { @@ -1218,7 +1242,7 @@ void GlCoreRhi::begin_default_render_pass(Handle ctx, bool clea gl_->ClearDepth(1.0f); gl_->ClearStencil(0); gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GL_ASSERT + GL_ASSERT; } current_render_pass_ = GlCoreRhi::DefaultRenderPassState {}; @@ -1231,65 +1255,74 @@ void GlCoreRhi::begin_render_pass(Handle ctx, const RenderPassB SRB2_ASSERT(render_pass_slab_.is_valid(info.render_pass) == true); 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()) { // Create a new framebuffer for this color-depth pair GLuint fb_name; gl_->GenFramebuffers(1, &fb_name); - GL_ASSERT + GL_ASSERT; gl_->BindFramebuffer(GL_FRAMEBUFFER, fb_name); - GL_ASSERT + GL_ASSERT; fb_itr = framebuffers_ .insert( - {GlCoreFramebufferKey {info.color_attachment, info.depth_attachment}, + {GlCoreFramebufferKey {info.color_attachment, info.depth_stencil_attachment}, static_cast(fb_name)} ) .first; - GLuint attachment = GL_COLOR_ATTACHMENT0; - auto visitor = srb2::Overload { - [&, this](const Handle& handle) - { - SRB2_ASSERT(texture_slab_.is_valid(handle)); - auto& texture = texture_slab_[handle]; - gl_->FramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.texture, 0); - GL_ASSERT - }, - [&, this](const Handle& 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) + SRB2_ASSERT(texture_slab_.is_valid(info.color_attachment)); + auto& texture = texture_slab_[info.color_attachment]; + SRB2_ASSERT(texture.desc.format == TextureFormat::kRGBA); + gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.texture, 0); + GL_ASSERT; + + if (rp.desc.use_depth_stencil && info.depth_stencil_attachment.has_value()) { - attachment = GL_DEPTH_ATTACHMENT; - std::visit(visitor, *info.depth_attachment); + SRB2_ASSERT(renderbuffer_slab_.is_valid(*info.depth_stencil_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; gl_->BindFramebuffer(GL_FRAMEBUFFER, fb.second); - GL_ASSERT + GL_ASSERT; 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_->ClearDepth(1.f); - gl_->ClearStencil(0); - gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - GL_ASSERT + clear_bits |= GL_COLOR_BUFFER_BIT; + } + + 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; @@ -1314,44 +1347,98 @@ void GlCoreRhi::bind_pipeline(Handle ctx, Handle pipe auto& desc = pl.desc; gl_->UseProgram(pl.program); - GL_ASSERT + GL_ASSERT; gl_->Disable(GL_SCISSOR_TEST); - GL_ASSERT + GL_ASSERT; - if (desc.depth_attachment) + if (desc.depth_stencil_state) { - gl_->Enable(GL_DEPTH_TEST); - GL_ASSERT - GLenum depth_func = map_compare_func(desc.depth_attachment->func); - SRB2_ASSERT(depth_func != GL_ZERO); - gl_->DepthFunc(depth_func); - GL_ASSERT - gl_->DepthMask(desc.depth_attachment->write ? GL_TRUE : GL_FALSE); - GL_ASSERT + if (desc.depth_stencil_state->depth_test) + { + gl_->Enable(GL_DEPTH_TEST); + GL_ASSERT; + GLenum depth_func = map_compare_func(desc.depth_stencil_state->depth_func); + SRB2_ASSERT(depth_func != GL_ZERO); + gl_->DepthFunc(depth_func); + 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 { 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_ASSERT + GL_ASSERT; gl_->BlendFuncSeparate( map_blend_factor(bl.source_factor_color), map_blend_factor(bl.dest_factor_color), map_blend_factor(bl.source_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_ASSERT + GL_ASSERT; gl_->BlendColor(desc.blend_color.r, desc.blend_color.g, desc.blend_color.b, desc.blend_color.a); - GL_ASSERT + GL_ASSERT; } else { @@ -1359,28 +1446,28 @@ void GlCoreRhi::bind_pipeline(Handle ctx, Handle pipe } gl_->ColorMask( - desc.color_attachment.color_mask.r ? GL_TRUE : GL_FALSE, - desc.color_attachment.color_mask.g ? GL_TRUE : GL_FALSE, - desc.color_attachment.color_mask.b ? GL_TRUE : GL_FALSE, - desc.color_attachment.color_mask.a ? GL_TRUE : GL_FALSE + desc.color_state.color_mask.r ? GL_TRUE : GL_FALSE, + desc.color_state.color_mask.g ? GL_TRUE : GL_FALSE, + desc.color_state.color_mask.b ? 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); if (cull_face == GL_NONE) { gl_->Disable(GL_CULL_FACE); - GL_ASSERT + GL_ASSERT; } else { gl_->Enable(GL_CULL_FACE); - GL_ASSERT + GL_ASSERT; gl_->CullFace(cull_face); - GL_ASSERT + GL_ASSERT; } gl_->FrontFace(map_winding(desc.winding)); - GL_ASSERT + GL_ASSERT; current_pipeline_ = pipeline; current_primitive_type_ = desc.primitive; @@ -1425,57 +1512,57 @@ void GlCoreRhi::bind_uniform_set(Handle ctx, uint32_t slot, Han [&](const float& value) { gl_->Uniform1f(pipeline_uniform, value); - GL_ASSERT + GL_ASSERT; }, [&](const glm::vec2& value) { gl_->Uniform2f(pipeline_uniform, value.x, value.y); - GL_ASSERT + GL_ASSERT; }, [&](const glm::vec3& value) { gl_->Uniform3f(pipeline_uniform, value.x, value.y, value.z); - GL_ASSERT + GL_ASSERT; }, [&](const glm::vec4& value) { gl_->Uniform4f(pipeline_uniform, value.x, value.y, value.z, value.w); - GL_ASSERT + GL_ASSERT; }, [&](const int32_t& value) { gl_->Uniform1i(pipeline_uniform, value); - GL_ASSERT + GL_ASSERT; }, [&](const glm::ivec2& value) { gl_->Uniform2i(pipeline_uniform, value.x, value.y); - GL_ASSERT + GL_ASSERT; }, [&](const glm::ivec3& value) { gl_->Uniform3i(pipeline_uniform, value.x, value.y, value.z); - GL_ASSERT + GL_ASSERT; }, [&](const glm::ivec4& value) { gl_->Uniform4i(pipeline_uniform, value.x, value.y, value.z, value.w); - GL_ASSERT + GL_ASSERT; }, [&](const glm::mat2& value) { gl_->UniformMatrix2fv(pipeline_uniform, 1, false, glm::value_ptr(value)); - GL_ASSERT + GL_ASSERT; }, [&](const glm::mat3& value) { gl_->UniformMatrix3fv(pipeline_uniform, 1, false, glm::value_ptr(value)); - GL_ASSERT + GL_ASSERT; }, [&](const glm::mat4& value) { gl_->UniformMatrix4fv(pipeline_uniform, 1, false, glm::value_ptr(value)); - GL_ASSERT + GL_ASSERT; }, }; std::visit(visitor, update_data); @@ -1530,11 +1617,11 @@ void GlCoreRhi::bind_binding_set(Handle ctx, Handle break; } gl_->ActiveTexture(active_texture); - GL_ASSERT + GL_ASSERT; gl_->BindTexture(GL_TEXTURE_2D, texture_gl_name); - GL_ASSERT + GL_ASSERT; gl_->Uniform1i(sampler_uniform_loc, uniform_value); - GL_ASSERT + GL_ASSERT; } } @@ -1577,7 +1664,7 @@ void GlCoreRhi::draw(Handle ctx, uint32_t vertex_count, uint32_ 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_ASSERT + GL_ASSERT; } void GlCoreRhi::draw_indexed(Handle ctx, uint32_t index_count, uint32_t first_index) @@ -1598,7 +1685,7 @@ void GlCoreRhi::draw_indexed(Handle ctx, uint32_t index_count, GL_UNSIGNED_SHORT, (const void*)((size_t)first_index * 2 + index_buffer_offset_) ); - GL_ASSERT + GL_ASSERT; } void GlCoreRhi::read_pixels(Handle ctx, const Rect& rect, PixelFormat format, tcb::span out) @@ -1623,10 +1710,10 @@ void GlCoreRhi::finish() for (auto it = binding_set_slab_.cbegin(); it != binding_set_slab_.cend(); it++) { gl_->BindVertexArray(0); - GL_ASSERT + GL_ASSERT; GLuint vao = reinterpret_cast(*it).vao; gl_->DeleteVertexArrays(1, &vao); - GL_ASSERT + GL_ASSERT; } binding_set_slab_.clear(); uniform_set_slab_.clear(); @@ -1644,5 +1731,5 @@ void GlCoreRhi::finish() } disposal_.clear(); - GL_ASSERT + GL_ASSERT; } diff --git a/src/rhi/gl3_core/gl3_core_rhi.hpp b/src/rhi/gl3_core/gl3_core_rhi.hpp index 200fa1456..b431c3771 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.hpp +++ b/src/rhi/gl3_core/gl3_core_rhi.hpp @@ -25,10 +25,13 @@ namespace srb2::rhi struct GlCoreFramebufferKey { - TextureOrRenderbuffer color; - std::optional depth; + Handle color; + std::optional> 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); } }; @@ -43,24 +46,13 @@ struct std::hash { std::size_t operator()(const srb2::rhi::GlCoreFramebufferKey& key) const { - struct GetHandleHashVisitor + std::size_t color_hash = std::hash>()(key.color); + std::size_t depth_stencil_hash = 0; + if (key.depth_stencil) { - uint32_t operator()(const srb2::rhi::Handle& handle) const noexcept - { - return std::hash>()(handle); - } - uint32_t operator()(const srb2::rhi::Handle& handle) const noexcept - { - return std::hash>()(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); + depth_stencil_hash = std::hash>()(*key.depth_stencil); } - return color_hash ^ (depth_hash << 1); + return color_hash ^ (depth_stencil_hash << 1); } }; diff --git a/src/rhi/handle.hpp b/src/rhi/handle.hpp index 282a924da..df160c564 100644 --- a/src/rhi/handle.hpp +++ b/src/rhi/handle.hpp @@ -314,7 +314,7 @@ namespace std { template -struct hash> +struct hash> { std::size_t operator()(const srb2::rhi::Handle& e) const { diff --git a/src/rhi/rhi.hpp b/src/rhi/rhi.hpp index a23fe5a72..fd4669742 100644 --- a/src/rhi/rhi.hpp +++ b/src/rhi/rhi.hpp @@ -34,6 +34,7 @@ struct Buffer { }; +/// @brief Sampler image source or color image attachment. struct Texture { }; @@ -46,12 +47,11 @@ struct RenderPass { }; +/// @brief Depth-stencil image attachment. struct Renderbuffer { }; -using TextureOrRenderbuffer = std::variant, Handle>; - enum class VertexAttributeFormat { kFloat, @@ -90,8 +90,7 @@ enum class TextureFormat kLuminance, kLuminanceAlpha, kRGB, - kRGBA, - kDepth + kRGBA }; enum class CompareFunc @@ -363,16 +362,41 @@ struct BlendDesc BlendFunction alpha_function; }; -struct PipelineDepthAttachmentDesc +enum class StencilOp { - PixelFormat format; - CompareFunc func; - bool write; + kKeep, + kZero, + 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; std::optional blend; ColorMask color_mask; }; @@ -383,9 +407,8 @@ struct PipelineDesc VertexInputDesc vertex_input; UniformInputDesc uniform_input; SamplerInputDesc sampler_input; - std::optional depth_attachment; - // std::optional stencil_attachment; - PipelineColorAttachmentDesc color_attachment; + std::optional depth_stencil_state; + PipelineColorStateDesc color_state; PrimitiveType primitive; CullMode cull; FaceWinding winding; @@ -394,24 +417,35 @@ struct PipelineDesc struct RenderPassDesc { - std::optional depth_format; - PixelFormat color_format; - AttachmentLoadOp load_op; - AttachmentStoreOp store_op; + bool use_depth_stencil; + AttachmentLoadOp color_load_op; + AttachmentStoreOp color_store_op; + AttachmentLoadOp depth_load_op; + AttachmentStoreOp depth_store_op; + AttachmentLoadOp stencil_load_op; + AttachmentStoreOp stencil_store_op; }; struct RenderbufferDesc { - PixelFormat format; uint32_t width; uint32_t height; }; +enum class TextureWrapMode +{ + kRepeat, + kMirroredRepeat, + kClamp +}; + struct TextureDesc { TextureFormat format; uint32_t width; uint32_t height; + TextureWrapMode u_wrap; + TextureWrapMode v_wrap; }; struct BufferDesc @@ -424,8 +458,8 @@ struct BufferDesc struct RenderPassBeginInfo { Handle render_pass; - TextureOrRenderbuffer color_attachment; - std::optional depth_attachment; + Handle color_attachment; + std::optional> depth_stencil_attachment; glm::vec4 clear_color; };