From 6763c13f88684ac210966eb22d13e6490ab20700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 27 Nov 2024 01:13:59 +0100 Subject: [PATCH] ImGui: Finish implementing pipeline switching for all backends --- Common/GPU/D3D11/thin3d_d3d11.cpp | 14 +- Common/GPU/D3D9/thin3d_d3d9.cpp | 10 +- Common/GPU/OpenGL/thin3d_gl.cpp | 12 +- Common/GPU/Vulkan/thin3d_vulkan.cpp | 11 +- Common/GPU/thin3d.h | 3 +- GPU/Common/FramebufferManagerCommon.cpp | 7 +- ext/imgui/imgui_impl_thin3d.cpp | 181 +++++++++++------------- ext/imgui/imgui_impl_thin3d.h | 21 +-- 8 files changed, 143 insertions(+), 116 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 1baa6512be9e..a911fa80ac95 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -164,7 +164,7 @@ class D3D11DrawContext : public DrawContext { void DrawIndexed(int indexCount, int offset) override; void DrawUP(const void *vdata, int vertexCount) override; void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override; - void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) override; + void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *ub, size_t ubSize) override; void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override; @@ -1407,7 +1407,13 @@ void D3D11DrawContext::DrawIndexedUP(const void *vdata, int vertexCount, const v DrawIndexed(indexCount, 0); } -void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) { +void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *ub, size_t ubSize) { + if (draws.is_empty() || !vertexCount || !indexCount) { + return; + } + + curPipeline_ = (D3D11Pipeline *)draws[0].pipeline; + int vbyteSize = vertexCount * curPipeline_->input->stride; int ibyteSize = indexCount * sizeof(u16); @@ -1417,12 +1423,14 @@ void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCo UpdateBuffer(upIBuffer_, (const uint8_t *)idata, 0, ibyteSize, Draw::UPDATE_DISCARD); BindIndexBuffer(upIBuffer_, 0); + UpdateDynamicUniformBuffer(ub, ubSize); ApplyCurrentState(); for (int i = 0; i < draws.size(); i++) { if (draws[i].pipeline != curPipeline_) { curPipeline_ = (D3D11Pipeline *)draws[i].pipeline; ApplyCurrentState(); + UpdateDynamicUniformBuffer(ub, ubSize); } if (draws[i].bindTexture) { @@ -1432,6 +1440,8 @@ void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCo ID3D11ShaderResourceView *view = ((D3D11Framebuffer *)draws[i].bindFramebufferAsTex)->colorSRView; context_->PSSetShaderResources(0, 1, &view); } + ID3D11SamplerState *sstate = ((D3D11SamplerState *)draws[i].samplerState)->ss; + context_->PSSetSamplers(0, 1, &sstate); D3D11_RECT rc; rc.left = draws[i].clipx; rc.top = draws[i].clipy; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index f931db5141bb..72644baff99f 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -574,7 +574,7 @@ class D3D9Context : public DrawContext { void DrawIndexed(int vertexCount, int offset) override; void DrawUP(const void *vdata, int vertexCount) override; void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override; - void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) override; + void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *ub, size_t ubSize) override; void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override; @@ -1203,10 +1203,16 @@ void D3D9Context::DrawIndexedUP(const void *vdata, int vertexCount, const void * vdata, curPipeline_->inputLayout->GetStride()); } -void D3D9Context::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) { +void D3D9Context::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *ub, size_t ubSize) { + if (draws.is_empty() || !vertexCount || !indexCount) { + return; + } + + BindPipeline(draws[0].pipeline); curPipeline_->inputLayout->Apply(device_); curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_); ApplyDynamicState(); + UpdateDynamicUniformBuffer(ub, ubSize); // Suboptimal! Should dirty-track textures. for (int i = 0; i < draws.size(); i++) { diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index bf7bf064adcf..281eee37896b 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -444,7 +444,7 @@ class OpenGLContext : public DrawContext { void DrawIndexed(int vertexCount, int offset) override; void DrawUP(const void *vdata, int vertexCount) override; void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override; - void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) override; + void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *ub, size_t ubSize) override; void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override; @@ -1442,7 +1442,14 @@ void OpenGLContext::DrawIndexedUP(const void *vdata, int vertexCount, const void renderManager_.DrawIndexed(curPipeline_->inputLayout->inputLayout_, vbuf, voffset, ibuf, ioffset, curPipeline_->prim, indexCount, GL_UNSIGNED_SHORT, 1); } -void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) { +void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *ub, size_t ubSize) { + if (draws.is_empty() || !vertexCount || !indexCount) { + return; + } + + BindPipeline(draws[0].pipeline); + UpdateDynamicUniformBuffer(ub, ubSize); + _assert_(curPipeline_->inputLayout != nullptr); int stride = curPipeline_->inputLayout->stride; uint32_t vdataSize = stride * vertexCount; @@ -1467,6 +1474,7 @@ void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount OpenGLPipeline *glPipeline = (OpenGLPipeline *)draw.pipeline; _dbg_assert_(glPipeline->inputLayout->stride == stride); BindPipeline(glPipeline); // this updated curPipeline_. + UpdateDynamicUniformBuffer(ub, ubSize); } if (draw.bindTexture) { renderManager_.BindTexture(0, ((OpenGLTexture *)draw.bindTexture)->GetTex()); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 8480dca3358c..5d0a8b8c86d7 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -493,7 +493,7 @@ class VKContext : public DrawContext { void DrawUP(const void *vdata, int vertexCount) override; void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override; // Specialized for quick IMGUI drawing. - void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice) override; + void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice, const void *dynUniforms, size_t size) override; void BindCurrentPipeline(); void ApplyDynamicState(); @@ -1557,13 +1557,15 @@ void VKContext::DrawIndexedUP(const void *vdata, int vertexCount, const void *id renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, indexCount, 1); } -void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) { +void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *ub, size_t ubSize) { _dbg_assert_(vertexCount >= 0); _dbg_assert_(indexCount >= 0); if (vertexCount <= 0 || indexCount <= 0 || draws.is_empty()) { return; } + curPipeline_ = (VKPipeline *)draws[0].pipeline; + VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf; size_t vdataSize = vertexCount * curPipeline_->stride; uint32_t vbBindOffset; @@ -1579,6 +1581,8 @@ void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, co _assert_(idataPtr != nullptr); memcpy(idataPtr, idata, idataSize); + curPipeline_->SetDynamicUniformData(ub, ubSize); + uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf); BindCurrentPipeline(); @@ -1589,6 +1593,7 @@ void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, co VKPipeline *vkPipe = (VKPipeline *)draw.pipeline; renderManager_.BindPipeline(vkPipe->pipeline, vkPipe->flags, pipelineLayout_); curPipeline_ = (VKPipeline *)draw.pipeline; + curPipeline_->SetDynamicUniformData(ub, ubSize); } // TODO: Dirty-check these. if (draw.bindTexture) { @@ -1596,6 +1601,8 @@ void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, co } else if (draw.bindFramebufferAsTex) { BindFramebufferAsTexture(draw.bindFramebufferAsTex, 0, FBChannel::FB_COLOR_BIT, 0); } + Draw::SamplerState *sstate = draw.samplerState; + BindSamplerStates(0, 1, &sstate); int descSetIndex; PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex); BindDescriptors(vulkanUBObuf, descriptors); diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index d5d00c546f34..c1210c7d1c9c 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -705,6 +705,7 @@ struct ClippedDraw { s16 cliph; Draw::Texture *bindTexture; Draw::Framebuffer *bindFramebufferAsTex; + Draw::SamplerState *samplerState; Draw::Pipeline *pipeline; }; @@ -844,7 +845,7 @@ class DrawContext { virtual void DrawUP(const void *vdata, int vertexCount) = 0; virtual void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) = 0; // Intended for ImGui display lists, easier to do optimally this way. - virtual void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws) = 0; + virtual void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice draws, const void *dynUniforms, size_t size) = 0; // Frame management (for the purposes of sync and resource management, necessary with modern APIs). Default implementations here. virtual void BeginFrame(DebugFlags debugFlags) = 0; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index bb7679669906..499be8fa6334 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -3705,10 +3705,15 @@ void FramebufferManagerCommon::DrawImGuiDebug(int &selected) const { } ImGui::EndTable(); + // Fix out-of-bounds issues when framebuffers are removed. + if (selected >= vfbs_.size()) { + selected = -1; + } + if (selected != -1) { // Now, draw the image of the selected framebuffer. Draw::Framebuffer *fb = vfbs_[selected]->fbo; - ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(fb, Draw::FB_COLOR_BIT); + ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(fb, Draw::FB_COLOR_BIT, ImGuiPipeline::TexturedOpaque); ImGui::Image(texId, ImVec2(fb->Width(), fb->Height())); } } diff --git a/ext/imgui/imgui_impl_thin3d.cpp b/ext/imgui/imgui_impl_thin3d.cpp index 2398c0d57414..18c0a4fef4f0 100644 --- a/ext/imgui/imgui_impl_thin3d.cpp +++ b/ext/imgui/imgui_impl_thin3d.cpp @@ -21,18 +21,13 @@ struct RegisteredTexture { Draw::FBChannel aspect; }; }; - Draw::Pipeline *pipeline; -}; - -enum { - IMGUI_PIPELINE_TEXTURE_BLEND, - IMGUI_PIPELINE_TEXTURE, + ImGuiPipeline pipeline; }; struct BackendData { Draw::SamplerState *fontSampler = nullptr; Draw::Texture *fontImage = nullptr; - Draw::Pipeline *pipeline = nullptr; + Draw::Pipeline *pipelines[2]{}; std::vector tempTextures; }; @@ -45,39 +40,6 @@ static BackendData *ImGui_ImplThin3d_GetBackendData() { return ImGui::GetCurrentContext() ? (BackendData *)ImGui::GetIO().BackendRendererUserData : nullptr; } -static void ImGui_ImplThin3d_SetupRenderState(Draw::DrawContext *draw, ImDrawData* drawData, Draw::Pipeline *pipeline, int fb_width, int fb_height) { - BackendData *bd = ImGui_ImplThin3d_GetBackendData(); - - // Bind pipeline and texture - draw->BindPipeline(pipeline); - draw->BindSamplerStates(0, 1, &bd->fontSampler); - - // Setup viewport - { - Draw::Viewport viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = (float)fb_width; - viewport.Height = (float)fb_height; - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - draw->SetViewport(viewport); - } - - // Setup scale and translation: - // Our visible imgui space lies from drawData->DisplayPps (top left) to drawData->DisplayPos + drawData->DisplaySize (bottom right). - // DisplayPos is (0,0) for single viewport apps. We currently ignore DisplayPos. - // We probably only need to do this at the start of the frame. - { - Lin::Matrix4x4 mtx = ComputeOrthoMatrix(drawData->DisplaySize.x, drawData->DisplaySize.y, draw->GetDeviceCaps().coordConvention); - - Draw::VsTexColUB ub{}; - memcpy(ub.WorldViewProj, mtx.getReadPtr(), sizeof(Lin::Matrix4x4)); - ub.saturation = 1.0f; - draw->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); - } -} - // Render function void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) @@ -88,9 +50,23 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d } BackendData* bd = ImGui_ImplThin3d_GetBackendData(); + draw->BindSamplerStates(0, 1, &bd->fontSampler); - // Setup desired Vulkan state - ImGui_ImplThin3d_SetupRenderState(draw, draw_data, bd->pipeline, fb_width, fb_height); + // Setup viewport + Draw::Viewport viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = (float)fb_width; + viewport.Height = (float)fb_height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + draw->SetViewport(viewport); + + Lin::Matrix4x4 mtx = ComputeOrthoMatrix(draw_data->DisplaySize.x, draw_data->DisplaySize.y, draw->GetDeviceCaps().coordConvention); + + Draw::VsTexColUB ub{}; + memcpy(ub.WorldViewProj, mtx.getReadPtr(), sizeof(Lin::Matrix4x4)); + ub.saturation = 1.0f; // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports @@ -103,7 +79,8 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d std::vector draws; Draw::Texture *boundTexture; Draw::Framebuffer *boundFBAsTexture; - Draw::Pipeline *boundPipeline = bd->pipeline; + Draw::Pipeline *boundPipeline = bd->pipelines[0]; + Draw::SamplerState *boundSampler = bd->fontSampler; // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { @@ -111,59 +88,56 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d draws.clear(); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != nullptr) { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) { - ImGui_ImplThin3d_SetupRenderState(draw, draw_data, bd->pipeline, fb_width, fb_height); - } else { - pcmd->UserCallback(cmd_list, pcmd); - } + // We don't use the callback mechanism. + _dbg_assert_(pcmd->UserCallback == nullptr); + + // Update the texture pointers. + if (!pcmd->TextureId) { + // Default + boundTexture = bd->fontImage; + boundFBAsTexture = nullptr; + boundPipeline = bd->pipelines[0]; + boundSampler = bd->fontSampler; } else { - // Update the texture pointers. - if (!pcmd->TextureId) { - boundTexture = bd->fontImage; - boundFBAsTexture = nullptr; - boundPipeline = bd->pipeline; + size_t index = (size_t)pcmd->TextureId - TEX_ID_OFFSET; + _dbg_assert_(index < bd->tempTextures.size()); + if (bd->tempTextures[index].framebuffer) { + boundFBAsTexture = bd->tempTextures[index].framebuffer; + boundTexture = nullptr; } else { - size_t index = (size_t)pcmd->TextureId - TEX_ID_OFFSET; - _dbg_assert_(index < bd->tempTextures.size()); - if (bd->tempTextures[index].framebuffer) { - boundFBAsTexture = bd->tempTextures[index].framebuffer; - boundTexture = nullptr; - } else { - boundTexture = bd->tempTextures[index].texture; - boundFBAsTexture = nullptr; - } - boundPipeline = bd->tempTextures[index].pipeline ? bd->tempTextures[index].pipeline : bd->pipeline; + boundTexture = bd->tempTextures[index].texture; + boundFBAsTexture = nullptr; } - - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); - ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - - // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds - if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } - if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } - if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } - if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } - if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) - continue; - - Draw::ClippedDraw clippedDraw; - clippedDraw.pipeline = boundPipeline; - clippedDraw.bindTexture = boundTexture; - clippedDraw.bindFramebufferAsTex = boundFBAsTexture; - clippedDraw.clipx = clip_min.x; - clippedDraw.clipy = clip_min.y; - clippedDraw.clipw = clip_max.x - clip_min.x; - clippedDraw.cliph = clip_max.y - clip_min.y; - clippedDraw.indexCount = pcmd->ElemCount; - clippedDraw.indexOffset = pcmd->IdxOffset; - draws.push_back(clippedDraw); + boundPipeline = bd->pipelines[(int)bd->tempTextures[index].pipeline]; + boundSampler = bd->fontSampler; } + + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + + // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds + if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } + if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } + if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } + if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + Draw::ClippedDraw clippedDraw; + clippedDraw.pipeline = boundPipeline; + clippedDraw.bindTexture = boundTexture; + clippedDraw.bindFramebufferAsTex = boundFBAsTexture; + clippedDraw.samplerState = boundSampler; + clippedDraw.clipx = clip_min.x; + clippedDraw.clipy = clip_min.y; + clippedDraw.clipw = clip_max.x - clip_min.x; + clippedDraw.cliph = clip_max.y - clip_min.y; + clippedDraw.indexCount = pcmd->ElemCount; + clippedDraw.indexOffset = pcmd->IdxOffset; + draws.push_back(clippedDraw); } - draw->DrawIndexedClippedBatchUP(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.size(), cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.size(), draws); + draw->DrawIndexedClippedBatchUP(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.size(), cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.size(), draws, &ub, sizeof(ub)); } draw->SetScissorRect(0, 0, fb_width, fb_height); @@ -188,7 +162,7 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) { bd->fontSampler = draw->CreateSamplerState(desc); } - if (!bd->pipeline) { + if (!bd->pipelines[0]) { BackendData* bd = ImGui_ImplThin3d_GetBackendData(); using namespace Draw; @@ -207,6 +181,7 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) { BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD, BlendFactor::ONE, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD, }); + BlendState *blendOpaque = draw->CreateBlendState({ false, 0xF }); DepthStencilStateDesc dsDesc{}; DepthStencilState *depthStencil = draw->CreateDepthStencilState(dsDesc); @@ -225,7 +200,15 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) { &vsTexColBufDesc }; - bd->pipeline = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline"); + bd->pipelines[0] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline"); + pipelineDesc.blend = blendOpaque; + bd->pipelines[1] = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline-opaque"); + + inputLayout->Release(); + blend->Release(); + blendOpaque->Release(); + depthStencil->Release(); + rasterNoCull->Release(); } if (!bd->fontImage) { @@ -261,9 +244,11 @@ void ImGui_ImplThin3d_DestroyDeviceObjects() { bd->fontImage = nullptr; io.Fonts->SetTexID(0); } - if (bd->pipeline) { - bd->pipeline->Release(); - bd->pipeline = nullptr; + for (int i = 0; i < ARRAY_SIZE(bd->pipelines); i++) { + if (bd->pipelines[i]) { + bd->pipelines[i]->Release(); + bd->pipelines[i] = nullptr; + } } if (bd->fontSampler) { bd->fontSampler->Release(); @@ -324,7 +309,7 @@ void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatri g_drawMatrix = drawMatrix; } -ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture, Draw::Pipeline *pipeline) { +ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture, ImGuiPipeline pipeline) { BackendData* bd = ImGui_ImplThin3d_GetBackendData(); RegisteredTexture tex{ false }; @@ -335,7 +320,7 @@ ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture, Draw::Pipeli return (ImTextureID)(uint64_t)(TEX_ID_OFFSET + bd->tempTextures.size() - 1); } -ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer, Draw::FBChannel aspect, Draw::Pipeline *pipeline) { +ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer, Draw::FBChannel aspect, ImGuiPipeline pipeline) { BackendData* bd = ImGui_ImplThin3d_GetBackendData(); RegisteredTexture tex{ true }; diff --git a/ext/imgui/imgui_impl_thin3d.h b/ext/imgui/imgui_impl_thin3d.h index 3d8326289418..11096c9dfd51 100644 --- a/ext/imgui/imgui_impl_thin3d.h +++ b/ext/imgui/imgui_impl_thin3d.h @@ -34,17 +34,22 @@ #include "Common/Math/lin/matrix4x4.h" // Called by user code. Takes ownership of the font buffer and later deletes it. -IMGUI_IMPL_API bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw, const uint8_t *ttf_font, size_t size); -IMGUI_IMPL_API void ImGui_ImplThin3d_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix); -IMGUI_IMPL_API void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw); -IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw); -IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyDeviceObjects(); +IMGUI_IMPL_API bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw, const uint8_t *ttf_font, size_t size); +IMGUI_IMPL_API void ImGui_ImplThin3d_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix); +IMGUI_IMPL_API void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw); +IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw); +IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyDeviceObjects(); + +enum class ImGuiPipeline { + TexturedAlphaBlend = 0, + TexturedOpaque = 1, +}; // These register a texture for imgui drawing, but just for the current frame. // Textures are unregistered again in RenderDrawData. This is just simpler. -IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture, Draw::Pipeline *pipeline = nullptr); -IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer, Draw::FBChannel aspect = Draw::FB_COLOR_BIT, Draw::Pipeline *pipeline = nullptr); +IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddTextureTemp(Draw::Texture *texture, ImGuiPipeline pipeline = ImGuiPipeline::TexturedAlphaBlend); +IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer *framebuffer, Draw::FBChannel aspect = Draw::FB_COLOR_BIT, ImGuiPipeline pipeline = ImGuiPipeline::TexturedAlphaBlend); void ImGui_PushFixedFont(); void ImGui_PopFont();