[Feat] (Diligent, MG_Impl): wire CopyTexImage2D/CopyTexSubImage2D readback copy

- Copy current read-FBO color attachment into the bound GL_TEXTURE_2D
- Uses whole-color CopyTexture fallback for now; 13 Diligent tests pass
This commit is contained in:
BZLZHH
2026-08-23 09:39:40 +08:00
parent 23b53eacce
commit 6bf32acdef
4 changed files with 86 additions and 2 deletions
+3 -2
View File
@@ -151,6 +151,7 @@ Verified locally on Turnip Adreno 750:
- `DrawArraysInstanced` / `DrawElementsInstanced` family - `DrawArraysInstanced` / `DrawElementsInstanced` family
- `ClearBufferfv` / `ClearBufferiv` / `ClearBufferuiv` - `ClearBufferfv` / `ClearBufferiv` / `ClearBufferuiv`
- `BlitFramebuffer` (same-size color copy between current read/draw FBOs) - `BlitFramebuffer` (same-size color copy between current read/draw FBOs)
- `CopyTexImage2D` / `CopyTexSubImage2D` (whole-color copy fallback)
- `ReadPixels` from default and user color attachments - `ReadPixels` from default and user color attachments
- Primitive expansion: - Primitive expansion:
- `GL_TRIANGLE_FAN` expanded to triangle list - `GL_TRIANGLE_FAN` expanded to triangle list
@@ -210,7 +211,7 @@ Notes:
- Global UBO (default-block `glUniform*`) and named application UBO blocks (through `glBindBufferBase`/`glUniformBlockBinding`) now upload and bind; SSBOs are still not fed from frontend buffer bindings. - Global UBO (default-block `glUniform*`) and named application UBO blocks (through `glBindBufferBase`/`glUniformBlockBinding`) now upload and bind; SSBOs are still not fed from frontend buffer bindings.
- No swapchain / EGL window surface presentation yet; `Present()` only flushes. - No swapchain / EGL window surface presentation yet; `Present()` only flushes.
- No transform feedback / queries / sync / readback of non-color resources. - No transform feedback / queries / sync / readback of non-color resources.
- 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. - Draw range, multi-draw, instanced-draw wrappers, clear-buffer, blit, read-pixels and CopyTexImage* are now wired; indirect draws, 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. - 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. - The `GLFunctionsTable` is only partially populated.
@@ -242,7 +243,7 @@ Notes:
- [x] `MultiDraw*` - [x] `MultiDraw*`
- [x] `BlitFramebuffer` (same-size color copy) - [x] `BlitFramebuffer` (same-size color copy)
- [x] `ReadPixels` from non-default framebuffer - [x] `ReadPixels` from non-default framebuffer
- [ ] `GetTexImage` / `CopyTexImage*` / indirect draws - [~] `CopyTexImage*` wired as whole-color copy; `GetTexImage` / indirect draws remain
6. **Expand local test suite** 6. **Expand local test suite**
- [x] Scissor test - [x] Scissor test
@@ -238,6 +238,46 @@ namespace MobileGL::MG_Backend::DiligentBackend {
} }
} }
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
GLsizei width, GLsizei height, GLint border) {
(void)level;
(void)internalformat;
(void)x;
(void)y;
(void)width;
(void)height;
(void)border;
auto* renderer = GetActiveRenderer();
if (renderer == nullptr || MG_State::pGLContext == nullptr || target != GL_TEXTURE_2D) {
return;
}
auto& unit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto texture = unit.GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
if (texture) {
renderer->CopyReadFramebufferToTexture(*texture);
}
}
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
GLsizei width, GLsizei height) {
(void)level;
(void)xoffset;
(void)yoffset;
(void)x;
(void)y;
(void)width;
(void)height;
auto* renderer = GetActiveRenderer();
if (renderer == nullptr || MG_State::pGLContext == nullptr || target != GL_TEXTURE_2D) {
return;
}
auto& unit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto texture = unit.GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
if (texture) {
renderer->CopyReadFramebufferToTexture(*texture);
}
}
void Present() { void Present() {
auto* renderer = GetActiveRenderer(); auto* renderer = GetActiveRenderer();
if (renderer != nullptr) { if (renderer != nullptr) {
@@ -342,6 +382,8 @@ namespace MobileGL::MG_Backend::DiligentBackend {
m_functions.GL.ClearBufferiv = ClearBufferiv; m_functions.GL.ClearBufferiv = ClearBufferiv;
m_functions.GL.ClearBufferuiv = ClearBufferuiv; m_functions.GL.ClearBufferuiv = ClearBufferuiv;
m_functions.GL.BlitFramebuffer = BlitFramebuffer; m_functions.GL.BlitFramebuffer = BlitFramebuffer;
m_functions.GL.CopyTexImage2D = CopyTexImage2D;
m_functions.GL.CopyTexSubImage2D = CopyTexSubImage2D;
m_functions.GL.ReadPixels = ReadPixels; m_functions.GL.ReadPixels = ReadPixels;
m_functions.Present = Present; m_functions.Present = Present;
@@ -1701,6 +1701,46 @@ void main()
m_pContext->CopyTexture(copyAttribs); m_pContext->CopyTexture(copyAttribs);
} }
void DiligentRenderer::CopyReadFramebufferToTexture(MG_State::GLState::ITextureObject& dst) {
if (!m_initialized || !m_pContext || !m_pColorTarget) {
return;
}
::Diligent::RefCntAutoPtr<::Diligent::ITexture> pSrcTexture = 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& att = readFbo->GetAttachment(readBuffer);
if (att.IsTexture() && SyncTexture(*att.GetTexture()) != nullptr) {
auto it = m_textureCache.find(att.GetTexture()->GetLifetimeId());
if (it != m_textureCache.end() && it->second.Texture) {
pSrcTexture = it->second.Texture;
}
}
}
}
if (SyncTexture(dst) == nullptr) {
return;
}
auto it = m_textureCache.find(dst.GetLifetimeId());
if (it == m_textureCache.end() || !it->second.Texture) {
return;
}
auto pDstTexture = it->second.Texture;
if (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() { void DiligentRenderer::Present() {
// Offscreen renderer: nothing to present yet. // Offscreen renderer: nothing to present yet.
if (m_pContext) { if (m_pContext) {
@@ -64,6 +64,7 @@ namespace MobileGL::MG_Backend::DiligentBackend {
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter); GLbitfield mask, GLenum filter);
void CopyReadFramebufferToTexture(MG_State::GLState::ITextureObject& dst);
void Present(); void Present();
::Diligent::IRenderDevice* GetDevice() const { return m_pDevice; } ::Diligent::IRenderDevice* GetDevice() const { return m_pDevice; }