[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
This commit is contained in:
BZLZHH
2026-08-23 09:15:21 +08:00
parent 45b309db37
commit 87750c3b21
4 changed files with 207 additions and 10 deletions
+12 -10
View File
@@ -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
@@ -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<Float>(value[0]) / 255.0f,
static_cast<Float>(value[1]) / 255.0f,
static_cast<Float>(value[2]) / 255.0f,
static_cast<Float>(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<Float>(value[0]) / 255.0f,
static_cast<Float>(value[1]) / 255.0f,
static_cast<Float>(value[2]) / 255.0f,
static_cast<Float>(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<Uint32>(width), static_cast<Uint32>(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;
@@ -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) {
@@ -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; }