From 08ca897a0770e2a36338d616e61a5912589a5b8e Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Tue, 18 Aug 2026 14:20:02 +0800 Subject: [PATCH] [Feat, Test] (Diligent, MG_Test): add basic texture binding and textured state-draw test - Add CreateTestTexture(): creates an RGBA8 texture, SRV and default sampler, and attaches the sampler to the SRV. - State PSOs now bind a static pixel-shader variable 'g_Texture' to the test texture and commit shader resources before drawing. - Add DrawsTexturedFromMobileGLState test using a real GL program with sampler2D and interleaved position+UV attributes. - All 4 Diligent local tests pass on Turnip Adreno 750. --- .../Diligent/Renderer/DiligentRenderer.cpp | 56 ++++++++++++++ .../Diligent/Renderer/DiligentRenderer.h | 9 +++ .../MG_Test/Backend/Diligent/SanityTest.cpp | 74 +++++++++++++++++++ 3 files changed, 139 insertions(+) diff --git a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp index 343c1b03..27048c2e 100644 --- a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp +++ b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -431,6 +432,46 @@ void main() m_pContext->Draw(drawAttrs); } + Bool DiligentRenderer::CreateTestTexture(const void* data, Uint32 width, Uint32 height) { + if (m_pDevice == nullptr || data == nullptr || width == 0 || height == 0) { + return false; + } + + ::Diligent::TextureDesc texDesc; + texDesc.Name = "MobileGL Diligent test texture"; + texDesc.Type = ::Diligent::RESOURCE_DIM_TEX_2D; + texDesc.Format = ::Diligent::TEX_FORMAT_RGBA8_UNORM; + texDesc.Width = width; + texDesc.Height = height; + texDesc.MipLevels = 1; + texDesc.BindFlags = ::Diligent::BIND_SHADER_RESOURCE; + texDesc.Usage = ::Diligent::USAGE_DEFAULT; + + ::Diligent::TextureSubResData subResData; + subResData.pData = data; + subResData.Stride = static_cast<::Diligent::Uint64>(width) * 4; + + ::Diligent::TextureData texData; + texData.pSubResources = &subResData; + texData.NumSubresources = 1; + + m_pDevice->CreateTexture(texDesc, &texData, &m_pTestTexture); + if (!m_pTestTexture) { + return false; + } + m_pTestSRV = m_pTestTexture->GetDefaultView(::Diligent::TEXTURE_VIEW_SHADER_RESOURCE); + if (!m_pTestSRV) { + return false; + } + + ::Diligent::SamplerDesc samplerDesc; + m_pDevice->CreateSampler(samplerDesc, &m_pTestSampler); + if (m_pTestSampler) { + m_pTestSRV->SetSampler(m_pTestSampler); + } + return m_pTestSampler != nullptr; + } + void DiligentRenderer::DrawFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices) { if (!m_initialized || !m_pContext || MG_State::pGLContext == nullptr) { return; @@ -480,6 +521,9 @@ void main() const auto& front = MG_State::pGLContext->GetStencilState(StencilFace::Front); m_pContext->SetStencilRef(static_cast<::Diligent::Uint32>(front.Ref)); } + if (m_pStateSRB) { + m_pContext->CommitShaderResources(m_pStateSRB, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + } ::Diligent::DrawAttribs drawAttrs; drawAttrs.NumVertices = m_lastDrawVertexCount; @@ -649,6 +693,18 @@ void main() MGLOG_E("DiligentRenderer: failed to create state pipeline"); return false; } + + m_pStateSRB = nullptr; + if (m_pTestSRV) { + auto* staticVar = m_pPSO->GetStaticVariableByName(::Diligent::SHADER_TYPE_PIXEL, "g_Texture"); + if (staticVar != nullptr) { + staticVar->Set(m_pTestSRV); + } + m_pPSO->CreateShaderResourceBinding(&m_pStateSRB, false); + if (m_pStateSRB) { + m_pPSO->InitializeStaticSRBResources(m_pStateSRB); + } + } return true; } diff --git a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h index 50b8ecba..ae450741 100644 --- a/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h +++ b/MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.h @@ -27,6 +27,8 @@ namespace Diligent { struct ITextureView; struct IPipelineState; struct IBuffer; + struct ISampler; + struct IShaderResourceBinding; } namespace MobileGL::MG_Backend::DiligentBackend { @@ -44,6 +46,9 @@ namespace MobileGL::MG_Backend::DiligentBackend { void ClearDepth(Float depth); void DrawTriangle(); void DrawVertices(const Float* vertices, Uint32 vertexCount); + // Creates a simple 2D RGBA8 texture from CPU data and makes it available + // to state PSOs under the shader variable name "g_Texture". + 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); @@ -66,6 +71,10 @@ namespace MobileGL::MG_Backend::DiligentBackend { ::Diligent::RefCntAutoPtr<::Diligent::ITextureView> m_pColorRTV; ::Diligent::RefCntAutoPtr<::Diligent::ITexture> m_pDepthTarget; ::Diligent::RefCntAutoPtr<::Diligent::ITextureView> m_pDepthDSV; + ::Diligent::RefCntAutoPtr<::Diligent::ITexture> m_pTestTexture; + ::Diligent::RefCntAutoPtr<::Diligent::ITextureView> m_pTestSRV; + ::Diligent::RefCntAutoPtr<::Diligent::ISampler> m_pTestSampler; + ::Diligent::RefCntAutoPtr<::Diligent::IShaderResourceBinding> m_pStateSRB; ::Diligent::RefCntAutoPtr<::Diligent::IPipelineState> m_pPSO; ::Diligent::RefCntAutoPtr<::Diligent::IBuffer> m_pVertexBuffer; Uint32 m_width = 256; diff --git a/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp b/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp index f71341e6..519c972a 100644 --- a/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp +++ b/MobileGL/MG_Test/Backend/Diligent/SanityTest.cpp @@ -135,3 +135,77 @@ void main() { Color = vec4(1.0, 0.0, 0.0, 1.0); } EXPECT_GT(corner[1], 200) << "corner should remain green after clear"; EXPECT_LT(corner[0], 50) << "corner should not be red"; } + +TEST(DiligentVulkanBackend, DrawsTexturedFromMobileGLState) { + MobileGL::Initialize(); + + const char* vsSrc = R"(#version 330 core +layout(location = 0) in vec2 Position; +layout(location = 1) in vec2 UV; +out vec2 vUV; +void main() { gl_Position = vec4(Position, 0.0, 1.0); vUV = UV; } +)"; + const char* fsSrc = R"(#version 330 core +uniform sampler2D g_Texture; +in vec2 vUV; +out vec4 Color; +void main() { Color = texture(g_Texture, vUV); } +)"; + + 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); + + // Position + UV interleaved. + const float vertices[] = { + -0.5f, -0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 1.0f, 0.0f, + 0.0f, 0.5f, 0.5f, 1.0f, + }; + 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, 16, nullptr); + EnableVertexAttribArray(1); + VertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 16, reinterpret_cast(8)); + + DiligentBackend::BackendObject_Diligent backend; + backend.Initialize(); + auto* renderer = backend.GetRenderer(); + if (renderer == nullptr) { + GTEST_SKIP() << "No Vulkan adapter available; skipping textured state test"; + } + + // 2x2 solid red texture. + const std::uint8_t redTexture[2 * 2 * 4] = { + 255, 0, 0, 255, 255, 0, 0, 255, + 255, 0, 0, 255, 255, 0, 0, 255, + }; + ASSERT_TRUE(renderer->CreateTestTexture(redTexture, 2, 2)); + + 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 from textured triangle"; + EXPECT_LT(center[1], 50) << "center should not be green"; +}