mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 05:38:31 +09:00
[Fix, Test] (RenderState, DirectGLES, MG_IntegrationTest): tell a deliberately empty scissor box apart from one that was never written
This commit is contained in:
@@ -843,6 +843,21 @@ namespace MobileGL {
|
||||
stored = box;
|
||||
stateChanged = true;
|
||||
}
|
||||
// "The application has written this rectangle" is a DIFFERENT predicate from "the
|
||||
// value moved", and the backends need the first one: glScissor(0, 0, 0, 0) as the
|
||||
// very first scissor call leaves every stored box byte-identical to its
|
||||
// never-written default, and that call is precisely the one whose meaning a
|
||||
// backend must stop guessing at (see ScissorBoxWrittenMask).
|
||||
//
|
||||
// The transition has to count as a state change for the version too. DirectGLES'
|
||||
// SyncRenderState early-outs on an unchanged render-state version BEFORE it
|
||||
// reaches the span memcmp that would otherwise notice the mask, so a version-less
|
||||
// flag flip would sit in the parameter block and never be pushed. It is a
|
||||
// once-per-index transition, so the steady state still costs nothing.
|
||||
if (m_parameters.ScissorBoxWrittenMask != kAllViewportsMask) {
|
||||
m_parameters.ScissorBoxWrittenMask = kAllViewportsMask;
|
||||
stateChanged = true;
|
||||
}
|
||||
if (stateChanged) ++m_version;
|
||||
}
|
||||
|
||||
@@ -855,9 +870,15 @@ namespace MobileGL {
|
||||
MOBILEGL_ASSERT(false, "Scissor box index out of range: %u", index);
|
||||
return;
|
||||
}
|
||||
if (m_parameters.ScissorBoxes[index] == box) return;
|
||||
// See SetScissorBox: a first write is state even when it does not move the value,
|
||||
// so the unchanged-value early-out may only fire once this index is already
|
||||
// marked written.
|
||||
const Uint32 writtenBit = 1u << index;
|
||||
const Bool alreadyWritten = (m_parameters.ScissorBoxWrittenMask & writtenBit) != 0;
|
||||
if (alreadyWritten && m_parameters.ScissorBoxes[index] == box) return;
|
||||
|
||||
m_parameters.ScissorBoxes[index] = box;
|
||||
m_parameters.ScissorBoxWrittenMask |= writtenBit;
|
||||
++m_version;
|
||||
}
|
||||
|
||||
|
||||
@@ -328,6 +328,18 @@ namespace MobileGL {
|
||||
// turns it into a real glEnable/glDisable.
|
||||
Uint32 ScissorTestEnabledMask = 0;
|
||||
Array<IntVec4, MAX_VIEWPORTS> ScissorBoxes{}; // x, y, width, height
|
||||
// One bit per viewport, set the first time the application writes that index's scissor
|
||||
// rectangle - glScissor broadcasts and sets all 16, glScissorIndexed/glScissorArrayv set
|
||||
// the indices they name. It exists because the RECTANGLE cannot answer "has the
|
||||
// application spoken?": ScissorBoxes starts all-zero (its spec initial value is the size
|
||||
// of a window the frontend does not know yet, see the RenderState constructor), and
|
||||
// glScissor(0, 0, 0, 0) is a legal GL state meaning "the scissor test rejects every
|
||||
// fragment". A backend that reads an empty rectangle as the never-written sentinel
|
||||
// therefore INVERTS that request into "accept every fragment"; DirectGLES did exactly
|
||||
// that and KHR-GL43.viewport_array.scissor_zero_dimension caught it. Deliberately beside
|
||||
// ScissorBoxes so it shares their tail span (after LogicOp) and DirectGLES' span memcmp
|
||||
// picks a transition up like any other state.
|
||||
Uint32 ScissorBoxWrittenMask = 0;
|
||||
// glEnable(GL_CLIP_DISTANCE0 + i) for i in [0, 8), one bit each. A bitmask rather than
|
||||
// eight bools because every consumer wants the set, not an individual flag, and because
|
||||
// the SYNC_CAPABILITY/SET_CAPABILITY macros key off a "<Name>Enabled" field name that
|
||||
|
||||
Reference in New Issue
Block a user