[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.
This commit is contained in:
BZLZHH
2026-08-18 14:20:02 +08:00
parent 98f2a55214
commit 08ca897a07
3 changed files with 139 additions and 0 deletions
@@ -13,6 +13,7 @@
#include <Shader.h>
#include <PipelineState.h>
#include <InputLayout.h>
#include <Sampler.h>
#include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ProgramState/ProgramObject.h>
@@ -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;
}
@@ -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;
@@ -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<const void*>(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";
}