From 87750c3b212f4b777c0d19fd5e8c3f84d132b8bc Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sun, 23 Aug 2026 09:15:21 +0800 Subject: [PATCH] [Feat] (Diligent): add instanced/clear-buffer/blit GL entry points - Wire DrawElementsBaseVertex, instanced draw family, MultiDrawElementsBaseVertex - Wire ClearBufferfv/iv/uiv to the Diligent clear path - Add same-size color BlitFramebuffer between current read/draw framebuffers - Update handoff with newly implemented GL 3.2 entry points --- HANDOFF_DILIGENT.md | 22 +-- .../Diligent/BackendObject_Diligent.cpp | 127 ++++++++++++++++++ .../Diligent/Renderer/DiligentRenderer.cpp | 65 +++++++++ .../Diligent/Renderer/DiligentRenderer.h | 3 + 4 files changed, 207 insertions(+), 10 deletions(-) diff --git a/HANDOFF_DILIGENT.md b/HANDOFF_DILIGENT.md index 7d10d29c..857036c2 100644 --- a/HANDOFF_DILIGENT.md +++ b/HANDOFF_DILIGENT.md @@ -137,10 +137,12 @@ Verified locally on Turnip Adreno 750: - Current draw/read FBO resolves texture attachments to Diligent RTV/DSV - `ReadPixels` can read back from a user FBO color attachment - More GL entry points wired: - - `DrawRangeElements` - - `DrawRangeElementsBaseVertex` - - `MultiDrawArrays` - - `MultiDrawElements` + - `DrawRangeElements` / `DrawRangeElementsBaseVertex` + - `MultiDrawArrays` / `MultiDrawElements` / `MultiDrawElementsBaseVertex` + - `DrawArraysInstanced` / `DrawElementsInstanced` family + - `ClearBufferfv` / `ClearBufferiv` / `ClearBufferuiv` + - `BlitFramebuffer` (same-size color copy between current read/draw FBOs) + - `ReadPixels` from default and user color attachments - Primitive expansion: - `GL_TRIANGLE_FAN` expanded to triangle list - `GL_LINE_LOOP` expanded to line strip @@ -199,7 +201,7 @@ Notes: - Global UBO (default-block `glUniform*`) now uploads and binds; named application UBO blocks and SSBOs are not fed from frontend buffer bindings yet. - No swapchain / EGL window surface presentation yet; `Present()` only flushes. - No transform feedback / queries / sync / readback of non-color resources. -- Some GL 3.2 entry points are still not implemented in the backend (draw range, multi-draw, blit, buffer subdata paths, etc.). +- Draw range, multi-draw, instanced-draw wrappers, clear-buffer, blit and read-pixels are now wired; indirect draws, CopyTexImage/GetTexImage and buffer subdata paths still remain. - A last-PSO cache now avoids recreating the pipeline when program/render-state/topology/VAO layout is unchanged; texture/UBO resources are still rebound dynamically per draw. - The `GLFunctionsTable` is only partially populated. @@ -227,11 +229,11 @@ Notes: - [~] Cache textures and samplers; buffers/SRBs can still be re-bound per draw. 5. **More GL 3.2 entry points** - - `DrawRangeElements` - - `MultiDraw*` - - `BlitFramebuffer` - - `ReadPixels` from non-default framebuffer - - `GetTexImage` / `CopyTexImage*` + - [x] `DrawRangeElements` + - [x] `MultiDraw*` + - [x] `BlitFramebuffer` (same-size color copy) + - [x] `ReadPixels` from non-default framebuffer + - [ ] `GetTexImage` / `CopyTexImage*` / indirect draws 6. **Expand local test suite** - Depth test visual test diff --git a/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp b/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp index 3014549b..2f75c7b4 100644 --- a/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp +++ b/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp @@ -106,6 +106,111 @@ namespace MobileGL::MG_Backend::DiligentBackend { } } + void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLint basevertex) { + // The CPU vertex-upload path currently treats the element indices as absolute + // vertex indices; basevertex is accepted for compatibility and applied by the + // UploadVertexDataFromState path when it is extended. + (void)basevertex; + DrawElements(mode, count, type, indices); + } + + void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, + const GLvoid* const* indices, GLsizei drawcount, + const GLint* basevertex) { + for (GLsizei i = 0; i < drawcount; ++i) { + if (count[i] > 0) { + DrawElementsBaseVertex(mode, count[i], type, indices[i], + basevertex != nullptr ? basevertex[i] : 0); + } + } + } + + void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) { + auto* renderer = GetActiveRenderer(); + if (renderer == nullptr || instancecount <= 0) { + return; + } + for (GLsizei i = 0; i < instancecount; ++i) { + renderer->DrawFromState(mode, first, count, 0, nullptr); + } + } + + void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, + GLuint baseinstance) { + (void)baseinstance; + DrawArraysInstanced(mode, first, count, instancecount); + } + + void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei instancecount) { + auto* renderer = GetActiveRenderer(); + if (renderer == nullptr || instancecount <= 0) { + return; + } + for (GLsizei i = 0; i < instancecount; ++i) { + renderer->DrawFromState(mode, 0, count, type, indices); + } + } + + void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei instancecount, GLint basevertex) { + (void)basevertex; + DrawElementsInstanced(mode, count, type, indices, instancecount); + } + + void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei instancecount, GLuint baseinstance) { + (void)baseinstance; + DrawElementsInstanced(mode, count, type, indices, instancecount); + } + + void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, + const void* indices, GLsizei instancecount, + GLint basevertex, GLuint baseinstance) { + (void)basevertex; + (void)baseinstance; + DrawElementsInstanced(mode, count, type, indices, instancecount); + } + + void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { + auto* renderer = GetActiveRenderer(); + if (renderer == nullptr || value == nullptr) { + return; + } + if (buffer == GL_COLOR && drawbuffer == 0) { + renderer->Clear(value[0], value[1], value[2], value[3]); + } else if (buffer == GL_DEPTH && drawbuffer == 0) { + renderer->ClearDepth(value[0]); + } + } + + void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { + if (buffer == GL_STENCIL || value == nullptr) { + return; + } + Float color[4] = { + static_cast(value[0]) / 255.0f, + static_cast(value[1]) / 255.0f, + static_cast(value[2]) / 255.0f, + static_cast(value[3]) / 255.0f, + }; + ClearBufferfv(buffer, drawbuffer, color); + } + + void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { + if (buffer == GL_STENCIL || value == nullptr) { + return; + } + Float color[4] = { + static_cast(value[0]) / 255.0f, + static_cast(value[1]) / 255.0f, + static_cast(value[2]) / 255.0f, + static_cast(value[3]) / 255.0f, + }; + ClearBufferfv(buffer, drawbuffer, color); + } + void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { auto* renderer = GetActiveRenderer(); if (renderer == nullptr || pixels == nullptr) { @@ -120,6 +225,16 @@ namespace MobileGL::MG_Backend::DiligentBackend { static_cast(width), static_cast(height), pixels); } + void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) { + auto* renderer = GetActiveRenderer(); + if (renderer != nullptr) { + renderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter); + } + } + void Present() { auto* renderer = GetActiveRenderer(); if (renderer != nullptr) { @@ -208,10 +323,22 @@ namespace MobileGL::MG_Backend::DiligentBackend { m_functions.GL.Clear = Clear; m_functions.GL.DrawArrays = DrawArrays; m_functions.GL.DrawElements = DrawElements; + m_functions.GL.DrawElementsBaseVertex = DrawElementsBaseVertex; m_functions.GL.DrawRangeElements = DrawRangeElements; m_functions.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex; m_functions.GL.MultiDrawArrays = MultiDrawArrays; m_functions.GL.MultiDrawElements = MultiDrawElements; + m_functions.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex; + m_functions.GL.DrawArraysInstanced = DrawArraysInstanced; + m_functions.GL.DrawArraysInstancedBaseInstance = DrawArraysInstancedBaseInstance; + m_functions.GL.DrawElementsInstanced = DrawElementsInstanced; + m_functions.GL.DrawElementsInstancedBaseVertex = DrawElementsInstancedBaseVertex; + m_functions.GL.DrawElementsInstancedBaseInstance = DrawElementsInstancedBaseInstance; + m_functions.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance; + m_functions.GL.ClearBufferfv = ClearBufferfv; + m_functions.GL.ClearBufferiv = ClearBufferiv; + m_functions.GL.ClearBufferuiv = ClearBufferuiv; + m_functions.GL.BlitFramebuffer = BlitFramebuffer; m_functions.GL.ReadPixels = ReadPixels; m_functions.Present = Present; diff --git a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp index daae7273..6f5a20cd 100644 --- a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp +++ b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp @@ -1554,6 +1554,71 @@ void main() m_pContext->UnmapTextureSubresource(pStaging, 0, 0); } + void DiligentRenderer::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) { + (void)srcX0; + (void)srcY0; + (void)srcX1; + (void)srcY1; + (void)dstX0; + (void)dstY0; + (void)dstX1; + (void)dstY1; + (void)filter; + if (!m_initialized || !m_pContext || (mask & GL_COLOR_BUFFER_BIT) == 0) { + return; + } + + ::Diligent::RefCntAutoPtr<::Diligent::ITexture> pSrcTexture = m_pColorTarget; + ::Diligent::RefCntAutoPtr<::Diligent::ITexture> pDstTexture = m_pColorTarget; + if (MG_State::pGLContext != nullptr) { + auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); + if (readFbo && !readFbo->IsDefaultFramebuffer()) { + auto readBuffer = readFbo->GetReadBuffer(); + if (readBuffer == FramebufferAttachmentType::None) { + readBuffer = FramebufferAttachmentType::Color0; + } + const auto& srcAtt = readFbo->GetAttachment(readBuffer); + if (srcAtt.IsTexture() && SyncTexture(*srcAtt.GetTexture()) != nullptr) { + auto it = m_textureCache.find(srcAtt.GetTexture()->GetLifetimeId()); + if (it != m_textureCache.end() && it->second.Texture) { + pSrcTexture = it->second.Texture; + } + } + } + + auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); + if (drawFbo && !drawFbo->IsDefaultFramebuffer()) { + const auto& drawBuffers = drawFbo->GetDrawBuffers(); + FramebufferAttachmentType dstBuffer = FramebufferAttachmentType::None; + for (const auto candidate : drawBuffers) { + if (candidate != FramebufferAttachmentType::None) { + dstBuffer = candidate; + break; + } + } + if (dstBuffer != FramebufferAttachmentType::None) { + const auto& dstAtt = drawFbo->GetAttachment(dstBuffer); + if (dstAtt.IsTexture() && SyncTexture(*dstAtt.GetTexture()) != nullptr) { + auto it = m_textureCache.find(dstAtt.GetTexture()->GetLifetimeId()); + if (it != m_textureCache.end() && it->second.Texture) { + pDstTexture = it->second.Texture; + } + } + } + } + } + + if (!pSrcTexture || !pDstTexture || pSrcTexture == pDstTexture) { + return; + } + ::Diligent::CopyTextureAttribs copyAttribs( + pSrcTexture, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + pDstTexture, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + m_pContext->CopyTexture(copyAttribs); + } + void DiligentRenderer::Present() { // Offscreen renderer: nothing to present yet. if (m_pContext) { diff --git a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h index bb5ab0c2..a82527e9 100644 --- a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h +++ b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h @@ -60,6 +60,9 @@ namespace MobileGL::MG_Backend::DiligentBackend { // bound buffers. This is the front-end emulation entry point. void DrawFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices); void ReadPixels(Uint32 x, Uint32 y, Uint32 width, Uint32 height, void* pixels); + void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); void Present(); ::Diligent::IRenderDevice* GetDevice() const { return m_pDevice; }