[Feat] (Diligent, MG_Impl): honor DrawElementsBaseVertex baseVertex in CPU vertex packing

- Add baseVertex parameter through DrawFromState/UploadVertexDataFromState
- Apply baseVertex when resolving indexed vertex indices
- Pass baseVertex through DrawElementsBaseVertex, instanced, and indirect indexed draws
- Add DrawsIndexedBaseVertexFromMobileGLState; 16 Diligent tests pass
This commit is contained in:
BZLZHH
2026-08-23 10:02:44 +08:00
parent eb8ef893be
commit 5dca617f01
5 changed files with 121 additions and 20 deletions
+3 -1
View File
@@ -108,6 +108,7 @@ Working tree is clean.
- `DrawsWithStencilTestFromMobileGLState`
- `DrawsToRenderbufferFramebufferFromMobileGLState`
- `DrawsToMultipleColorAttachmentsFromMobileGLState`
- `DrawsIndexedBaseVertexFromMobileGLState`
---
@@ -149,6 +150,7 @@ Verified locally on Turnip Adreno 750:
- `ReadPixels` can read back from a user FBO color attachment
- More GL entry points wired:
- `DrawRangeElements` / `DrawRangeElementsBaseVertex`
- `DrawElementsBaseVertex` with real baseVertex selection
- `MultiDrawArrays` / `MultiDrawElements` / `MultiDrawElementsBaseVertex`
- `DrawArraysInstanced` / `DrawElementsInstanced` family
- Indirect draw CPU fallback: `DrawArraysIndirect`, `DrawElementsIndirect`, `MultiDraw*Indirect`, `*IndirectCount`
@@ -163,7 +165,7 @@ Verified locally on Turnip Adreno 750:
- Local test result:
```
[ PASSED ] 15 tests
[ PASSED ] 16 tests
```
---
@@ -113,8 +113,10 @@ namespace MobileGL::MG_Backend::DiligentBackend {
const void* indices, GLint basevertex) {
(void)start;
(void)end;
(void)basevertex;
DrawElements(mode, count, type, indices);
auto* renderer = GetActiveRenderer();
if (renderer != nullptr) {
renderer->DrawFromState(mode, 0, count, type, indices, basevertex);
}
}
void MultiDrawArrays(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) {
@@ -144,11 +146,10 @@ 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);
auto* renderer = GetActiveRenderer();
if (renderer != nullptr) {
renderer->DrawFromState(mode, 0, count, type, indices, basevertex);
}
}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type,
@@ -204,7 +205,8 @@ namespace MobileGL::MG_Backend::DiligentBackend {
}
const void* indices = reinterpret_cast<const void*>(static_cast<SizeT>(cmd.FirstIndex) * indexSize);
for (Uint32 i = 0; i < cmd.InstanceCount; ++i) {
renderer->DrawFromState(mode, 0, static_cast<GLsizei>(cmd.Count), type, indices);
renderer->DrawFromState(mode, 0, static_cast<GLsizei>(cmd.Count), type, indices,
static_cast<GLint>(cmd.BaseVertex));
}
}
@@ -258,7 +260,8 @@ namespace MobileGL::MG_Backend::DiligentBackend {
}
const void* indices = reinterpret_cast<const void*>(static_cast<SizeT>(cmd.FirstIndex) * indexSize);
for (Uint32 instance = 0; instance < cmd.InstanceCount; ++instance) {
renderer->DrawFromState(mode, 0, static_cast<GLsizei>(cmd.Count), type, indices);
renderer->DrawFromState(mode, 0, static_cast<GLsizei>(cmd.Count), type, indices,
static_cast<GLint>(cmd.BaseVertex));
}
}
}
@@ -332,8 +335,13 @@ namespace MobileGL::MG_Backend::DiligentBackend {
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex) {
(void)basevertex;
DrawElementsInstanced(mode, count, type, indices, instancecount);
auto* renderer = GetActiveRenderer();
if (renderer == nullptr || instancecount <= 0) {
return;
}
for (GLsizei i = 0; i < instancecount; ++i) {
renderer->DrawFromState(mode, 0, count, type, indices, basevertex);
}
}
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
@@ -345,9 +353,14 @@ namespace MobileGL::MG_Backend::DiligentBackend {
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);
auto* renderer = GetActiveRenderer();
if (renderer == nullptr || instancecount <= 0) {
return;
}
for (GLsizei i = 0; i < instancecount; ++i) {
renderer->DrawFromState(mode, 0, count, type, indices, basevertex);
}
}
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
@@ -1190,14 +1190,15 @@ void main()
return true;
}
void DiligentRenderer::DrawFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices) {
void DiligentRenderer::DrawFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices,
GLint baseVertex) {
if (!m_initialized || !m_pContext || MG_State::pGLContext == nullptr) {
return;
}
if (!CreatePipelineFromState(mode)) {
return;
}
if (!UploadVertexDataFromState(mode, first, count, type, indices)) {
if (!UploadVertexDataFromState(mode, first, count, type, indices, baseVertex)) {
return;
}
@@ -1496,7 +1497,7 @@ void main()
}
Bool DiligentRenderer::UploadVertexDataFromState(GLenum mode, GLint first, GLsizei count, GLenum type,
const void* indices) {
const void* indices, GLint baseVertex) {
if (MG_State::pGLContext == nullptr) {
return false;
}
@@ -1581,7 +1582,16 @@ void main()
Vector<Uint8> vertexData(static_cast<SizeT>(drawVertexCount) * vertexStride);
for (Uint32 vi = 0; vi < drawVertexCount; ++vi) {
const Uint32 srcIndex = indicesData.empty() ? (static_cast<Uint32>(first) + vi) : indicesData[vi];
Uint32 srcIndex = 0;
if (indicesData.empty()) {
srcIndex = static_cast<Uint32>(first) + vi;
} else {
const Int64 resolvedIndex = static_cast<Int64>(indicesData[vi]) + baseVertex;
if (resolvedIndex < 0) {
return false;
}
srcIndex = static_cast<Uint32>(resolvedIndex);
}
Uint8* dst = vertexData.data() + static_cast<SizeT>(vi) * vertexStride;
for (Uint32 attrIndex : activeAttribs) {
const auto& attr = attributes[attrIndex];
@@ -59,7 +59,8 @@ namespace MobileGL::MG_Backend::DiligentBackend {
Bool CreateTestTexture(const void* data, Uint32 width, Uint32 height);
// Draws using the live MG_State GL context: current program, VAO and
// bound buffers. This is the front-end emulation entry point.
void DrawFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices);
void DrawFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices,
GLint baseVertex = 0);
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,
@@ -91,7 +92,8 @@ namespace MobileGL::MG_Backend::DiligentBackend {
Bool CreatePipeline();
Bool CreateVertexBuffer();
Bool CreatePipelineFromState(GLenum mode);
Bool UploadVertexDataFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices);
Bool UploadVertexDataFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices,
GLint baseVertex = 0);
::Diligent::ITextureView* SyncTexture(MG_State::GLState::ITextureObject& texture);
::Diligent::ITextureView* SyncTextureForAttachment(MG_State::GLState::ITextureObject& texture, Bool depth);
::Diligent::ITextureView* SyncRenderbuffer(MG_State::GLState::RenderbufferObject& renderbuffer);
@@ -1046,3 +1046,77 @@ void main() {
EXPECT_LT(center1[0], 50) << "attachment 1 should not be red";
EXPECT_GT(center1[2], 200) << "attachment 1 should be blue";
}
TEST(DiligentVulkanBackend, DrawsIndexedBaseVertexFromMobileGLState) {
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);
BindFramebuffer(GL_FRAMEBUFFER, 0);
ReadBuffer(GL_BACK);
Disable(GL_DEPTH_TEST);
Disable(GL_BLEND);
Disable(GL_SCISSOR_TEST);
Disable(GL_STENCIL_TEST);
// First triangle is far offscreen; baseVertex=3 makes indices {0,1,2} select
// the second, visible triangle.
const float vertices[] = {
-10.0f, -10.0f, -9.0f, -10.0f, -9.0f, -9.0f,
-0.5f, -0.5f, 0.5f, -0.5f, 0.0f, 0.5f,
};
const GLuint indices[] = {0, 1, 2};
GLuint vbo = 0;
GenBuffers(1, &vbo);
BindBuffer(GL_ARRAY_BUFFER, vbo);
BufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint ebo = 0;
GenBuffers(1, &ebo);
BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
GLuint vao = 0;
GenVertexArrays(1, &vao);
BindVertexArray(vao);
EnableVertexAttribArray(0);
VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
DiligentBackend::BackendObject_Diligent backend;
backend.Initialize();
auto* renderer = backend.GetRenderer();
if (renderer == nullptr) {
GTEST_SKIP() << "No Vulkan adapter available; skipping base vertex test";
}
renderer->Clear(0.0f, 1.0f, 0.0f, 1.0f);
renderer->DrawFromState(GL_TRIANGLES, 0, 3, GL_UNSIGNED_INT, nullptr, 3);
renderer->Present();
std::uint8_t center[4] = {};
renderer->ReadPixels(128, 128, 1, 1, center);
EXPECT_GT(center[0], 200) << "center should be red from baseVertex-selected triangle";
EXPECT_LT(center[1], 50) << "center should not be green";
}