diff --git a/HANDOFF_DILIGENT.md b/HANDOFF_DILIGENT.md index dbb29883..f2a6eae1 100644 --- a/HANDOFF_DILIGENT.md +++ b/HANDOFF_DILIGENT.md @@ -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 ``` --- diff --git a/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp b/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp index d5fa8b0f..3ab3bc4d 100644 --- a/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp +++ b/MobileGL/MG_Backend/Diligent/BackendObject_Diligent.cpp @@ -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(static_cast(cmd.FirstIndex) * indexSize); for (Uint32 i = 0; i < cmd.InstanceCount; ++i) { - renderer->DrawFromState(mode, 0, static_cast(cmd.Count), type, indices); + renderer->DrawFromState(mode, 0, static_cast(cmd.Count), type, indices, + static_cast(cmd.BaseVertex)); } } @@ -258,7 +260,8 @@ namespace MobileGL::MG_Backend::DiligentBackend { } const void* indices = reinterpret_cast(static_cast(cmd.FirstIndex) * indexSize); for (Uint32 instance = 0; instance < cmd.InstanceCount; ++instance) { - renderer->DrawFromState(mode, 0, static_cast(cmd.Count), type, indices); + renderer->DrawFromState(mode, 0, static_cast(cmd.Count), type, indices, + static_cast(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) { diff --git a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp index b7534e39..61d7a0ce 100644 --- a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp +++ b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp @@ -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 vertexData(static_cast(drawVertexCount) * vertexStride); for (Uint32 vi = 0; vi < drawVertexCount; ++vi) { - const Uint32 srcIndex = indicesData.empty() ? (static_cast(first) + vi) : indicesData[vi]; + Uint32 srcIndex = 0; + if (indicesData.empty()) { + srcIndex = static_cast(first) + vi; + } else { + const Int64 resolvedIndex = static_cast(indicesData[vi]) + baseVertex; + if (resolvedIndex < 0) { + return false; + } + srcIndex = static_cast(resolvedIndex); + } Uint8* dst = vertexData.data() + static_cast(vi) * vertexStride; for (Uint32 attrIndex : activeAttribs) { const auto& attr = attributes[attrIndex]; diff --git a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h index 2036729e..92268af7 100644 --- a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h +++ b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h @@ -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); diff --git a/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp b/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp index 38910a9b..8ba71376 100644 --- a/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp +++ b/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp @@ -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"; +}