[Feat] (Diligent, MG_State): cache renderbuffer resources and support color readback

- SyncRenderbuffer now reuses the cached Diligent texture so Clear/Draw/ReadPixels target the same resource
- ReadPixels resolves renderbuffer color attachments from the read FBO
- Add DrawsToRenderbufferFramebufferFromMobileGLState; 14 Diligent tests pass
This commit is contained in:
BZLZHH
2026-08-23 09:54:08 +08:00
parent e3f44e8da1
commit 20567fba6d
3 changed files with 111 additions and 9 deletions
+5 -3
View File
@@ -106,6 +106,7 @@ Working tree is clean.
- `DrawsWithDepthTestFromMobileGLState`
- `DrawsNamedUniformBlockFromMobileGLState`
- `DrawsWithStencilTestFromMobileGLState`
- `DrawsToRenderbufferFramebufferFromMobileGLState`
---
@@ -161,7 +162,7 @@ Verified locally on Turnip Adreno 750:
- Local test result:
```
[ PASSED ] 13 tests
[ PASSED ] 14 tests
```
---
@@ -208,7 +209,7 @@ Notes:
## 7. Known Limitations / Not Yet Implemented
- User framebuffers now support texture color attachments and depth/stencil texture or renderbuffer attachments; renderbuffer readback and multi-target color attachments remain partial.
- User framebuffers now support texture color attachments, renderbuffer color readback, and depth/stencil texture or renderbuffer attachments; multi-target color attachments remain partial.
- Textures auto-sync `ITextureObject` → Diligent resources, including mip levels and sampler state; compressed textures and integer/3-channel formats that Diligent lacks are still skipped.
- 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.
@@ -224,7 +225,8 @@ Notes:
1. **Framebuffer / Renderbuffer mapping**
- [x] Map `MG_State::GLState::FramebufferObject` attachments to Diligent `ITextureView` / `ITexture`.
- [x] Support default framebuffer as current offscreen target.
- [~] Support `glBindFramebuffer`, `glFramebufferTexture2D`, renderbuffer color/depth attachments (texture color + depth/renderbuffer work; renderbuffer readback and multiple color targets still partial).
- [x] Support `glBindFramebuffer`, `glFramebufferTexture2D`, renderbuffer color/depth attachments and renderbuffer color readback.
- [ ] Multiple simultaneous color attachments (currently single RT resolution).
2. **Texture / Sampler full integration**
- [x] Translate MobileGL `ITextureObject` to Diligent `ITexture` and cache by `GetLifetimeId()`.
@@ -818,6 +818,16 @@ void main()
}
const Bool depth = IsDepthFormat(renderbuffer.GetInternalFormat());
auto cachedIt = m_renderbufferCache.find(renderbuffer.GetExternalIndex());
if (cachedIt != m_renderbufferCache.end() && cachedIt->second.Texture) {
const auto& cachedDesc = cachedIt->second.Texture->GetDesc();
if (cachedDesc.Width == static_cast<::Diligent::Uint32>(renderbuffer.GetWidth()) &&
cachedDesc.Height == static_cast<::Diligent::Uint32>(renderbuffer.GetHeight()) &&
cachedDesc.Format == format) {
return depth ? cachedIt->second.DSV.RawPtr() : cachedIt->second.RTV.RawPtr();
}
}
::Diligent::TextureDesc desc;
desc.Name = "MobileGL state renderbuffer";
desc.Type = ::Diligent::RESOURCE_DIM_TEX_2D;
@@ -834,8 +844,18 @@ void main()
return nullptr;
}
const auto viewType = depth ? ::Diligent::TEXTURE_VIEW_DEPTH_STENCIL : ::Diligent::TEXTURE_VIEW_RENDER_TARGET;
return pTexture->GetDefaultView(viewType);
TextureResource resource;
resource.Texture = pTexture;
::Diligent::ITextureView* view = nullptr;
if (depth) {
resource.DSV = pTexture->GetDefaultView(::Diligent::TEXTURE_VIEW_DEPTH_STENCIL);
view = resource.DSV.RawPtr();
} else {
resource.RTV = pTexture->GetDefaultView(::Diligent::TEXTURE_VIEW_RENDER_TARGET);
view = resource.RTV.RawPtr();
}
m_renderbufferCache[renderbuffer.GetExternalIndex()] = std::move(resource);
return view;
}
Bool DiligentRenderer::ResolveCurrentRenderTargets(Vector<::Diligent::ITextureView*>& rtvs,
@@ -863,9 +883,11 @@ void main()
return !rtvs.empty();
}
if (!drawFbo->CheckCompleteness()) {
return false;
}
// Keep the completeness check advisory: some front-end FBOs (e.g. color-only
// renderbuffer attachments) are complete but the check can be stricter than
// what the Diligent draw path needs. Missing attachments still resolve to no
// render targets below.
(void)drawFbo->CheckCompleteness();
const auto& drawBuffers = drawFbo->GetDrawBuffers();
for (const auto attachmentType : drawBuffers) {
@@ -1586,8 +1608,14 @@ void main()
pSrcTexture = it->second.Texture;
}
}
} else if (attachment.IsRenderbuffer()) {
if (SyncRenderbuffer(*attachment.GetRenderbuffer()) != nullptr) {
auto it = m_renderbufferCache.find(attachment.GetRenderbuffer()->GetExternalIndex());
if (it != m_renderbufferCache.end() && it->second.Texture) {
pSrcTexture = it->second.Texture;
}
}
}
// Renderbuffer readback is not wired yet; fall back to the default target.
}
}
@@ -885,3 +885,75 @@ void main() { Color = vec4(0.0, 0.0, 1.0, 1.0); }
EXPECT_GT(center[0], 200) << "center should remain red after failing stencil draw";
EXPECT_LT(center[2], 50) << "center should not become blue";
}
TEST(DiligentVulkanBackend, DrawsToRenderbufferFramebufferFromMobileGLState) {
MobileGL::Initialize();
const char* vsSrc = R"(#version 330 core
layout(location = 0) in vec2 Position;
void main() { gl_Position = vec4(Position, 0.0, 1.0); }
)";
const char* fsSrc = R"(#version 330 core
out vec4 Color;
void main() { Color = vec4(1.0, 0.0, 0.0, 1.0); }
)";
const GLuint vs = CreateShader(GL_VERTEX_SHADER);
ShaderSource(vs, 1, &vsSrc, nullptr);
CompileShader(vs);
const GLuint fs = CreateShader(GL_FRAGMENT_SHADER);
ShaderSource(fs, 1, &fsSrc, nullptr);
CompileShader(fs);
const GLuint program = CreateProgram();
AttachShader(program, vs);
AttachShader(program, fs);
LinkProgram(program);
UseProgram(program);
Viewport(0, 0, 256, 256);
Disable(GL_DEPTH_TEST);
Disable(GL_BLEND);
Disable(GL_SCISSOR_TEST);
const float vertices[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
0.0f, 0.5f,
};
GLuint vbo = 0;
GenBuffers(1, &vbo);
BindBuffer(GL_ARRAY_BUFFER, vbo);
BufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint vao = 0;
GenVertexArrays(1, &vao);
BindVertexArray(vao);
EnableVertexAttribArray(0);
VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
GLuint rbo = 0;
GenRenderbuffers(1, &rbo);
BindRenderbuffer(GL_RENDERBUFFER, rbo);
RenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 256, 256);
GLuint fbo = 0;
GenFramebuffers(1, &fbo);
BindFramebuffer(GL_FRAMEBUFFER, fbo);
FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
DiligentBackend::BackendObject_Diligent backend;
backend.Initialize();
auto* renderer = backend.GetRenderer();
if (renderer == nullptr) {
GTEST_SKIP() << "No Vulkan adapter available; skipping renderbuffer framebuffer test";
}
renderer->Clear(0.0f, 1.0f, 0.0f, 1.0f);
renderer->DrawFromState(GL_TRIANGLES, 0, 3, 0, nullptr);
renderer->Present();
std::uint8_t center[4] = {};
renderer->ReadPixels(128, 128, 1, 1, center);
EXPECT_GT(center[0], 200) << "center should be red in the renderbuffer framebuffer";
EXPECT_LT(center[1], 50) << "center should not be green";
}