mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Fix] (Diligent): fix y inversion and front-face winding in viewport mapping
- Translate OpenGL bottom-left viewport/scissor rects to Diligent top-left origin - Invert FrontCounterClockwise to compensate for the Y conversion - Add DrawsTopHalfTriangleFromMobileGLState y-orientation test
This commit is contained in:
@@ -1282,9 +1282,12 @@ void main()
|
||||
if (glViewport.z() <= 0 || glViewport.w() <= 0) {
|
||||
glViewport = IntVec4(0, 0, static_cast<Int32>(m_width), static_cast<Int32>(m_height));
|
||||
}
|
||||
// Diligent uses the top-left window origin (Direct3D convention); OpenGL uses
|
||||
// a bottom-left origin. Translate the GL viewport rect into Diligent's space.
|
||||
const Float viewportY = static_cast<Float>(m_height) - (glViewport.w() + glViewport.y());
|
||||
::Diligent::Viewport viewport{
|
||||
static_cast<Float>(glViewport.x()),
|
||||
static_cast<Float>(glViewport.y()),
|
||||
viewportY,
|
||||
static_cast<Float>(glViewport.z()),
|
||||
static_cast<Float>(glViewport.w()),
|
||||
0.0f, 1.0f};
|
||||
@@ -1292,11 +1295,12 @@ void main()
|
||||
|
||||
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ScissorTest)) {
|
||||
const auto scissor = MG_State::pGLContext->GetScissorBox();
|
||||
const Int32 scissorTop = static_cast<Int32>(m_height) - (scissor.w() + scissor.y());
|
||||
::Diligent::Rect rect{
|
||||
scissor.x(),
|
||||
scissor.y(),
|
||||
scissorTop,
|
||||
scissor.x() + scissor.z(),
|
||||
scissor.y() + scissor.w()};
|
||||
scissorTop + scissor.w()};
|
||||
m_pContext->SetScissorRects(1, &rect, m_width, m_height);
|
||||
} else {
|
||||
::Diligent::Rect rect{0, 0, static_cast<::Diligent::Int32>(m_width),
|
||||
@@ -1508,8 +1512,10 @@ void main()
|
||||
|
||||
graphicsPipeline.RasterizerDesc.CullMode = cullEnabled ? ConvertCullMode(MG_State::pGLContext->GetCullFaceMode())
|
||||
: ::Diligent::CULL_MODE_NONE;
|
||||
// The viewport Y conversion mirrors GL's bottom-left origin to Diligent's
|
||||
// top-left origin, so the front-face winding must be inverted to match GL.
|
||||
graphicsPipeline.RasterizerDesc.FrontCounterClockwise =
|
||||
MG_State::pGLContext->GetFrontFaceMode() == FrontFaceMode::CounterClockwise;
|
||||
MG_State::pGLContext->GetFrontFaceMode() == FrontFaceMode::Clockwise;
|
||||
graphicsPipeline.DepthStencilDesc.DepthEnable = depthEnabled;
|
||||
graphicsPipeline.DepthStencilDesc.DepthWriteEnable = MG_State::pGLContext->GetDepthMask();
|
||||
graphicsPipeline.DepthStencilDesc.DepthFunc = ConvertDepthFunc(MG_State::pGLContext->GetDepthFunc());
|
||||
|
||||
@@ -1120,3 +1120,73 @@ void main() { Color = vec4(1.0, 0.0, 0.0, 1.0); }
|
||||
EXPECT_GT(center[0], 200) << "center should be red from baseVertex-selected triangle";
|
||||
EXPECT_LT(center[1], 50) << "center should not be green";
|
||||
}
|
||||
|
||||
|
||||
TEST(DiligentVulkanBackend, DrawsTopHalfTriangleFromMobileGLState) {
|
||||
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);
|
||||
|
||||
// Triangle occupies the upper half of NDC (positive Y).
|
||||
const float vertices[] = {
|
||||
-0.5f, 0.1f,
|
||||
0.5f, 0.1f,
|
||||
0.0f, 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, 0, nullptr);
|
||||
|
||||
DiligentBackend::BackendObject_Diligent backend;
|
||||
backend.Initialize();
|
||||
auto* renderer = backend.GetRenderer();
|
||||
if (renderer == nullptr) {
|
||||
GTEST_SKIP() << "No Vulkan adapter available; skipping y-orientation test";
|
||||
}
|
||||
|
||||
renderer->Clear(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
renderer->DrawFromState(GL_TRIANGLES, 0, 3, 0, nullptr);
|
||||
renderer->Present();
|
||||
|
||||
std::uint8_t upper[4] = {};
|
||||
renderer->ReadPixels(128, 64, 1, 1, upper);
|
||||
EXPECT_GT(upper[0], 200) << "upper half should be red";
|
||||
|
||||
std::uint8_t lower[4] = {};
|
||||
renderer->ReadPixels(128, 192, 1, 1, lower);
|
||||
EXPECT_GT(lower[1], 200) << "lower half should remain green";
|
||||
EXPECT_LT(lower[0], 50) << "lower half should not be red";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user