mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-18 09:08:31 +09:00
[MG_Pipe, MG_Impl, MG_Remote, MG_Backend] (Disaggregated): P5c rv - set_context_values retires the value-class BARRIER_PULLED rows
set_context_values (opcode 79, MGPContextValues 96B, kCtxState) carries the active texture unit, the max touched unit, the fifteen touched-binding-point counts and the five value-class XFB rows, emitted at validate under the subsystem bit and hash-suppressed as a whole; the emit gate and the residual-skip gate read the same answer so they can never disagree. MGPipeApplySetContextValues writes gPipeInputs (the PackState shape). MGPAttribValue grows 24->56B to carry the frontend's converted three views, and MGPipeApplySetVertexAttribDefaults finally writes them (the 'ignores MGPAttribValue::ValueClass' warning dies), so GetCurrentVertexAttribute leaves the refusal set. The three texture shutters answer the applier's own serials under a server-stamped verb (APPLIER_DERIVED), storage answer kept verbatim elsewhere. FieldOwnership.def: nine value-class rows become derived RECORD_SUPPLIED, the three shutters APPLIER_DERIVED, the nine object-class rows keep their phases; FieldOwnershipTest pins that the remaining pulls are exactly the object-class list. gen_pipe.py gains SCAN_EXEMPT_ACCESSORS with per-name reasons and retiring phases (it repairs the --check gate the hd merge's two G6 probes had left red). Evidence: unit 2175/2175; integration-split 111/111; both generators' --check and --self-test green; rsp on the Xfb capture scenario 36 -> 22; red-once - gating the emission off turns seven named scenarios red, restoring returns 111/111. CONTRACT-P5C section 5.3.
This commit is contained in:
@@ -13,6 +13,15 @@
|
|||||||
// the live context happens on the client side, in MG_Impl/Pipe/PipeFill.cpp.
|
// the live context happens on the client side, in MG_Impl/Pipe/PipeFill.cpp.
|
||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
|
|
||||||
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
|
// P5c (rv, CONTRACT-P5C.md §5.3): the three texture shutters' server-side answer lives in the
|
||||||
|
// applier - MGPipeApplierTextureShutterSerial() / MGPipeApplierContextSerial(), declared here
|
||||||
|
// so the accessors below can answer with them under a server-stamped verb. MG_Pipe is below
|
||||||
|
// MG_Backend, so this direction is the layering's, and PipeApply.h forward-declares
|
||||||
|
// PipeInputs rather than including this header, so there is no cycle.
|
||||||
|
#include <MG_Pipe/PipeApply.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// MOBILEGL_PIPE_POISON: the per-verb generation stamps and the read-side
|
// MOBILEGL_PIPE_POISON: the per-verb generation stamps and the read-side
|
||||||
// Fatal{UnmigratedPipeInput} check. Derived here, once. The repository's debug gate is
|
// Fatal{UnmigratedPipeInput} check. Derived here, once. The repository's debug gate is
|
||||||
// MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG (Defines.h); the verify CI build is
|
// MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG (Defines.h); the verify CI build is
|
||||||
@@ -471,9 +480,19 @@ namespace MobileGL::MG_Pipe {
|
|||||||
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetRenderStateParameters, 0, 0);
|
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetRenderStateParameters, 0, 0);
|
||||||
return m_renderState;
|
return m_renderState;
|
||||||
}
|
}
|
||||||
|
// THE THREE TEXTURE SHUTTERS (P5c rv, CONTRACT-P5C.md §5.3). Their FieldOwnership rows
|
||||||
|
// have said "a shutter, not a value: the server answers from its own Serial" since P5;
|
||||||
|
// rv is the edit that makes the accessor DO it. Under a SERVER-STAMPED verb the answer
|
||||||
|
// is the applier's own serial (APPLIER_DERIVED): server-owned, monotone, moved by every
|
||||||
|
// applied record that can move what the frontend generation guarded. Everywhere else -
|
||||||
|
// monolith, a split build on monolith transport, any read outside a stamped verb - the
|
||||||
|
// storage answer is kept, byte for byte (G1).
|
||||||
Uint64 GetSamplingResolutionGeneration() const {
|
Uint64 GetSamplingResolutionGeneration() const {
|
||||||
MGP_INPUT_CHECK(MGPipeInputField::GetSamplingResolutionGeneration);
|
MGP_INPUT_CHECK(MGPipeInputField::GetSamplingResolutionGeneration);
|
||||||
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetSamplingResolutionGeneration, 0, 0);
|
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetSamplingResolutionGeneration, 0, 0);
|
||||||
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
|
if (m_serverStampedVerb) return MGPipeApplierTextureShutterSerial();
|
||||||
|
#endif
|
||||||
return m_samplingResolutionGeneration;
|
return m_samplingResolutionGeneration;
|
||||||
}
|
}
|
||||||
const IntVec4& GetScissorBox() const {
|
const IntVec4& GetScissorBox() const {
|
||||||
@@ -489,11 +508,21 @@ namespace MobileGL::MG_Pipe {
|
|||||||
Uint64 GetTextureBindGeneration() const {
|
Uint64 GetTextureBindGeneration() const {
|
||||||
MGP_INPUT_CHECK(MGPipeInputField::GetTextureBindGeneration);
|
MGP_INPUT_CHECK(MGPipeInputField::GetTextureBindGeneration);
|
||||||
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetTextureBindGeneration, 0, 0);
|
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetTextureBindGeneration, 0, 0);
|
||||||
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
|
// See GetSamplingResolutionGeneration: the server answers from its own Serial.
|
||||||
|
if (m_serverStampedVerb) return MGPipeApplierTextureShutterSerial();
|
||||||
|
#endif
|
||||||
return m_textureBindGeneration;
|
return m_textureBindGeneration;
|
||||||
}
|
}
|
||||||
Uint64 GetTextureContextId() const {
|
Uint64 GetTextureContextId() const {
|
||||||
MGP_INPUT_CHECK(MGPipeInputField::GetTextureContextId);
|
MGP_INPUT_CHECK(MGPipeInputField::GetTextureContextId);
|
||||||
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetTextureContextId, 0, 0);
|
MGP_INPUT_VERIFY_READ(MGPipeInputField::GetTextureContextId, 0, 0);
|
||||||
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
|
// A context IDENTITY rather than a generation: stable within the served context,
|
||||||
|
// moved by every MGPipeApplierReset - which is all the backends' per-context memo
|
||||||
|
// keys ask of it.
|
||||||
|
if (m_serverStampedVerb) return MGPipeApplierContextSerial();
|
||||||
|
#endif
|
||||||
return m_textureContextId;
|
return m_textureContextId;
|
||||||
}
|
}
|
||||||
Uint64 GetTransformFeedbackCapturedVertices() const {
|
Uint64 GetTransformFeedbackCapturedVertices() const {
|
||||||
|
|||||||
@@ -1886,6 +1886,11 @@ namespace MobileGL::MG_Pipe {
|
|||||||
case MGPipeFieldEmitter::SetDrawProgram:
|
case MGPipeFieldEmitter::SetDrawProgram:
|
||||||
case MGPipeFieldEmitter::SetDispatchProgram:
|
case MGPipeFieldEmitter::SetDispatchProgram:
|
||||||
return kMGPipeSubsystemPrograms;
|
return kMGPipeSubsystemPrograms;
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3): the residual-value record rides the residual
|
||||||
|
// subsystem - the one family with no dirty bit of its own, which is why its
|
||||||
|
// emission gate is the subsystem bit plus the whole-record hash and nothing else.
|
||||||
|
case MGPipeFieldEmitter::SetContextValues:
|
||||||
|
return kMGPipeSubsystemResidualValues;
|
||||||
case MGPipeFieldEmitter::kNone:
|
case MGPipeFieldEmitter::kNone:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2062,10 +2067,15 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// commit, not at the merge, and no file is touched twice.
|
// commit, not at the merge, and no file is touched twice.
|
||||||
//
|
//
|
||||||
// The sampler bit covers SamplerEmit.h AND ImageEmit.h: one family, one A/B.
|
// The sampler bit covers SamplerEmit.h AND ImageEmit.h: one family, one A/B.
|
||||||
|
// P5c rv: the residual subsystem joins the wired mask for set_context_values - the
|
||||||
|
// record's emission is NOT gated on a dirty bit (there is none for the family,
|
||||||
|
// NoDirtyBitOwnsTheResidualSubsystem says so), so this bit is what the residual-fill
|
||||||
|
// skip consults for the eight fields the record supplies.
|
||||||
constexpr Uint64 kMGPipeWiredSubsystems = kMGPipeSubsystemRenderState |
|
constexpr Uint64 kMGPipeWiredSubsystems = kMGPipeSubsystemRenderState |
|
||||||
kMGPipeSubsystemPixelPack |
|
kMGPipeSubsystemPixelPack |
|
||||||
kMGPipeSubsystemPatchState |
|
kMGPipeSubsystemPatchState |
|
||||||
kMGPipeSubsystemVertexAttribDefaults |
|
kMGPipeSubsystemVertexAttribDefaults |
|
||||||
|
kMGPipeSubsystemResidualValues |
|
||||||
kMGPipeSubsystemResources |
|
kMGPipeSubsystemResources |
|
||||||
kMGPipeSubsystemVertexInput |
|
kMGPipeSubsystemVertexInput |
|
||||||
kMGPipeWiredFramebufferSubsystem |
|
kMGPipeWiredFramebufferSubsystem |
|
||||||
@@ -2097,17 +2107,6 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// (ARCHITECTURE.md 4.6 D5, MGPipeTypes.h). The unpack half has no carrier at all,
|
// (ARCHITECTURE.md 4.6 D5, MGPipeTypes.h). The unpack half has no carrier at all,
|
||||||
// so the field keeps being pulled and the verify comparator keeps proving it.
|
// so the field keeps being pulled and the verify comparator keeps proving it.
|
||||||
//
|
//
|
||||||
// GetCurrentVertexAttribute's three views are NOT bit-identical: GLContext
|
|
||||||
// CONVERTS between them (SetCurrentVertexAttributeFloat writes (Int32)value into
|
|
||||||
// intValue), while MGPipeApplySetVertexAttribDefaults (package A's) memcpys one
|
|
||||||
// Data[4] into all three views and ignores MGPAttribValue::ValueClass. The CLIENT
|
|
||||||
// half of that is fixed - the call now carries the class the frontend actually
|
|
||||||
// wrote and that class's own bytes - but the APPLIER still cannot reproduce the
|
|
||||||
// conversion, so this row stays SHAPE-ONLY: the field keeps being pulled, and
|
|
||||||
// retiring that pull is blocked on A teaching the applier to switch on
|
|
||||||
// ValueClass. EmitVertexAttribDefaults checks rather than trusts, and repairs the
|
|
||||||
// mirror when the applier's write does not reproduce the value.
|
|
||||||
//
|
|
||||||
// GetBoundVertexArray is P3a's row, and Coverage.def asks for the decision to be
|
// GetBoundVertexArray is P3a's row, and Coverage.def asks for the decision to be
|
||||||
// taken HERE, deliberately, rather than inherited from the row's presence. THE
|
// taken HERE, deliberately, rather than inherited from the row's presence. THE
|
||||||
// ANSWER IS NO, and it is not a matter of degree: the field's storage is a
|
// ANSWER IS NO, and it is not a matter of degree: the field's storage is a
|
||||||
@@ -2137,25 +2136,21 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// null on every draw of every push build. What retires them is not a better
|
// null on every draw of every push build. What retires them is not a better
|
||||||
// applier, it is the phase where the backend stops reading a frontend object.
|
// applier, it is the phase where the backend stops reading a frontend object.
|
||||||
//
|
//
|
||||||
// GetMaxTouchedTextureUnit is the sixth and its argument is different, which is
|
// GetMaxTouchedTextureUnit was the sixth and its argument was different - a plain
|
||||||
// why it is written out: it is a plain Int, and set_sampler_views' Count IS that
|
// Int whose carrier (set_sampler_views' Count) is hash-suppressed while the
|
||||||
// value plus one. But the set is SUPPRESSED on an unchanged content hash and is
|
// high-water mark still moves on a redundant re-bind. P5c rv RETIRED it from this
|
||||||
// emitted only when NEW_SAMPLER_VIEWS fires, and that bit's shutter -
|
// list (CONTRACT-P5C.md §5.3): set_context_values carries the mark as a VALUE of
|
||||||
// Mix(textureContent, GetTextureBindGeneration()) - does NOT move on a redundant
|
// its own, whole-record suppressed, so the lag the suppressor could introduce is
|
||||||
// re-bind of the object a unit already holds, while the high-water mark DOES. So
|
// gone and the derivation's RECORD_SUPPLIED answer is honest.
|
||||||
// the applier's Count can lag the frontend's mark by exactly the case the
|
|
||||||
// suppressor exists to swallow, and the field keeps being pulled.
|
|
||||||
constexpr Bool EmittedCallSuppliesTheWholeField(MGPipeInputField field) {
|
constexpr Bool EmittedCallSuppliesTheWholeField(MGPipeInputField field) {
|
||||||
switch (field) {
|
switch (field) {
|
||||||
case MGPipeInputField::GetPixelStoreParameters:
|
case MGPipeInputField::GetPixelStoreParameters:
|
||||||
case MGPipeInputField::GetCurrentVertexAttribute:
|
|
||||||
case MGPipeInputField::GetBoundVertexArray:
|
case MGPipeInputField::GetBoundVertexArray:
|
||||||
case MGPipeInputField::GetFramebufferBindingSlot:
|
case MGPipeInputField::GetFramebufferBindingSlot:
|
||||||
case MGPipeInputField::GetImageTextureBinding:
|
case MGPipeInputField::GetImageTextureBinding:
|
||||||
case MGPipeInputField::GetTextureUnitObject:
|
case MGPipeInputField::GetTextureUnitObject:
|
||||||
case MGPipeInputField::GetProgramForDraw:
|
case MGPipeInputField::GetProgramForDraw:
|
||||||
case MGPipeInputField::GetProgramForDispatch:
|
case MGPipeInputField::GetProgramForDispatch:
|
||||||
case MGPipeInputField::GetMaxTouchedTextureUnit:
|
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
@@ -2175,6 +2170,16 @@ namespace MobileGL::MG_Pipe {
|
|||||||
case MGPipeInputField::GetPatchDefaultOuterLevel:
|
case MGPipeInputField::GetPatchDefaultOuterLevel:
|
||||||
case MGPipeInputField::GetPatchDefaultInnerLevel:
|
case MGPipeInputField::GetPatchDefaultInnerLevel:
|
||||||
case MGPipeInputField::GetCurrentVertexAttribute:
|
case MGPipeInputField::GetCurrentVertexAttribute:
|
||||||
|
// P5c rv's eight: MGPipeApplySetContextValues writes them out of the record,
|
||||||
|
// field for field, through MGPipeApplyAccess::SetContextValues.
|
||||||
|
case MGPipeInputField::GetActiveTextureUnit:
|
||||||
|
case MGPipeInputField::GetMaxTouchedTextureUnit:
|
||||||
|
case MGPipeInputField::GetTouchedBufferBindingPointCount:
|
||||||
|
case MGPipeInputField::IsTransformFeedbackActive:
|
||||||
|
case MGPipeInputField::IsTransformFeedbackPaused:
|
||||||
|
case MGPipeInputField::GetTransformFeedbackGeneration:
|
||||||
|
case MGPipeInputField::GetBoundTransformFeedbackLifetimeId:
|
||||||
|
case MGPipeInputField::GetTransformFeedbackCapturedVertices:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -2256,15 +2261,18 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// when the hash has not moved. That is coalescing rule 4, and this is its one wired
|
// when the hash has not moved. That is coalescing rule 4, and this is its one wired
|
||||||
// consumer in P2.
|
// consumer in P2.
|
||||||
//
|
//
|
||||||
// THE PAYLOAD AND ITS ONE MISSING HALF. A CurrentVertexAttributeValue is one value in
|
// THE PAYLOAD, SINCE P5c rv (CONTRACT-P5C.md §5.3). A CurrentVertexAttributeValue is
|
||||||
// three views, and GLContext CONVERTS between them numerically, so "the bytes of one
|
// one value in three views, and GLContext CONVERTS between them numerically, so "the
|
||||||
// view" is not the value: glVertexAttrib4f(loc, 1.5f, ...) leaves 1 in intValue and
|
// bytes of one view" is not the value: glVertexAttrib4f(loc, 1.5f, ...) leaves 1 in
|
||||||
// 0x3FC00000 in floatValue, and every glVertexAttribI4i/ui is a different pair again.
|
// intValue and 0x3FC00000 in floatValue, and every glVertexAttribI4i/ui is a different
|
||||||
// MGPAttribValue carries ValueClass for exactly this reason, so the client sends the
|
// pair again. MGPAttribValue now carries all three views VERBATIM
|
||||||
// class the frontend actually wrote (GLContext::GetCurrentVertexAttributeClass) and
|
// (FloatView/IntView/UintView) plus the class the frontend actually wrote
|
||||||
// THAT class's own four words. What is still missing is the other half:
|
// (GLContext::GetCurrentVertexAttributeClass), and MGPipeApplySetVertexAttribDefaults
|
||||||
// MGPipeApplySetVertexAttribDefaults (package A's file) memcpys the four words into
|
// writes each view from its own array - the cross-view conversion's authoritative
|
||||||
// all three views regardless of ValueClass, which cannot reproduce the conversion.
|
// answer is the client's, and the applier no longer reconverts anything. The pre-rv
|
||||||
|
// shape (one Data[4] memcpied into all three views, ValueClass ignored) is exactly
|
||||||
|
// what kept this row EMITTED-AND-STILL-PULLED in EmittedCallSuppliesTheWholeField;
|
||||||
|
// with the applier fixed, the field is RECORD_SUPPLIED outright.
|
||||||
//
|
//
|
||||||
// The suppressing memcmp below is over the three VIEWS only, and that is not an
|
// The suppressing memcmp below is over the three VIEWS only, and that is not an
|
||||||
// oversight: the class decides how the views are REBUILT, so two writes that leave
|
// oversight: the class decides how the views are REBUILT, so two writes that leave
|
||||||
@@ -2277,8 +2285,9 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// and says so once. That is what keeps the block correct in the window this call used
|
// and says so once. That is what keeps the block correct in the window this call used
|
||||||
// to corrupt - a glVertexAttrib4f followed by a non-kDraw verb, where the residual
|
// to corrupt - a glVertexAttrib4f followed by a non-kDraw verb, where the residual
|
||||||
// fill does not run for this field and nothing else would have put the value back.
|
// fill does not run for this field and nothing else would have put the value back.
|
||||||
// The day the applier honours ValueClass the compare stops failing and the repair
|
// Since rv the applier writes all three views verbatim, so the compare below is
|
||||||
// stops happening, with no edit here.
|
// expected to pass on every emission; it stays armed because it is the one observable
|
||||||
|
// of that write being verbatim in a window no other gate looks at.
|
||||||
Uint64 g_attribDefaultRepairs = 0;
|
Uint64 g_attribDefaultRepairs = 0;
|
||||||
|
|
||||||
// The header of the last set_vertex_attrib_defaults that actually went out. Count == 0
|
// The header of the last set_vertex_attrib_defaults that actually went out. Count == 0
|
||||||
@@ -2349,14 +2358,73 @@ namespace MobileGL::MG_Pipe {
|
|||||||
}
|
}
|
||||||
if (!reproduced) {
|
if (!reproduced) {
|
||||||
++g_attribDefaultRepairs;
|
++g_attribDefaultRepairs;
|
||||||
MGLOG_W_ONCE("MGPipe: MGPipeApplySetVertexAttribDefaults does not reproduce the "
|
MGLOG_W_ONCE("MGPipe: MGPipeApplySetVertexAttribDefaults did not reproduce the "
|
||||||
"carried value on this build (it ignores MGPAttribValue::ValueClass) "
|
"carried three views on this build - the client is keeping "
|
||||||
"- the client is keeping m_currentVertexAttribute authoritative");
|
"m_currentVertexAttribute authoritative");
|
||||||
MGPipeFillAccess::CopyField(gPipeInputs, ctx, MGPipeInputField::GetCurrentVertexAttribute);
|
MGPipeFillAccess::CopyField(gPipeInputs, ctx, MGPipeInputField::GetCurrentVertexAttribute);
|
||||||
}
|
}
|
||||||
return sizeof(MGPVertexAttribDefaults) + header.Count * sizeof(MGPAttribValue);
|
return sizeof(MGPVertexAttribDefaults) + header.Count * sizeof(MGPAttribValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
|
// set_context_values (P5c rv, CONTRACT-P5C.md §5.3): the residual-value record. One
|
||||||
|
// POD carrying every value-class field no other set_* supplies - the two texture-unit
|
||||||
|
// counters, the 15 per-target touched-buffer-binding counts and the five XFB values -
|
||||||
|
// emitted at validate WHEN ANY COVERED VALUE MOVED, which the whole-record hash says:
|
||||||
|
// there is deliberately no dirty bit for the family (the tracker's value-class dirty
|
||||||
|
// accounting is untouched - "零新增记账", ARCHITECTURE.md 5.2) and no dirty mask in the
|
||||||
|
// payload, so a suppressed record means "nothing moved", never "field invalid" (§1).
|
||||||
|
//
|
||||||
|
// THE PRODUCER IS TRANSPORT-GATED, and the residual-fill skip for the same eight fields
|
||||||
|
// is gated on the same answer (MGPipeValidateForVerb's contextValuesWireLive): under
|
||||||
|
// monolith - or with a transport configured but no live session (the bring-up window, a
|
||||||
|
// server-role-only fixture) - nothing is emitted and the fields keep being pulled, byte
|
||||||
|
// for byte as before (G1).
|
||||||
|
Uint64 EmitContextValues(GLContext& ctx) {
|
||||||
|
MGPContextValues values{};
|
||||||
|
values.ActiveTextureUnit = static_cast<Uint32>(ctx.GetActiveTextureUnit());
|
||||||
|
values.MaxTouchedTextureUnit = static_cast<Uint32>(ctx.GetMaxTouchedTextureUnit());
|
||||||
|
// The array is indexed by BufferTarget value, all 15 of them (MGPipeTypes.h);
|
||||||
|
// targets with no binding points answer 0 (BufferState::GetTouchedBindPointCount).
|
||||||
|
static_assert(
|
||||||
|
std::extent_v<decltype(MGPContextValues::TouchedBufferBindingPointCount)> ==
|
||||||
|
static_cast<SizeT>(BufferTarget::BufferTargetCount),
|
||||||
|
"MGPContextValues' per-target array and BufferTargetCount have drifted");
|
||||||
|
for (Uint32 t = 0; t < static_cast<Uint32>(BufferTarget::BufferTargetCount); ++t) {
|
||||||
|
values.TouchedBufferBindingPointCount[t] =
|
||||||
|
static_cast<Uint32>(ctx.GetTouchedBufferBindingPointCount(static_cast<BufferTarget>(t)));
|
||||||
|
}
|
||||||
|
values.IsTransformFeedbackActive = ctx.IsTransformFeedbackActive() ? 1 : 0;
|
||||||
|
values.IsTransformFeedbackPaused = ctx.IsTransformFeedbackPaused() ? 1 : 0;
|
||||||
|
values.TransformFeedbackGeneration = ctx.GetTransformFeedbackGeneration();
|
||||||
|
values.BoundTransformFeedbackLifetimeId = ctx.GetBoundTransformFeedbackLifetimeId();
|
||||||
|
values.TransformFeedbackCapturedVertices = ctx.GetTransformFeedbackCapturedVertices();
|
||||||
|
// The whole record is the hash input, padding included - `values{}` zeroes it, so
|
||||||
|
// the pad bytes are defined and the hash is stable.
|
||||||
|
const Uint64 contentHash = XXH64(&values, sizeof(values), 0);
|
||||||
|
if (!MGPipeSetHashSuppressorInstance().ShouldEmit(MGPipeSuppressorSlot::SetContextValues,
|
||||||
|
contentHash)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MGPipeRouteSetContextValues(values);
|
||||||
|
return sizeof(MGPContextValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The fields set_context_values supplies. A validate whose verb class reads NONE of
|
||||||
|
// them skips the record build entirely - the record exists so a verb's reads are
|
||||||
|
// answered, and a verb that never reads them needs no publication.
|
||||||
|
constexpr Bool VerbMaskReadsContextValues(const MGPipeFieldMask& mask) {
|
||||||
|
return MGPipeFieldMaskHas(mask, MGPipeInputField::GetActiveTextureUnit) ||
|
||||||
|
MGPipeFieldMaskHas(mask, MGPipeInputField::GetMaxTouchedTextureUnit) ||
|
||||||
|
MGPipeFieldMaskHas(mask, MGPipeInputField::GetTouchedBufferBindingPointCount) ||
|
||||||
|
MGPipeFieldMaskHas(mask, MGPipeInputField::IsTransformFeedbackActive) ||
|
||||||
|
MGPipeFieldMaskHas(mask, MGPipeInputField::IsTransformFeedbackPaused) ||
|
||||||
|
MGPipeFieldMaskHas(mask, MGPipeInputField::GetTransformFeedbackGeneration) ||
|
||||||
|
MGPipeFieldMaskHas(mask, MGPipeInputField::GetBoundTransformFeedbackLifetimeId) ||
|
||||||
|
MGPipeFieldMaskHas(mask, MGPipeInputField::GetTransformFeedbackCapturedVertices);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// set_residual_value_state (P2 brief D9, ARCHITECTURE.md 9.4).
|
// set_residual_value_state (P2 brief D9, ARCHITECTURE.md 9.4).
|
||||||
//
|
//
|
||||||
@@ -2669,6 +2737,19 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// emission the server refuses is an emission whose acceptance already cleared a frontend
|
// emission the server refuses is an emission whose acceptance already cleared a frontend
|
||||||
// dirty flag the legacy arm still owed. Same table, same four families, one place.
|
// dirty flag the legacy arm still owed. Same table, same four families, one place.
|
||||||
const Uint64 pushMask = MG_Config::Features.PipePush;
|
const Uint64 pushMask = MG_Config::Features.PipePush;
|
||||||
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3): set_context_values is the carrier for the eight
|
||||||
|
// value-class fields ONLY with a live wire. ONE answer gates both halves - the emission
|
||||||
|
// below and the residual-fill skip in step 4 - so they can never disagree about who
|
||||||
|
// supplies a field: with no live session (a monolith transport, the bring-up window, a
|
||||||
|
// server-role-only fixture) nothing is emitted and the fields keep being pulled, byte
|
||||||
|
// for byte as before (G1).
|
||||||
|
const Bool contextValuesWireLive =
|
||||||
|
MG_Config::Transport != MG_Config::TransportMode::Monolith &&
|
||||||
|
MG_Remote::Client::ContextValuesWireLive();
|
||||||
|
#else
|
||||||
|
constexpr Bool contextValuesWireLive = false;
|
||||||
|
#endif
|
||||||
const auto wants = [&](MGPipeDirty bit) {
|
const auto wants = [&](MGPipeDirty bit) {
|
||||||
const Uint64 subsystem = MGPipeSubsystemForDirty(bit);
|
const Uint64 subsystem = MGPipeSubsystemForDirty(bit);
|
||||||
return subsystem != 0 && (pushMask & subsystem) != 0 &&
|
return subsystem != 0 && (pushMask & subsystem) != 0 &&
|
||||||
@@ -2808,6 +2889,19 @@ namespace MobileGL::MG_Pipe {
|
|||||||
payloadBytes += EmitVertexAttribDefaults(*ctx, tracker.FreshlyPrimed());
|
payloadBytes += EmitVertexAttribDefaults(*ctx, tracker.FreshlyPrimed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3): the residual-value record, emitted when any covered
|
||||||
|
// value moved. THE GATE IS THE SUBSYSTEM BIT PLUS THE WIRE BEING LIVE - the family has
|
||||||
|
// no dirty bit (NoDirtyBitOwnsTheResidualSubsystem) and no P4a consumer predicate (it
|
||||||
|
// is not one of the four families), and the "did anything move" question is the
|
||||||
|
// whole-record hash inside EmitContextValues. The class-mask test skips the build for
|
||||||
|
// verbs that read none of the eight fields.
|
||||||
|
if (contextValuesWireLive && (pushMask & kMGPipeSubsystemResidualValues) != 0 &&
|
||||||
|
VerbMaskReadsContextValues(mask)) {
|
||||||
|
payloadBytes += EmitContextValues(*ctx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// P3a's vertex segment, in the order the design fixes: vertex elements, then the
|
// P3a's vertex segment, in the order the design fixes: vertex elements, then the
|
||||||
// vertex buffers that fill them, then the index binding. All three are LIVE now (m1):
|
// vertex buffers that fill them, then the index binding. All three are LIVE now (m1):
|
||||||
// bits 5 / 9 / 10 map onto kMGPipeSubsystemVertexInput in Tracker.h:145-148 and all
|
// bits 5 / 9 / 10 map onto kMGPipeSubsystemVertexInput in Tracker.h:145-148 and all
|
||||||
@@ -2857,12 +2951,20 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// FIELD, and on a backend with no consumer - or at a mask that leaves one of the
|
// FIELD, and on a backend with no consumer - or at a mask that leaves one of the
|
||||||
// family's D-K2 dependency bits clear - no P4a call went out at all, so withholding
|
// family's D-K2 dependency bits clear - no P4a call went out at all, so withholding
|
||||||
// the pull here would leave the field unfilled at the very verb that reads it.
|
// the pull here would leave the field unfilled at the very verb that reads it.
|
||||||
|
//
|
||||||
|
// AND THE LAST CONJUNCT IS P5c rv's (CONTRACT-P5C.md §5.3): set_context_values has
|
||||||
|
// NO PRODUCER without a live wire (its emission is transport-gated, above), so its
|
||||||
|
// eight fields keep being pulled under monolith - G1's byte-for-byte rule - and are
|
||||||
|
// skipped only when the record really crosses. The two sides read the ONE answer
|
||||||
|
// computed at the top of this function, so they cannot disagree.
|
||||||
const Bool supplied = subsystem != 0 && (subsystem & kMGPipeWiredSubsystems) != 0 &&
|
const Bool supplied = subsystem != 0 && (subsystem & kMGPipeWiredSubsystems) != 0 &&
|
||||||
(pushMask & subsystem) != 0 &&
|
(pushMask & subsystem) != 0 &&
|
||||||
P4aFamilyHasItsConsumer(subsystem) &&
|
P4aFamilyHasItsConsumer(subsystem) &&
|
||||||
P4aFamilyDependenciesAreSet(subsystem, pushMask) &&
|
P4aFamilyDependenciesAreSet(subsystem, pushMask) &&
|
||||||
EmittedCallSuppliesTheWholeField(field) &&
|
EmittedCallSuppliesTheWholeField(field) &&
|
||||||
(applierDerives || AppliedWithoutDerivation(field));
|
(applierDerives || AppliedWithoutDerivation(field)) &&
|
||||||
|
(emitter != MGPipeFieldEmitter::SetContextValues ||
|
||||||
|
contextValuesWireLive);
|
||||||
if (!supplied) MGPipeFillAccess::CopyField(inputs, *ctx, field);
|
if (!supplied) MGPipeFillAccess::CopyField(inputs, *ctx, field);
|
||||||
#if MOBILEGL_PIPE_POISON
|
#if MOBILEGL_PIPE_POISON
|
||||||
// The value is copied either way; only the stamp is withheld for the omitted pair.
|
// The value is copied either way; only the stamp is withheld for the omitted pair.
|
||||||
|
|||||||
@@ -113,8 +113,10 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// (EmitVertexAttribDefaults). It is the ONE observable of that repair: the window it
|
// (EmitVertexAttribDefaults). It is the ONE observable of that repair: the window it
|
||||||
// covers is a verb whose class does not read m_currentVertexAttribute, where reading the
|
// covers is a verb whose class does not read m_currentVertexAttribute, where reading the
|
||||||
// storage to check it would be the poison violation the fill table exists to forbid. So
|
// storage to check it would be the poison violation the fill table exists to forbid. So
|
||||||
// TrackerShippedEmitter asserts on this counter instead, and the day package A's applier
|
// TrackerShippedEmitter asserts on this counter instead. Since P5c rv the record carries
|
||||||
// switches on MGPAttribValue::ValueClass the counter stops moving.
|
// all three views verbatim (CONTRACT-P5C.md §5.3) and the applier writes each from its own
|
||||||
|
// array, so the counter is expected to stay at 0 - the check that increments it is the
|
||||||
|
// trip wire that remains.
|
||||||
//
|
//
|
||||||
// Not hot-path instrumentation: it is incremented only inside the repair branch, which
|
// Not hot-path instrumentation: it is incremented only inside the repair branch, which
|
||||||
// runs only when the call actually went out, which is only when an attribute default
|
// runs only when the call actually went out, which is only when an attribute default
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// One slot per kVarTail set_* (ARCHITECTURE.md 5.1's call list), PLUS
|
// One slot per kVarTail set_* (ARCHITECTURE.md 5.1's call list), PLUS
|
||||||
// SetFramebufferState, which is not kVarTail at all: MGPFramebufferState carries a
|
// SetFramebufferState, which is not kVarTail at all: MGPFramebufferState carries a
|
||||||
// ContentHash for TWO jobs - the server's render-pass memo key and the client's emission
|
// ContentHash for TWO jobs - the server's render-pass memo key and the client's emission
|
||||||
// suppressor - and the second one needs a slot here like any other. The enum is
|
// suppressor - and the second one needs a slot here like any other, PLUS
|
||||||
|
// SetContextValues (P5c rv), also not kVarTail: one fixed-width POD whose whole-record
|
||||||
|
// hash is the "did any covered value move" answer. The enum is
|
||||||
// CLIENT-ONLY and is not a wire opcode, so appending before Count is safe.
|
// CLIENT-ONLY and is not a wire opcode, so appending before Count is safe.
|
||||||
enum class MGPipeSuppressorSlot : Uint32 {
|
enum class MGPipeSuppressorSlot : Uint32 {
|
||||||
SetVertexBuffers = 0, // P3a - wired, and its hash includes BaseInstance
|
SetVertexBuffers = 0, // P3a - wired, and its hash includes BaseInstance
|
||||||
@@ -64,6 +66,12 @@ namespace MobileGL::MG_Pipe {
|
|||||||
SetStreamOutputTargets, // P4b
|
SetStreamOutputTargets, // P4b
|
||||||
SetVertexAttribDefaults, // P2 - the one consumer that is wired
|
SetVertexAttribDefaults, // P2 - the one consumer that is wired
|
||||||
SetFramebufferState, // P4a - wired
|
SetFramebufferState, // P4a - wired
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3). NOT kVarTail either - the same shape as
|
||||||
|
// SetFramebufferState's note: MGPContextValues is one fixed-width POD, and the
|
||||||
|
// whole-record hash IS its "did any covered value move" answer (there is deliberately
|
||||||
|
// no dirty mask in the payload - a suppressed record means "nothing moved", never
|
||||||
|
// "field invalid").
|
||||||
|
SetContextValues, // P5c rv - wired, split+transport only (PipeFill.cpp gates)
|
||||||
Count,
|
Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -821,31 +821,30 @@ namespace MobileGL::MG_Pipe {
|
|||||||
Uint64 m_walks[kMGPipeVerbClassCount]{};
|
Uint64 m_walks[kMGPipeVerbClassCount]{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// ONE attribute default, flattened onto the wire (P2 brief D10). A named function rather
|
// ONE attribute default, flattened onto the wire (P2 brief D10, AMENDED at P5c rv). A
|
||||||
// than four lines inside the emitter because this flattening is the whole correctness
|
// named function rather than four lines inside the emitter because this flattening is the
|
||||||
// question of set_vertex_attrib_defaults: a CurrentVertexAttributeValue is one value in
|
// whole correctness question of set_vertex_attrib_defaults: a CurrentVertexAttributeValue
|
||||||
// three views and GLContext converts NUMERICALLY between them, so four words alone are
|
// is one value in three views and GLContext converts NUMERICALLY between them, so four
|
||||||
// not the value - glVertexAttrib4f(loc, 1.5f, ...) leaves 1 in intValue and 0x3FC00000 in
|
// words alone are not the value - glVertexAttrib4f(loc, 1.5f, ...) leaves 1 in intValue
|
||||||
// floatValue. MGPAttribValue::ValueClass is what makes the four words readable again, and
|
// and 0x3FC00000 in floatValue. Since rv the record carries ALL THREE VIEWS VERBATIM
|
||||||
// TrackerAttribPayload pins that here instead of leaving it to the emitter's shape.
|
// (MGPAttribValue::FloatView/IntView/UintView, CONTRACT-P5C.md §5.3) and the applier writes
|
||||||
|
// each view from its own array; ValueClass is the record of which view the application
|
||||||
|
// wrote directly, kept for the comparator and for readers - the applier no longer needs
|
||||||
|
// it to rebuild anything.
|
||||||
inline void MGPipeFillAttribValue(Uint32 location,
|
inline void MGPipeFillAttribValue(Uint32 location,
|
||||||
const MG_State::GLState::CurrentVertexAttributeValue& value,
|
const MG_State::GLState::CurrentVertexAttributeValue& value,
|
||||||
Uint32 writtenClass, MGPAttribValue& out) {
|
Uint32 writtenClass, MGPAttribValue& out) {
|
||||||
out = MGPAttribValue{};
|
out = MGPAttribValue{};
|
||||||
out.Location = location;
|
out.Location = location;
|
||||||
out.ValueClass = static_cast<Uint8>(writtenClass);
|
out.ValueClass = static_cast<Uint8>(writtenClass);
|
||||||
static_assert(sizeof(out.Data) == sizeof(value.floatValue), "MGPAttribValue::Data is four words");
|
static_assert(sizeof(out.FloatView) == sizeof(value.floatValue),
|
||||||
switch (writtenClass) {
|
"MGPAttribValue's views are four words each");
|
||||||
case MG_State::GLState::kVertexAttribValueClassInt:
|
static_assert(sizeof(out.IntView) == sizeof(value.intValue) &&
|
||||||
std::memcpy(out.Data, value.intValue.data(), sizeof(out.Data));
|
sizeof(out.UintView) == sizeof(value.uintValue),
|
||||||
break;
|
"MGPAttribValue's views are four words each");
|
||||||
case MG_State::GLState::kVertexAttribValueClassUint:
|
std::memcpy(out.FloatView, value.floatValue.data(), sizeof(out.FloatView));
|
||||||
std::memcpy(out.Data, value.uintValue.data(), sizeof(out.Data));
|
std::memcpy(out.IntView, value.intValue.data(), sizeof(out.IntView));
|
||||||
break;
|
std::memcpy(out.UintView, value.uintValue.data(), sizeof(out.UintView));
|
||||||
default:
|
|
||||||
std::memcpy(out.Data, value.floatValue.data(), sizeof(out.Data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The monolith's one tracker. Under split there is one per client context; the context
|
// The monolith's one tracker. Under split there is one per client context; the context
|
||||||
|
|||||||
@@ -212,33 +212,36 @@
|
|||||||
// mirrors null on every draw of every push build. What retires those pulls is not a better
|
// mirrors null on every draw of every push build. What retires those pulls is not a better
|
||||||
// applier, it is the phase where the backend stops reading a frontend object at all.
|
// applier, it is the phase where the backend stops reading a frontend object at all.
|
||||||
//
|
//
|
||||||
// THE SIXTH IS A DIFFERENT ARGUMENT AND IT IS WORTH WRITING DOWN, because it looks like the
|
// THE SIXTH left that arm at P5c rv: GetMaxTouchedTextureUnit is a plain Int whose problem was
|
||||||
// easy one. GetMaxTouchedTextureUnit is a plain Int, and set_sampler_views' Count IS that
|
// never shape, it was the CARRIER - set_sampler_views' Count is the set's window, and the set
|
||||||
// value plus one (the second merge rule: a high-water mark is directly the count argument).
|
// is suppressed on an unchanged content hash while the high-water mark still moves on a
|
||||||
// But the set is SUPPRESSED on an unchanged content hash and is emitted only when bit 12 fires,
|
// redundant re-bind. set_context_values (CONTRACT-P5C.md §5.3) carries the mark as a VALUE of
|
||||||
// and bit 12's shutter is Mix(textureContent, GetTextureBindGeneration()) - which does NOT
|
// its own, whole-record suppressed, so the mark rides an unsuppressed field and the row is
|
||||||
// move on a redundant re-bind of the object a unit already holds, while the high-water mark
|
// RECORD_SUPPLIED outright.
|
||||||
// DOES (see NoteUnitTouched in DirtySurface.def). So the applier's Count can lag the frontend's
|
|
||||||
// high-water mark by exactly the case the suppressor exists to swallow, and the field keeps
|
|
||||||
// being pulled. Narrowing that is P3b/P4b's, with the backend debounce it takes over.
|
|
||||||
//
|
//
|
||||||
// FOUR ACCESSORS THAT MAP TO A P4a CALL ARE DELIBERATELY NOT HERE, for GetPixelStoreParameters'
|
// P5c rv ADDS EIGHT ROWS, and they are the whole of the value-class debt that was left
|
||||||
// reason - a row here says "this field is supplied", and for these it would be a half-truth:
|
// (CONTRACT-P5C.md §5.3): seven residual values no set_* call carried - the two texture-unit
|
||||||
// GetActiveTextureUnit - glActiveTexture's selector. set_sampler_views carries the RESOLVED
|
// counters, the 15-target touched-count array and the five transform-feedback values - plus
|
||||||
// per-unit set and no active-unit selector at all; nothing on the wire carries it.
|
// GetMaxTouchedTextureUnit re-homed from SetSamplerViews. All eight name SetContextValues, one
|
||||||
// GetTextureContextId - a context identity the backend keys its own tables on. No call
|
// POD emitted at validate when any covered value moved, hash-suppressed whole. The OBJECT rows
|
||||||
// carries it and none should: it is the server's question about the client, not state.
|
// (GetTextureUnitObject and its four P4a siblings above) stay BARRIER_PULLED with their
|
||||||
// GetTextureBindGeneration / GetSamplingResolutionGeneration - frontend SHUTTERS. What
|
// retiring phases; the three texture shutters (below) take no row here either - they carry no
|
||||||
// replaces them server-side is the applier's own Serial, which is a different value with a
|
// wire value at all, the accessors answer the applier's own Serial.
|
||||||
// different owner; claiming the sets supply the generations would make the fill loop skip
|
//
|
||||||
// two counters no record carries.
|
// GetTextureContextId / GetTextureBindGeneration / GetSamplingResolutionGeneration stay out
|
||||||
|
// DELIBERATELY, and the reason is ownership rather than coverage: they are frontend SHUTTERS,
|
||||||
|
// and what replaces them server-side is the applier's own Serial - a different value with a
|
||||||
|
// different owner. A row here would claim the sets supply the generations, and the fill loop
|
||||||
|
// would skip two counters no record carries.
|
||||||
// And GetTextureObject / GetProgramObject are STICKY (see MGP_COVERAGE_STICKY_LIST): they are
|
// And GetTextureObject / GetProgramObject are STICKY (see MGP_COVERAGE_STICKY_LIST): they are
|
||||||
// keyed by GL name, they are object lookups rather than verb state, and a forwarded field has
|
// keyed by GL name, they are object lookups rather than verb state, and a forwarded field has
|
||||||
// no storage for an emitted call to supply.
|
// no storage for an emitted call to supply.
|
||||||
#define MGP_COVERAGE_EMITTED_LIST(X) \
|
#define MGP_COVERAGE_EMITTED_LIST(X) \
|
||||||
|
X(GetActiveTextureUnit, SetContextValues) \
|
||||||
X(GetBlendColor, SetDynamicState) \
|
X(GetBlendColor, SetDynamicState) \
|
||||||
X(GetBlendEquationIndexed, CreateRenderState) \
|
X(GetBlendEquationIndexed, CreateRenderState) \
|
||||||
X(GetBlendFuncIndexed, CreateRenderState) \
|
X(GetBlendFuncIndexed, CreateRenderState) \
|
||||||
|
X(GetBoundTransformFeedbackLifetimeId, SetContextValues) \
|
||||||
X(GetBoundVertexArray, BindVertexElements) \
|
X(GetBoundVertexArray, BindVertexElements) \
|
||||||
X(GetClampReadColor, SetDynamicState) \
|
X(GetClampReadColor, SetDynamicState) \
|
||||||
X(GetClearColor, SetDynamicState) \
|
X(GetClearColor, SetDynamicState) \
|
||||||
@@ -254,7 +257,7 @@
|
|||||||
X(GetImageTextureBinding, SetShaderImages) \
|
X(GetImageTextureBinding, SetShaderImages) \
|
||||||
X(GetLineWidth, SetDynamicState) \
|
X(GetLineWidth, SetDynamicState) \
|
||||||
X(GetLogicOp, CreateRenderState) \
|
X(GetLogicOp, CreateRenderState) \
|
||||||
X(GetMaxTouchedTextureUnit, SetSamplerViews) \
|
X(GetMaxTouchedTextureUnit, SetContextValues) \
|
||||||
X(GetMinSampleShadingValue, CreateRenderState) \
|
X(GetMinSampleShadingValue, CreateRenderState) \
|
||||||
X(GetPatchDefaultInnerLevel, SetPatchState) \
|
X(GetPatchDefaultInnerLevel, SetPatchState) \
|
||||||
X(GetPatchDefaultOuterLevel, SetPatchState) \
|
X(GetPatchDefaultOuterLevel, SetPatchState) \
|
||||||
@@ -272,9 +275,14 @@
|
|||||||
X(GetScissorBox, SetDynamicState) \
|
X(GetScissorBox, SetDynamicState) \
|
||||||
X(GetStencilState, CreateRenderState) \
|
X(GetStencilState, CreateRenderState) \
|
||||||
X(GetTextureUnitObject, SetSamplerViews) \
|
X(GetTextureUnitObject, SetSamplerViews) \
|
||||||
|
X(GetTouchedBufferBindingPointCount, SetContextValues) \
|
||||||
|
X(GetTransformFeedbackCapturedVertices, SetContextValues) \
|
||||||
|
X(GetTransformFeedbackGeneration, SetContextValues) \
|
||||||
X(GetViewport, SetDynamicState) \
|
X(GetViewport, SetDynamicState) \
|
||||||
X(GetViewportIndexed, SetDynamicState) \
|
X(GetViewportIndexed, SetDynamicState) \
|
||||||
X(IsCapabilityEnabled, CreateRenderState) \
|
X(IsCapabilityEnabled, CreateRenderState) \
|
||||||
X(IsCapabilityEnabledIndexed, CreateRenderState)
|
X(IsCapabilityEnabledIndexed, CreateRenderState) \
|
||||||
|
X(IsTransformFeedbackActive, SetContextValues) \
|
||||||
|
X(IsTransformFeedbackPaused, SetContextValues)
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
// the client for it. THIS CLASS IS DERIVED, NOT LISTED: it is
|
// the client for it. THIS CLASS IS DERIVED, NOT LISTED: it is
|
||||||
// kMGPipeFieldEmittedBy != kNone (Coverage.def's MGP_COVERAGE_EMITTED_LIST)
|
// kMGPipeFieldEmittedBy != kNone (Coverage.def's MGP_COVERAGE_EMITTED_LIST)
|
||||||
// minus the fields EmittedCallSuppliesTheWholeField refuses
|
// minus the fields EmittedCallSuppliesTheWholeField refuses
|
||||||
// (MG_Impl/Pipe/PipeFill.cpp). 32 fields today. A row below that names a
|
// (MG_Impl/Pipe/PipeFill.cpp). 41 fields since P5c rv (32 before it). A row
|
||||||
|
// below that names a
|
||||||
// field the derivation already placed here is a CONTRADICTION and stops
|
// field the derivation already placed here is a CONTRADICTION and stops
|
||||||
// the generator - which is the only way this file can stay true as the
|
// the generator - which is the only way this file can stay true as the
|
||||||
// emitted list grows.
|
// emitted list grows.
|
||||||
@@ -50,14 +51,20 @@
|
|||||||
// whose row stops the pull. It is a string, not an enum, because two of them name two
|
// whose row stops the pull. It is a string, not an enum, because two of them name two
|
||||||
// phases for the two backends and flattening that would lose the half that matters.
|
// phases for the two backends and flattening that would lose the half that matters.
|
||||||
#define MGP_FIELD_OWNERSHIP_LIST(X) \
|
#define MGP_FIELD_OWNERSHIP_LIST(X) \
|
||||||
/* ---- BARRIER_PULLED: the 20 non-sticky rows the reduced path actually reads ---- */ \
|
/* ---- BARRIER_PULLED: the 9 non-sticky rows the reduced path actually reads ---- */ \
|
||||||
/* scout-unmigrated-census section 3 intersects each verb class's may-read mask with "no */ \
|
/* scout-unmigrated-census section 3 intersects each verb class's may-read mask with "no */ \
|
||||||
/* record supplies it" and unions kClear (7 of 18), kDraw (19 of 47) and kReadback (12 of */ \
|
/* record supplies it" and unions kClear (7 of 18), kDraw (19 of 47) and kReadback (12 of */ \
|
||||||
/* 17). That union is 21 fields; GetPixelStoreParameters is the 21st and it is */ \
|
/* 17). That union was 21 fields at P5; P5c rv (CONTRACT-P5C.md §5.3) retired NINE of them */ \
|
||||||
/* APPLIER_DERIVED below, for the reason written there. OpenRA adds no field to this set - */ \
|
/* to RECORD_SUPPLIED through set_context_values (the two texture-unit counters, the */ \
|
||||||
/* it widens the SITE set, not the field set. */ \
|
/* touched-count array, the five XFB values) plus GetCurrentVertexAttribute (the amended */ \
|
||||||
X(GetActiveTextureUnit, BARRIER_PULLED, "P3b/P4b", \
|
/* set_vertex_attrib_defaults payload), and moved the three texture SHUTTERS to */ \
|
||||||
"the server answers from its own state; Coverage.def:215-219 says no call carries it") \
|
/* APPLIER_DERIVED (their own rows said it since P5: "a shutter, not a value: the server */ \
|
||||||
|
/* answers from its own Serial" - rv made the accessor DO it). GetPixelStoreParameters is */ \
|
||||||
|
/* the 21st of the census and it is APPLIER_DERIVED below, for the reason written there. */ \
|
||||||
|
/* WHAT IS LEFT IS EXACTLY THE OBJECT CLASS: nine fields whose storage is a frontend heap */ \
|
||||||
|
/* reference no record can carry, each with the phase that retires it, and */ \
|
||||||
|
/* FieldOwnershipTest pins this list as ALL the remaining non-sticky rows. OpenRA adds no */ \
|
||||||
|
/* field to this set - it widens the SITE set, not the field set. */ \
|
||||||
/* DirectGLES.cpp:4486, PrepareForDraw, UNCONDITIONAL ON EVERY DRAW. No #if, no arm guard, */ \
|
/* DirectGLES.cpp:4486, PrepareForDraw, UNCONDITIONAL ON EVERY DRAW. No #if, no arm guard, */ \
|
||||||
/* no record fallback, and PipeFill.cpp:1902-1905 says outright that what retires the pull */ \
|
/* no record fallback, and PipeFill.cpp:1902-1905 says outright that what retires the pull */ \
|
||||||
/* is P8, not a better applier: the storage is a SharedPtr<VertexArrayObject> and */ \
|
/* is P8, not a better applier: the storage is a SharedPtr<VertexArrayObject> and */ \
|
||||||
@@ -72,14 +79,6 @@
|
|||||||
"7 of 15 BufferTargets have no call; the field is one array over all 15") \
|
"7 of 15 BufferTargets have no call; the field is one array over all 15") \
|
||||||
X(GetBufferBindingPoint, BARRIER_PULLED, "P3b/P4b, P7", \
|
X(GetBufferBindingPoint, BARRIER_PULLED, "P3b/P4b, P7", \
|
||||||
"frontend BindingSlotRange1D pointer") \
|
"frontend BindingSlotRange1D pointer") \
|
||||||
X(GetTouchedBufferBindingPointCount, BARRIER_PULLED, "P3b/P4b", \
|
|
||||||
"no call carries the touched-count high-water mark") \
|
|
||||||
/* The applier CANNOT reproduce GLContext's cross-view conversion: the frontend writes */ \
|
|
||||||
/* (Int32)value into intValue while MGPipeApplySetVertexAttribDefaults memcpys one Data[4] */ \
|
|
||||||
/* into all three views (PipeFill.cpp:1884-1896). So the record exists, the applier writes */ \
|
|
||||||
/* the field, and the value is still wrong - which is BARRIER_PULLED, not APPLIER_DERIVED. */ \
|
|
||||||
X(GetCurrentVertexAttribute, BARRIER_PULLED, "P3b/P4b", \
|
|
||||||
"the applier writes it but cannot reproduce the cross-view conversion") \
|
|
||||||
/* 8 Espryt sites through GetFramebufferBindingSlotChecked + 13 Magma. SyncCurrentFBO */ \
|
/* 8 Espryt sites through GetFramebufferBindingSlotChecked + 13 Magma. SyncCurrentFBO */ \
|
||||||
/* (:2995) is SELF-DECLARED monolith glue (DirectGLES.cpp:2961-2965) while BindCurrentFBO */ \
|
/* (:2995) is SELF-DECLARED monolith glue (DirectGLES.cpp:2961-2965) while BindCurrentFBO */ \
|
||||||
/* (:4303-4353) is already split-clean - the bind is migrated, the sync is not. */ \
|
/* (:4303-4353) is already split-clean - the bind is migrated, the sync is not. */ \
|
||||||
@@ -87,19 +86,6 @@
|
|||||||
"frontend BindingSlot<FramebufferObject> pointer") \
|
"frontend BindingSlot<FramebufferObject> pointer") \
|
||||||
X(GetImageTextureBinding, BARRIER_PULLED, "P3b/P4b, P7", \
|
X(GetImageTextureBinding, BARRIER_PULLED, "P3b/P4b, P7", \
|
||||||
"frontend ImageTextureBinding base pointer") \
|
"frontend ImageTextureBinding base pointer") \
|
||||||
/* set_sampler_views' Count IS this value plus one, but the set is suppressed on an */ \
|
|
||||||
/* unchanged content hash while the high-water mark still moves (PipeFill.cpp:1917-1923). */ \
|
|
||||||
X(GetMaxTouchedTextureUnit, BARRIER_PULLED, "P3b/P4b", \
|
|
||||||
"hash-suppressed set, high-water mark still moves") \
|
|
||||||
/* The three texture SHUTTERS. Coverage.def:220-224 is explicit that no call carries them */ \
|
|
||||||
/* and none should: what replaces them server-side is the applier's own Serial, a different */ \
|
|
||||||
/* value with a different owner. So these are not values to migrate. */ \
|
|
||||||
X(GetSamplingResolutionGeneration, BARRIER_PULLED, "P3b/P4b", \
|
|
||||||
"a shutter, not a value: the server answers from its own Serial") \
|
|
||||||
X(GetTextureBindGeneration, BARRIER_PULLED, "P3b/P4b", \
|
|
||||||
"a shutter, not a value: the server answers from its own Serial") \
|
|
||||||
X(GetTextureContextId, BARRIER_PULLED, "P3b/P4b", \
|
|
||||||
"a shutter, not a value: the server answers from its own Serial") \
|
|
||||||
X(GetTextureUnitObject, BARRIER_PULLED, "P3b/P4b, P7", \
|
X(GetTextureUnitObject, BARRIER_PULLED, "P3b/P4b, P7", \
|
||||||
"frontend TextureUnit base pointer; 13 Espryt + 8 Magma sites") \
|
"frontend TextureUnit base pointer; 13 Espryt + 8 Magma sites") \
|
||||||
/* DirectGLES.cpp:4497, PrepareForDraw, the second unconditional pointer read of every draw. */ \
|
/* DirectGLES.cpp:4497, PrepareForDraw, the second unconditional pointer read of every draw. */ \
|
||||||
@@ -113,24 +99,15 @@
|
|||||||
/* phases. Overturned by: nothing in P5b; P7/P8 retire both rows together. */ \
|
/* phases. Overturned by: nothing in P5b; P7/P8 retire both rows together. */ \
|
||||||
X(GetProgramForDispatch, BARRIER_PULLED, "P7 (Magma), P8 (Espryt)", \
|
X(GetProgramForDispatch, BARRIER_PULLED, "P7 (Magma), P8 (Espryt)", \
|
||||||
"frontend SharedPtr<ProgramObject>; the record carries a handle") \
|
"frontend SharedPtr<ProgramObject>; the record carries a handle") \
|
||||||
/* The XFB six. XFB itself is off the reduced path, but kDraw's may-read mask carries all */ \
|
/* The XFB family's one OBJECT row. XFB itself is off the reduced path, but kDraw's */ \
|
||||||
/* six and the draw walk reads them regardless - which is exactly the case a field census */ \
|
/* may-read mask carries it and the draw walk reads it regardless - which is exactly the */ \
|
||||||
/* taken from "what the scenario does" rather than from the mask would miss. */ \
|
/* case a field census taken from "what the scenario does" rather than from the mask would */ \
|
||||||
X(IsTransformFeedbackActive, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
/* miss. The family's five VALUE rows rode set_context_values out of this list at P5c rv. */ \
|
||||||
"read on every kDraw walk although XFB is off the reduced path") \
|
|
||||||
X(IsTransformFeedbackPaused, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
|
||||||
"read on every kDraw walk although XFB is off the reduced path") \
|
|
||||||
X(GetTransformFeedbackProgram, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
X(GetTransformFeedbackProgram, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
||||||
"frontend SharedPtr<ProgramObject>") \
|
"frontend SharedPtr<ProgramObject>") \
|
||||||
X(GetTransformFeedbackGeneration, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
|
||||||
"no call carries it") \
|
|
||||||
X(GetBoundTransformFeedbackLifetimeId, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
|
||||||
"the D21 counter-slot rekey's key; no call carries it") \
|
|
||||||
X(GetTransformFeedbackCapturedVertices, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
|
||||||
"no call carries it") \
|
|
||||||
\
|
\
|
||||||
/* ---- APPLIER_DERIVED ---- */ \
|
/* ---- APPLIER_DERIVED ---- */ \
|
||||||
/* THE ONE ROW, and it is the one the contract asked P5 to split into two field ids. It is */ \
|
/* THE FIRST ROW, and it is the one the contract asked P5 to split into two field ids. It is */ \
|
||||||
/* split HERE INSTEAD, by ARGUMENT, in the argument-exception list below - see that list's */ \
|
/* split HERE INSTEAD, by ARGUMENT, in the argument-exception list below - see that list's */ \
|
||||||
/* header for the evidence and for what would overturn the decision. The field itself is */ \
|
/* header for the evidence and for what would overturn the decision. The field itself is */ \
|
||||||
/* APPLIER_DERIVED because set_pixel_pack_state arrives and MGPipeApplyAccess::PackState */ \
|
/* APPLIER_DERIVED because set_pixel_pack_state arrives and MGPipeApplyAccess::PackState */ \
|
||||||
@@ -139,6 +116,19 @@
|
|||||||
/* half of it). */ \
|
/* half of it). */ \
|
||||||
X(GetPixelStoreParameters, APPLIER_DERIVED, "-", \
|
X(GetPixelStoreParameters, APPLIER_DERIVED, "-", \
|
||||||
"set_pixel_pack_state; the applier writes m_pixelStore[0] (PipeApply.cpp:1373)") \
|
"set_pixel_pack_state; the applier writes m_pixelStore[0] (PipeApply.cpp:1373)") \
|
||||||
|
/* THE THREE TEXTURE SHUTTERS (P5c rv, CONTRACT-P5C.md §5.3). No call carries them and none */ \
|
||||||
|
/* should (Coverage.def's emitted-list header): what replaces them server-side is the */ \
|
||||||
|
/* applier's own Serial - a different value with a different owner. rv is the edit that */ \
|
||||||
|
/* makes the accessor DO it: under a server-stamped verb the PipeInputs accessor answers */ \
|
||||||
|
/* MGPipeApplierTextureShutterSerial() / MGPipeApplierContextSerial() (PipeApply.cpp) */ \
|
||||||
|
/* instead of the client's residual-fill copy, and the class flips from BARRIER_PULLED to */ \
|
||||||
|
/* here. Under monolith the storage answer is kept, byte for byte (G1). */ \
|
||||||
|
X(GetSamplingResolutionGeneration, APPLIER_DERIVED, "-", \
|
||||||
|
"a shutter, not a value: the server answers from its own Serial") \
|
||||||
|
X(GetTextureBindGeneration, APPLIER_DERIVED, "-", \
|
||||||
|
"a shutter, not a value: the server answers from its own Serial") \
|
||||||
|
X(GetTextureContextId, APPLIER_DERIVED, "-", \
|
||||||
|
"a shutter, not a value: the server answers from its own Serial") \
|
||||||
\
|
\
|
||||||
/* ---- FATAL: two non-sticky fields, each off the reduced path for a checkable reason ----- */ \
|
/* ---- FATAL: two non-sticky fields, each off the reduced path for a checkable reason ----- */ \
|
||||||
/* Three until P5b: GetProgramForDispatch moved up to BARRIER_PULLED when package i1 put */ \
|
/* Three until P5b: GetProgramForDispatch moved up to BARRIER_PULLED when package i1 put */ \
|
||||||
|
|||||||
@@ -936,14 +936,29 @@ namespace MobileGL::MG_Pipe {
|
|||||||
};
|
};
|
||||||
MGP_ASSERT_POD(MGPGlobalConstants, 40);
|
MGP_ASSERT_POD(MGPGlobalConstants, 40);
|
||||||
|
|
||||||
// The float/int/uint view is resolved on the CLIENT by ClassifyVertexAttribType.
|
// One attribute default, resolved on the CLIENT. P5c (rv, CONTRACT-P5C.md §5.3) AMENDED
|
||||||
|
// the shape: a CurrentVertexAttributeValue is one value in THREE views and GLContext
|
||||||
|
// converts between them NUMERICALLY (SetCurrentVertexAttributeFloat writes (Int32)value
|
||||||
|
// into intValue), so the four words of the written class alone were never the value -
|
||||||
|
// glVertexAttrib4f(loc, 1.5f, ...) leaves 1 in intValue and 0x3FC00000 in floatValue. The
|
||||||
|
// record now carries all three views VERBATIM, as the frontend computed them, and the
|
||||||
|
// applier writes each view from its own array; ValueClass stays as the record of which
|
||||||
|
// view the application wrote directly (the verify comparator covers it, and the
|
||||||
|
// emission-side suppressor compares the three views, not it). This is the catalogue's
|
||||||
|
// second payload-size amendment after P5b's MGPCopyRegion 64 -> 72 (CONTRACT-P5C.md §7.6):
|
||||||
|
// 24 -> 56 bytes, and PipeCatalogueTest pins the new size.
|
||||||
struct MGPAttribValue {
|
struct MGPAttribValue {
|
||||||
Uint32 Location;
|
Uint32 Location;
|
||||||
Uint8 ValueClass; // Float | Int | Uint | Double
|
Uint8 ValueClass; // Float | Int | Uint | Double
|
||||||
Uint8 Pad0[3];
|
Uint8 Pad0[3];
|
||||||
Uint32 Data[4];
|
// The frontend's three views, VERBATIM - floatValue / intValue / uintValue of the
|
||||||
|
// CurrentVertexAttributeValue, converted between each other by the CLIENT. The
|
||||||
|
// applier writes each view from its own array and never reconverts.
|
||||||
|
Uint32 FloatView[4];
|
||||||
|
Uint32 IntView[4];
|
||||||
|
Uint32 UintView[4];
|
||||||
};
|
};
|
||||||
MGP_ASSERT_POD(MGPAttribValue, 24);
|
MGP_ASSERT_POD(MGPAttribValue, 56);
|
||||||
|
|
||||||
// Var-tail header: MGPAttribValue[popcount(Mask)] follows.
|
// Var-tail header: MGPAttribValue[popcount(Mask)] follows.
|
||||||
struct MGPVertexAttribDefaults {
|
struct MGPVertexAttribDefaults {
|
||||||
@@ -1634,13 +1649,16 @@ namespace MobileGL::MG_Pipe {
|
|||||||
MGP_ASSERT_POD(MGPCopyFromFramebuffer, 48);
|
MGP_ASSERT_POD(MGPCopyFromFramebuffer, 48);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
// P5c: the two appended rows (MG_Remote/CONTRACT-P5C.md §5). APPENDED, never inserted:
|
// P5c: the three appended rows (MG_Remote/CONTRACT-P5C.md §5). APPENDED, never inserted:
|
||||||
// applier_reset is opcode 77 and object_death opcode 78, and no earlier opcode moved.
|
// applier_reset is opcode 77, object_death opcode 78, and set_context_values (rv, §5.3)
|
||||||
|
// opcode 79 - and no earlier opcode moved.
|
||||||
//
|
//
|
||||||
// Neither has an MGPipeApply* entry point and neither gains one. Both reach
|
// THE TWO CONTROL RECORDS have no MGPipeApply* entry point and never gain one. Both reach
|
||||||
// MG_Remote::Wire::WireVerbSink like the five P5b verbs, and under monolith neither has a
|
// MG_Remote::Wire::WireVerbSink like the five P5b verbs, and under monolith neither has a
|
||||||
// producer - the reset is the GL thread's direct MGPipeApplierReset() call and the death
|
// producer - the reset is the GL thread's direct MGPipeApplierReset() call and the death
|
||||||
// notice's mailbox hop, byte for byte as today (G1/G2).
|
// notice's mailbox hop, byte for byte as today (G1/G2). set_context_values is the ordinary
|
||||||
|
// shape instead: a routed set_* row with an MGPipeApply* entry point, emitted at validate
|
||||||
|
// with an active transport and never produced under monolith (G1).
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
// applier_reset = tracker.FreshlyPrimed()'s server half (P5c §5.1). The one field is the
|
// applier_reset = tracker.FreshlyPrimed()'s server half (P5c §5.1). The one field is the
|
||||||
@@ -1660,6 +1678,32 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// object (§5.2), so a null handle arriving is Fatal{ProtocolCorruption,
|
// object (§5.2), so a null handle arriving is Fatal{ProtocolCorruption,
|
||||||
// "ObjectDeath.Handle"} at the sink.
|
// "ObjectDeath.Handle"} at the sink.
|
||||||
|
|
||||||
|
// set_context_values = opcode 79, P5c rv (CONTRACT-P5C.md §5.3): the rv field table as
|
||||||
|
// ONE fixed-width POD. It carries every value-class field that no set_* call supplies -
|
||||||
|
// the two texture-unit counters, the per-target touched-buffer-binding high-water marks
|
||||||
|
// (indexed by BufferTarget, all 15, the four bind-point targets today and the rest
|
||||||
|
// zero), and the five transform-feedback values - and it retires their BARRIER_PULLED
|
||||||
|
// rows to RECORD_SUPPLIED. There is NO dirty mask in the payload: the record is
|
||||||
|
// whole-record hash-suppressed like every other set_* call, and a suppressed record
|
||||||
|
// means "nothing moved", never "field invalid" (§1). The three texture SHUTTERS
|
||||||
|
// (GetSamplingResolutionGeneration / GetTextureBindGeneration / GetTextureContextId)
|
||||||
|
// deliberately carry NO field here: they are APPLIER_DERIVED, answered by the accessor
|
||||||
|
// from the applier's own Serial (MG_Backend/MGPipe/PipeInputs.h).
|
||||||
|
struct MGPContextValues {
|
||||||
|
Uint32 ActiveTextureUnit; // feeds GetActiveTextureUnit
|
||||||
|
Uint32 MaxTouchedTextureUnit; // feeds GetMaxTouchedTextureUnit
|
||||||
|
// 15 = BufferTarget::BufferTargetCount (BufferObject.h:15-33). MG_Pipe may not include
|
||||||
|
// MG_State, so the pairing is asserted where both sides are visible (PipeFill.cpp).
|
||||||
|
Uint32 TouchedBufferBindingPointCount[15];
|
||||||
|
Uint8 IsTransformFeedbackActive;
|
||||||
|
Uint8 IsTransformFeedbackPaused;
|
||||||
|
Uint8 Pad0[2];
|
||||||
|
Uint64 TransformFeedbackGeneration;
|
||||||
|
Uint64 BoundTransformFeedbackLifetimeId;
|
||||||
|
Uint64 TransformFeedbackCapturedVertices;
|
||||||
|
};
|
||||||
|
MGP_ASSERT_POD(MGPContextValues, 96);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
// Reverse channel payloads (section 7.1)
|
// Reverse channel payloads (section 7.1)
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -213,6 +213,23 @@ namespace MobileGL::MG_Pipe {
|
|||||||
inputs.m_patchDefaultOuterLevel = outer;
|
inputs.m_patchDefaultOuterLevel = outer;
|
||||||
inputs.m_patchDefaultInnerLevel = inner;
|
inputs.m_patchDefaultInnerLevel = inner;
|
||||||
}
|
}
|
||||||
|
// P5c (rv, CONTRACT-P5C.md §5.3): set_context_values' write, one field per payload
|
||||||
|
// member, on the server side of the wire. Like PackState it is a plain store - the
|
||||||
|
// stamp is the filler/verb boundary's statement, not the applier's (see the struct's
|
||||||
|
// header comment).
|
||||||
|
static void SetContextValues(PipeInputs& inputs, const MGPContextValues& values) {
|
||||||
|
inputs.m_activeTextureUnit = static_cast<Int>(values.ActiveTextureUnit);
|
||||||
|
inputs.m_maxTouchedTextureUnit = static_cast<Int>(values.MaxTouchedTextureUnit);
|
||||||
|
for (SizeT i = 0; i < PipeInputs::kBufferTargetCount; ++i) {
|
||||||
|
inputs.m_touchedBindingPointCount[i] =
|
||||||
|
static_cast<SizeT>(values.TouchedBufferBindingPointCount[i]);
|
||||||
|
}
|
||||||
|
inputs.m_transformFeedbackActive = values.IsTransformFeedbackActive != 0;
|
||||||
|
inputs.m_transformFeedbackPaused = values.IsTransformFeedbackPaused != 0;
|
||||||
|
inputs.m_transformFeedbackGeneration = values.TransformFeedbackGeneration;
|
||||||
|
inputs.m_boundTransformFeedbackLifetimeId = values.BoundTransformFeedbackLifetimeId;
|
||||||
|
inputs.m_transformFeedbackCapturedVertices = values.TransformFeedbackCapturedVertices;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// D5: the 29 PipeInputs fields that are PURE FUNCTIONS of RenderStateParameters.
|
// D5: the 29 PipeInputs fields that are PURE FUNCTIONS of RenderStateParameters.
|
||||||
@@ -1189,6 +1206,12 @@ namespace MobileGL::MG_Pipe {
|
|||||||
|
|
||||||
MGPipeApplierState& MGPipeApplier() { return g_applier; }
|
MGPipeApplierState& MGPipeApplier() { return g_applier; }
|
||||||
|
|
||||||
|
// P5c (rv, CONTRACT-P5C.md §5.3): the three texture shutters' server-side answers. See
|
||||||
|
// MGPipeApplierState::TextureShutterSerial / ContextSerial for the bump rule.
|
||||||
|
Uint64 MGPipeApplierTextureShutterSerial() { return g_applier.TextureShutterSerial; }
|
||||||
|
Uint64 MGPipeApplierContextSerial() { return g_applier.ContextSerial; }
|
||||||
|
void MGPipeApplierNoteTextureStateMoved() { ++g_applier.TextureShutterSerial; }
|
||||||
|
|
||||||
void MGPipeSetResourceOps(const MGPipeResourceOps* ops) { g_resourceOps = ops; }
|
void MGPipeSetResourceOps(const MGPipeResourceOps* ops) { g_resourceOps = ops; }
|
||||||
const MGPipeResourceOps* MGPipeGetResourceOps() { return g_resourceOps; }
|
const MGPipeResourceOps* MGPipeGetResourceOps() { return g_resourceOps; }
|
||||||
|
|
||||||
@@ -1306,6 +1329,13 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// the first compare after the switch is a mismatch, which is the safe direction.
|
// the first compare after the switch is a mismatch, which is the safe direction.
|
||||||
++g_applier.VertexBuffersSerial;
|
++g_applier.VertexBuffersSerial;
|
||||||
++g_applier.IndexBufferSerial;
|
++g_applier.IndexBufferSerial;
|
||||||
|
// P5c (rv): a make-current is a fresh server, and the two shutter serials are what the
|
||||||
|
// PipeInputs texture-shutter accessors answer with - so both ADVANCE here, for the
|
||||||
|
// serials' own reason: a counter that restarts walks back through values already
|
||||||
|
// stamped into a memo that outlived the switch. ContextSerial's move is also
|
||||||
|
// GetTextureContextId's whole job (the backends key their per-context memos on it).
|
||||||
|
++g_applier.TextureShutterSerial;
|
||||||
|
++g_applier.ContextSerial;
|
||||||
|
|
||||||
// ---- P4a's working state, cleared for the same reason and with the same serial rule
|
// ---- P4a's working state, cleared for the same reason and with the same serial rule
|
||||||
// (D-J4). The OBJECT records - texture and renderbuffer resources, sampler CSOs,
|
// (D-J4). The OBJECT records - texture and renderbuffer resources, sampler CSOs,
|
||||||
@@ -1351,6 +1381,10 @@ namespace MobileGL::MG_Pipe {
|
|||||||
g_applier.BoundVertexElements = kMGPipeNullHandle;
|
g_applier.BoundVertexElements = kMGPipeNullHandle;
|
||||||
++g_applier.VertexBuffersSerial;
|
++g_applier.VertexBuffersSerial;
|
||||||
++g_applier.IndexBufferSerial;
|
++g_applier.IndexBufferSerial;
|
||||||
|
// P5c (rv): same rule for the shutter serials - the served context is going away, and
|
||||||
|
// a memo that outlives it must not match a value these have already answered with.
|
||||||
|
++g_applier.TextureShutterSerial;
|
||||||
|
++g_applier.ContextSerial;
|
||||||
// P4a's five object tables go with them, and the working handles they could name go
|
// P4a's five object tables go with them, and the working handles they could name go
|
||||||
// too - a bound shader CSO whose record has just been dropped must not survive as a
|
// too - a bound shader CSO whose record has just been dropped must not survive as a
|
||||||
// handle the next call resolves against.
|
// handle the next call resolves against.
|
||||||
@@ -1493,6 +1527,18 @@ namespace MobileGL::MG_Pipe {
|
|||||||
MGPipeApplyAccess::PackState(gPipeInputs) = pack.Pack;
|
MGPipeApplyAccess::PackState(gPipeInputs) = pack.Pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set_context_values (P5c rv, CONTRACT-P5C.md §5.3): the residual-value record's server
|
||||||
|
// half. A plain store of the whole POD - there is no dirty mask and no field-level gate,
|
||||||
|
// because the record crosses only when one of its source values moved (the client's
|
||||||
|
// whole-record hash suppression) and a suppressed record means "nothing moved", never
|
||||||
|
// "field invalid" (§1).
|
||||||
|
void MGPipeApplySetContextValues(const MGPContextValues& values) {
|
||||||
|
static_assert(std::extent_v<decltype(MGPContextValues::TouchedBufferBindingPointCount)> ==
|
||||||
|
PipeInputs::kBufferTargetCount,
|
||||||
|
"the record's per-target array and PipeInputs' have drifted");
|
||||||
|
MGPipeApplyAccess::SetContextValues(gPipeInputs, values);
|
||||||
|
}
|
||||||
|
|
||||||
void MGPipeApplySetPatchState(const MGPPatchState& patch) {
|
void MGPipeApplySetPatchState(const MGPPatchState& patch) {
|
||||||
PipeInputs& inputs = gPipeInputs;
|
PipeInputs& inputs = gPipeInputs;
|
||||||
RenderStateParameters& working = MGPipeApplyAccess::RenderState(inputs);
|
RenderStateParameters& working = MGPipeApplyAccess::RenderState(inputs);
|
||||||
@@ -1581,11 +1627,16 @@ namespace MobileGL::MG_Pipe {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PipeInputs::CurrentVertexAttributeValue& slot = slots[location];
|
PipeInputs::CurrentVertexAttributeValue& slot = slots[location];
|
||||||
// The three views are always populated; which one a shader input consumes is
|
// P5c (rv, CONTRACT-P5C.md §5.3): the record carries ALL THREE VIEWS VERBATIM, as
|
||||||
// ClassifyVertexAttribType's answer, not the carrier's, so all three cross.
|
// the frontend computed them, and the applier writes each view from its own array.
|
||||||
std::memcpy(slot.floatValue.data(), value.Data, sizeof(slot.floatValue));
|
// The pre-rv shape - one Data[4] memcpied into all three views - could not
|
||||||
std::memcpy(slot.intValue.data(), value.Data, sizeof(slot.intValue));
|
// reproduce the frontend's NUMERIC cross-view conversion (glVertexAttrib4f(loc,
|
||||||
std::memcpy(slot.uintValue.data(), value.Data, sizeof(slot.uintValue));
|
// 1.5f, ...) leaves 1 in intValue and 0x3FC00000 in floatValue), which is exactly
|
||||||
|
// why the field stayed EMITTED-AND-STILL-PULLED until rv. ValueClass rides along
|
||||||
|
// for the comparator; the applier no longer needs it to rebuild anything.
|
||||||
|
std::memcpy(slot.floatValue.data(), value.FloatView, sizeof(slot.floatValue));
|
||||||
|
std::memcpy(slot.intValue.data(), value.IntView, sizeof(slot.intValue));
|
||||||
|
std::memcpy(slot.uintValue.data(), value.UintView, sizeof(slot.uintValue));
|
||||||
}
|
}
|
||||||
if (fault == nullptr && consumed != hdr.Count) {
|
if (fault == nullptr && consumed != hdr.Count) {
|
||||||
fault = "Count does not match the attributes Mask names";
|
fault = "Count does not match the attributes Mask names";
|
||||||
@@ -1767,6 +1818,9 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// the twin re-derives its storage flags from the new mask at its next sync and decides
|
// the twin re-derives its storage flags from the new mask at its next sync and decides
|
||||||
// for itself whether the backend needs a recreate.
|
// for itself whether the backend needs a recreate.
|
||||||
++record->Serial;
|
++record->Serial;
|
||||||
|
// P5c (rv): a respecify can move a texture's shape, which is exactly what the
|
||||||
|
// sampling-resolution shutter guarded - the server-side answer moves with it.
|
||||||
|
MGPipeApplierNoteTextureStateMoved();
|
||||||
|
|
||||||
// A RESPECIFY REDEFINES A STORE, SO THE PENDING UPLOADS AGAINST THE STORE IT REPLACES
|
// A RESPECIFY REDEFINES A STORE, SO THE PENDING UPLOADS AGAINST THE STORE IT REPLACES
|
||||||
// GO WITH IT - AND ONLY THOSE. They are boxes and rects in a level's coordinate system
|
// GO WITH IT - AND ONLY THOSE. They are boxes and rects in a level's coordinate system
|
||||||
@@ -2025,6 +2079,10 @@ namespace MobileGL::MG_Pipe {
|
|||||||
const Uint32 gen = record->Gen;
|
const Uint32 gen = record->Gen;
|
||||||
*record = MGPipeResourceRecord{};
|
*record = MGPipeResourceRecord{};
|
||||||
record->Gen = gen;
|
record->Gen = gen;
|
||||||
|
// P5c (rv): a destroyed object may still be BOUND somewhere the texture shutters guard;
|
||||||
|
// the server's answer for them moves with the death rather than waiting for the next
|
||||||
|
// unit-set record to say so.
|
||||||
|
MGPipeApplierNoteTextureStateMoved();
|
||||||
|
|
||||||
// The applier's own state is consistent before the backend hears the news, so a hook
|
// The applier's own state is consistent before the backend hears the news, so a hook
|
||||||
// that looked back at this applier could not see a resource that is already gone. The
|
// that looked back at this applier could not see a resource that is already gone. The
|
||||||
@@ -2700,6 +2758,8 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// bytes are CARRIED, never cleared here: the server ORs them into its own flags and
|
// bytes are CARRIED, never cleared here: the server ORs them into its own flags and
|
||||||
// clears its own copy, and the client never clears a server flag.
|
// clears its own copy, and the client never clears a server flag.
|
||||||
++record->ParamsSerial;
|
++record->ParamsSerial;
|
||||||
|
// P5c (rv): a parameter change is what the sampling-resolution shutter guarded.
|
||||||
|
MGPipeApplierNoteTextureStateMoved();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2729,6 +2789,8 @@ namespace MobileGL::MG_Pipe {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++g_applier.SamplerViewsSerial;
|
++g_applier.SamplerViewsSerial;
|
||||||
|
// P5c (rv): a texture bind is what the bind-generation shutter guarded.
|
||||||
|
MGPipeApplierNoteTextureStateMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MGPipeApplyBindSamplerStates(const MGPSamplerStates& hdr, const MGPipeHandle* tail) {
|
void MGPipeApplyBindSamplerStates(const MGPSamplerStates& hdr, const MGPipeHandle* tail) {
|
||||||
@@ -2739,6 +2801,8 @@ namespace MobileGL::MG_Pipe {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++g_applier.SamplerStatesSerial;
|
++g_applier.SamplerStatesSerial;
|
||||||
|
// P5c (rv): a sampler bind or parameter change is what the shutters guarded.
|
||||||
|
MGPipeApplierNoteTextureStateMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MGPipeApplySetShaderImages(const MGPShaderImages& hdr, const MGPImageView* tail) {
|
void MGPipeApplySetShaderImages(const MGPShaderImages& hdr, const MGPImageView* tail) {
|
||||||
@@ -2754,6 +2818,8 @@ namespace MobileGL::MG_Pipe {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++g_applier.ShaderImagesSerial;
|
++g_applier.ShaderImagesSerial;
|
||||||
|
// P5c (rv): an image bind moves the texture bind generation's guarded set too.
|
||||||
|
MGPipeApplierNoteTextureStateMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================================
|
// ================================================================================
|
||||||
|
|||||||
@@ -693,6 +693,27 @@ namespace MobileGL::MG_Pipe {
|
|||||||
MGPipeHandle BoundShaderCso = kMGPipeNullHandle;
|
MGPipeHandle BoundShaderCso = kMGPipeNullHandle;
|
||||||
Uint64 ProgramBindingSerial = 0;
|
Uint64 ProgramBindingSerial = 0;
|
||||||
|
|
||||||
|
// ---- P5c (rv, CONTRACT-P5C.md §5.3): the server-side answer for the three texture
|
||||||
|
// SHUTTERS. FieldOwnership.def moves GetSamplingResolutionGeneration /
|
||||||
|
// GetTextureBindGeneration / GetTextureContextId to APPLIER_DERIVED - "a shutter, not
|
||||||
|
// a value: the server answers from its own Serial", which their rows have said since
|
||||||
|
// P5 - and THESE are the serials, read by the PipeInputs accessors under a
|
||||||
|
// server-stamped verb instead of the client's residual-fill copy.
|
||||||
|
//
|
||||||
|
// TextureShutterSerial answers the two GENERATIONS. It is an MGGen like its seven
|
||||||
|
// siblings above: server-owned, monotone, ++ on every applied record that can move
|
||||||
|
// what the frontend's bind / sampling-resolution generations guard - the three unit
|
||||||
|
// sets, set_texture_params, a respecify or destroy of any resource, a bind_shader_image
|
||||||
|
// verb (the sink bumps it, PipeApplier.cpp) - and ADVANCED, never zeroed, by
|
||||||
|
// MGPipeApplierReset / MGPipeApplierReleaseObjectRecords. Over-firing is the safe
|
||||||
|
// direction for a memo key: a moved serial costs a re-sync, a stuck one renders stale.
|
||||||
|
//
|
||||||
|
// ContextSerial answers GetTextureContextId: stable within the served context, moved
|
||||||
|
// by every MGPipeApplierReset (a make-current is a fresh server, §5.1), which is all
|
||||||
|
// the backends' per-context memo keys need.
|
||||||
|
Uint64 TextureShutterSerial = 0;
|
||||||
|
Uint64 ContextSerial = 0;
|
||||||
|
|
||||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
// ---- P5c (hd, CONTRACT-P5C §3.2): THE CURRENT VERB'S OWN HANDLES. ----------------
|
// ---- P5c (hd, CONTRACT-P5C §3.2): THE CURRENT VERB'S OWN HANDLES. ----------------
|
||||||
//
|
//
|
||||||
@@ -761,6 +782,17 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// The monolith's single applier. Under split there is one per served context.
|
// The monolith's single applier. Under split there is one per served context.
|
||||||
MGPipeApplierState& MGPipeApplier();
|
MGPipeApplierState& MGPipeApplier();
|
||||||
|
|
||||||
|
// P5c (rv): the two serials the PipeInputs texture-shutter accessors answer with under a
|
||||||
|
// server-stamped verb (FieldOwnership.def, APPLIER_DERIVED). Free functions rather than
|
||||||
|
// member reads so PipeInputs.h needs this header's DECLARATIONS only... and because the
|
||||||
|
// bump rule - advance, never zero - is stated once, beside the state.
|
||||||
|
Uint64 MGPipeApplierTextureShutterSerial();
|
||||||
|
Uint64 MGPipeApplierContextSerial();
|
||||||
|
// The one writer-side helper: every applier entry point that can move what the frontend's
|
||||||
|
// texture bind / sampling-resolution generations guard bumps the shutter serial through
|
||||||
|
// this, so the bump rule lives in exactly one place.
|
||||||
|
void MGPipeApplierNoteTextureStateMoved();
|
||||||
|
|
||||||
// A MAKE-CURRENT, NOT A TEARDOWN - and the distinction is the whole of this function's
|
// A MAKE-CURRENT, NOT A TEARDOWN - and the distinction is the whole of this function's
|
||||||
// contract. It runs on every change of the current GLContext (MGPipeTracker::Update resets
|
// contract. It runs on every change of the current GLContext (MGPipeTracker::Update resets
|
||||||
// the tracker whenever the context pointer moves, and the emitter calls this from the
|
// the tracker whenever the context pointer moves, and the emitter calls this from the
|
||||||
@@ -829,6 +861,12 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// set_patch_state. The trio also travels in pipeline chunk P0, and the applier asserts
|
// set_patch_state. The trio also travels in pipeline chunk P0, and the applier asserts
|
||||||
// under verify that the two carriers agree - the redundancy is a trip wire, not waste.
|
// under verify that the two carriers agree - the redundancy is a trip wire, not waste.
|
||||||
void MGPipeApplySetPatchState(const MGPPatchState& patch);
|
void MGPipeApplySetPatchState(const MGPPatchState& patch);
|
||||||
|
// set_context_values (P5c rv, CONTRACT-P5C.md §5.3): the residual-value record. Writes
|
||||||
|
// every field it carries into gPipeInputs through MGPipeApplyAccess - the server-owned
|
||||||
|
// write that retires the eight value-class BARRIER_PULLED rows. Emitted only with an
|
||||||
|
// active transport; under monolith there is no producer and the fields keep coming
|
||||||
|
// through the residual fill (G1).
|
||||||
|
void MGPipeApplySetContextValues(const MGPContextValues& values);
|
||||||
// set_vertex_attrib_defaults: `tail` is hdr.Count MGPAttribValues for the attributes
|
// set_vertex_attrib_defaults: `tail` is hdr.Count MGPAttribValues for the attributes
|
||||||
// named by hdr.Mask, in ascending location order.
|
// named by hdr.Mask, in ascending location order.
|
||||||
void MGPipeApplySetVertexAttribDefaults(const MGPVertexAttribDefaults& hdr, const MGPAttribValue* tail);
|
void MGPipeApplySetVertexAttribDefaults(const MGPVertexAttribDefaults& hdr, const MGPAttribValue* tail);
|
||||||
|
|||||||
@@ -45,14 +45,15 @@
|
|||||||
// appended server-side fence wait 1 and P5c's applier_reset 1
|
// appended server-side fence wait 1 and P5c's applier_reset 1
|
||||||
// kCtxQuery 8 query object namespace 6, plus the appended timestamp pair 2
|
// kCtxQuery 8 query object namespace 6, plus the appended timestamp pair 2
|
||||||
// kCtxCso 13 CSO create/bind/delete
|
// kCtxCso 13 CSO create/bind/delete
|
||||||
// kCtxState 17 16 of the 17 set_* calls + the temporary set_residual_value_state
|
// kCtxState 18 16 of the 18 set_* calls + the temporary set_residual_value_state
|
||||||
|
// + P5c rv's set_context_values
|
||||||
// kCtxObject 10 set_texture_params (the 17th set_*) + 8 object-scoped transfers, plus
|
// kCtxObject 10 set_texture_params (the 17th set_*) + 8 object-scoped transfers, plus
|
||||||
// P5c's object_death 1
|
// P5c's object_death 1
|
||||||
// kCtxVerb 18 3 context-reading transfer calls + the 10 commands, plus the five
|
// kCtxVerb 18 3 context-reading transfer calls + the 10 commands, plus the five
|
||||||
// P5b-appended verbs (bind_shader_image, patch_parameter,
|
// P5b-appended verbs (bind_shader_image, patch_parameter,
|
||||||
// bind_stream_output, set_storage_block_binding,
|
// bind_stream_output, set_storage_block_binding,
|
||||||
// copy_framebuffer_to_texture - MG_Remote/CONTRACT-P5B.md)
|
// copy_framebuffer_to_texture - MG_Remote/CONTRACT-P5B.md)
|
||||||
// total 78
|
// total 79
|
||||||
//
|
//
|
||||||
// Reconciliation with the plan's headline numbers (section 4.4 / appendix A), because they
|
// Reconciliation with the plan's headline numbers (section 4.4 / appendix A), because they
|
||||||
// do not add up to a set of UNIQUE records and this file has to hold unique records:
|
// do not add up to a set of UNIQUE records and this file has to hold unique records:
|
||||||
@@ -94,10 +95,15 @@
|
|||||||
// GL-thread direct call into server memory, and object_death, the framebuffer family's
|
// GL-thread direct call into server memory, and object_death, the framebuffer family's
|
||||||
// FIRST wire delete opcode and the handle-keyed replacement for the death-notice mailbox.
|
// FIRST wire delete opcode and the handle-keyed replacement for the death-notice mailbox.
|
||||||
// Neither has an MGPipeApply* entry point and neither gains one; both reach WireVerbSink.
|
// Neither has an MGPipeApply* entry point and neither gains one; both reach WireVerbSink.
|
||||||
// 78 unique records.
|
// - P5c rv (§5.3) appended ONE more (opcode 79): set_context_values, the residual-value
|
||||||
|
// record that retires the value-class BARRIER_PULLED rows. Unlike the two control records
|
||||||
|
// it IS an ordinary set_* row: MGPipeApplySetContextValues writes gPipeInputs, the row is
|
||||||
|
// routed through gMGPipeContext like its seventeen siblings, and under monolith it has no
|
||||||
|
// producer at all - the fields keep coming through the residual fill, byte for byte as
|
||||||
|
// before (G1). 79 unique records.
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#define MGP_CALL_LIST_DOCUMENTED_COUNT 78
|
#define MGP_CALL_LIST_DOCUMENTED_COUNT 79
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define MGP_CALL_LIST(X) \
|
#define MGP_CALL_LIST(X) \
|
||||||
@@ -256,7 +262,15 @@
|
|||||||
/* twin table by handle. The framebuffer family's FIRST wire delete opcode: its death used */ \
|
/* twin table by handle. The framebuffer family's FIRST wire delete opcode: its death used */ \
|
||||||
/* to hop to the apply thread through a stack-struct mailbox and a lifetime-id probe of */ \
|
/* to hop to the apply thread through a stack-struct mailbox and a lifetime-id probe of */ \
|
||||||
/* the client's allocator, both rule-E surfaces. */ \
|
/* the client's allocator, both rule-E surfaces. */ \
|
||||||
X(ObjectDeath, MGPHandleOnly, kCtxObject, kNone)
|
X(ObjectDeath, MGPHandleOnly, kCtxObject, kNone) \
|
||||||
|
/* ---- P5c rv (CONTRACT-P5C.md §5.3), opcode 79: the residual-value record. One POD that ---- */ \
|
||||||
|
/* ---- carries every value-class BARRIER_PULLED field left after the set_* catalogue: the ---- */ \
|
||||||
|
/* ---- two texture-unit counters, the 15 per-target touched-buffer-binding counts and the ---- */ \
|
||||||
|
/* ---- five transform-feedback values. Emitted at validate when any covered value moved ---- */ \
|
||||||
|
/* ---- (whole-record hash suppression, D11's shape), ACTIVE ONLY with an active transport ---- */ \
|
||||||
|
/* ---- (PipeFill.cpp gates both the emission and the residual-fill skip on it): under ---- */ \
|
||||||
|
/* ---- monolith there is no producer and the fields keep being pulled, byte for byte (G1). ---- */ \
|
||||||
|
X(SetContextValues, MGPContextValues, kCtxState, kNone)
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Explicitly NOT migrated (plan 4.4.6 / appendix A "explicit deletions"):
|
// Explicitly NOT migrated (plan 4.4.6 / appendix A "explicit deletions"):
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
F(ShaderCso) F(Version) F(Blob)
|
F(ShaderCso) F(Version) F(Blob)
|
||||||
|
|
||||||
#define MGP_FIELDS_MGPAttribValue(F) \
|
#define MGP_FIELDS_MGPAttribValue(F) \
|
||||||
F(Location) F(ValueClass) F(Data)
|
F(Location) F(ValueClass) F(FloatView) F(IntView) F(UintView)
|
||||||
|
|
||||||
#define MGP_FIELDS_MGPVertexAttribDefaults(F) \
|
#define MGP_FIELDS_MGPVertexAttribDefaults(F) \
|
||||||
F(Mask) F(Count)
|
F(Mask) F(Count)
|
||||||
@@ -268,6 +268,14 @@
|
|||||||
#define MGP_FIELDS_MGPApplierReset(F) \
|
#define MGP_FIELDS_MGPApplierReset(F) \
|
||||||
F(ContextSerial)
|
F(ContextSerial)
|
||||||
|
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3): set_context_values' POD, one row per member. The 15-entry
|
||||||
|
// array is one field, exactly as MGPFramebufferState's Color[8] is one.
|
||||||
|
#define MGP_FIELDS_MGPContextValues(F) \
|
||||||
|
F(ActiveTextureUnit) F(MaxTouchedTextureUnit) F(TouchedBufferBindingPointCount) \
|
||||||
|
F(IsTransformFeedbackActive) F(IsTransformFeedbackPaused) \
|
||||||
|
F(TransformFeedbackGeneration) F(BoundTransformFeedbackLifetimeId) \
|
||||||
|
F(TransformFeedbackCapturedVertices)
|
||||||
|
|
||||||
// ---- the value structs and the host span (P1 brief D8). Not call payloads themselves, but
|
// ---- the value structs and the host span (P1 brief D8). Not call payloads themselves, but
|
||||||
// members of ones (ResidualValueBlock, MGPPixelPackState, MGPCaps) and of PipeInputs, so the
|
// members of ones (ResidualValueBlock, MGPPixelPackState, MGPCaps) and of PipeInputs, so the
|
||||||
// comparator has to see INTO them: with these lists the memcmp fallback of MGPipeFieldEqual is
|
// comparator has to see INTO them: with these lists the memcmp fallback of MGPipeFieldEqual is
|
||||||
@@ -385,7 +393,7 @@
|
|||||||
P(MGPSurfaceInfo) \
|
P(MGPSurfaceInfo) \
|
||||||
P(MGPImageBind) P(MGPPatchParameter) P(MGPStreamOutputBind) P(MGPStorageBlockBinding) \
|
P(MGPImageBind) P(MGPPatchParameter) P(MGPStreamOutputBind) P(MGPStorageBlockBinding) \
|
||||||
P(MGPCopyFromFramebuffer) \
|
P(MGPCopyFromFramebuffer) \
|
||||||
P(MGPApplierReset) \
|
P(MGPApplierReset) P(MGPContextValues) \
|
||||||
P(RenderStateParameters) P(PixelStoreParameters) P(SamplerParameters) P(PerBufferBlendState) \
|
P(RenderStateParameters) P(PixelStoreParameters) P(SamplerParameters) P(PerBufferBlendState) \
|
||||||
P(StencilFaceState) \
|
P(StencilFaceState) \
|
||||||
P(DynamicBackendParameters) P(MGHostSpan) \
|
P(DynamicBackendParameters) P(MGHostSpan) \
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
// The MONOLITH arm of R-17's routing: thirty-seven adapters that unpack a generated table
|
// The MONOLITH arm of R-17's routing: thirty-eight adapters that unpack a generated table
|
||||||
// row's parameters and call the MGPipeApply* entry point the call site used to call directly.
|
// row's parameters and call the MGPipeApply* entry point the call site used to call directly.
|
||||||
// Owner: package c1. See PipeRoute.h for why the arm exists and what R-17 actually cost.
|
// Owner: package c1. See PipeRoute.h for why the arm exists and what R-17 actually cost.
|
||||||
//
|
//
|
||||||
@@ -164,11 +164,11 @@ namespace MobileGL::MG_Pipe {
|
|||||||
Bool MGPipeTablesAreInstalled() { return g_arm != MGPipeRouteArm::kNone; }
|
Bool MGPipeTablesAreInstalled() { return g_arm != MGPipeRouteArm::kNone; }
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
// The thirty-seven monolith adapters
|
// The thirty-eight monolith adapters
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Three shapes, so the eye can check them against PipeTables.inc in one pass rather than
|
// Three shapes, so the eye can check them against PipeTables.inc in one pass rather than
|
||||||
// reading thirty-seven bodies. A row that does not fit one of the three is written out by
|
// reading thirty-eight bodies. A row that does not fit one of the three is written out by
|
||||||
// hand BELOW the macros, never by widening a macro - a macro that grew a special case is
|
// hand BELOW the macros, never by widening a macro - a macro that grew a special case is
|
||||||
// how one of these silently stops being a parameter shuffle.
|
// how one of these silently stops being a parameter shuffle.
|
||||||
|
|
||||||
@@ -207,6 +207,11 @@ namespace MobileGL::MG_Pipe {
|
|||||||
MGP_MONO_PLAIN(SetIndexBuffer, MGPIndexBuffer)
|
MGP_MONO_PLAIN(SetIndexBuffer, MGPIndexBuffer)
|
||||||
MGP_MONO_PLAIN(SetPixelPackState, MGPPixelPackState)
|
MGP_MONO_PLAIN(SetPixelPackState, MGPPixelPackState)
|
||||||
MGP_MONO_PLAIN(SetPatchState, MGPPatchState)
|
MGP_MONO_PLAIN(SetPatchState, MGPPatchState)
|
||||||
|
// P5c (rv): dormant under monolith - PipeFill.cpp's producer is transport-gated, so
|
||||||
|
// nothing routes here without a live wire. It exists because the row has an
|
||||||
|
// MGPipeApply* entry point (unlike the two control records) and because the wire
|
||||||
|
// emitter's server-role arm forwards to this table (WireTables.cpp).
|
||||||
|
MGP_MONO_PLAIN(SetContextValues, MGPContextValues)
|
||||||
|
|
||||||
// -- context, blob companion --------------------------------------------------
|
// -- context, blob companion --------------------------------------------------
|
||||||
MGP_MONO_BLOB(CreateRenderState, MGPRenderStateDesc)
|
MGP_MONO_BLOB(CreateRenderState, MGPRenderStateDesc)
|
||||||
@@ -341,6 +346,7 @@ namespace MobileGL::MG_Pipe {
|
|||||||
gMGPipeContext.SetVertexAttribDefaults = &Mono_SetVertexAttribDefaults;
|
gMGPipeContext.SetVertexAttribDefaults = &Mono_SetVertexAttribDefaults;
|
||||||
gMGPipeContext.SetPixelPackState = &Mono_SetPixelPackState;
|
gMGPipeContext.SetPixelPackState = &Mono_SetPixelPackState;
|
||||||
gMGPipeContext.SetPatchState = &Mono_SetPatchState;
|
gMGPipeContext.SetPatchState = &Mono_SetPatchState;
|
||||||
|
gMGPipeContext.SetContextValues = &Mono_SetContextValues;
|
||||||
gMGPipeContext.SetResidualValueState = &Mono_SetResidualValueState;
|
gMGPipeContext.SetResidualValueState = &Mono_SetResidualValueState;
|
||||||
gMGPipeContext.SetTextureParams = &Mono_SetTextureParams;
|
gMGPipeContext.SetTextureParams = &Mono_SetTextureParams;
|
||||||
gMGPipeContext.ResourceSubData = &Mono_ResourceSubData;
|
gMGPipeContext.ResourceSubData = &Mono_ResourceSubData;
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
// THE CLIENT -> WIRE ROUTING OF THE 37 MGPipeApply* ENTRY POINTS (P5, integrator ruling R-17).
|
// THE CLIENT -> WIRE ROUTING OF THE 38 MGPipeApply* ENTRY POINTS (P5, integrator ruling R-17;
|
||||||
|
// 38 since P5c rv added set_context_values, CONTRACT-P5C.md section 5.3).
|
||||||
// Owner: package c1.
|
// Owner: package c1.
|
||||||
//
|
//
|
||||||
// WHAT WAS MISSING. `gMGPipeWireRecordApply` is the DECODE hook and it has existed since w1:
|
// WHAT WAS MISSING. `gMGPipeWireRecordApply` is the DECODE hook and it has existed since w1:
|
||||||
@@ -218,7 +219,7 @@ namespace MobileGL::MG_Pipe {
|
|||||||
void MGPipeNoteInstalledArm(MGPipeRouteArm arm);
|
void MGPipeNoteInstalledArm(MGPipeRouteArm arm);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
// The call-site names: MGPipeRoute<Name> for each of the thirty-seven
|
// The call-site names: MGPipeRoute<Name> for each of the thirty-eight
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// EVERY ONE TAKES THE APPLIER'S OWN SIGNATURE, so converting a call site is a rename and
|
// EVERY ONE TAKES THE APPLIER'S OWN SIGNATURE, so converting a call site is a rename and
|
||||||
@@ -307,6 +308,14 @@ namespace MobileGL::MG_Pipe {
|
|||||||
MGP_SetPixelPackState(&pack);
|
MGP_SetPixelPackState(&pack);
|
||||||
}
|
}
|
||||||
inline void MGPipeRouteSetPatchState(const MGPPatchState& patch) { MGP_SetPatchState(&patch); }
|
inline void MGPipeRouteSetPatchState(const MGPPatchState& patch) { MGP_SetPatchState(&patch); }
|
||||||
|
// P5c (rv, CONTRACT-P5C.md §5.3): emitted ONLY with an active transport (PipeFill.cpp
|
||||||
|
// gates on it); under monolith the row is never produced and the fields keep coming
|
||||||
|
// through the residual fill (G1). The row IS an ordinary routed set_* otherwise - the
|
||||||
|
// monolith adapter exists so the wire emitter's server-role arm has something defined to
|
||||||
|
// forward to, and the catalogue's null-row accounting (PipeCatalogueTest) counts it.
|
||||||
|
inline void MGPipeRouteSetContextValues(const MGPContextValues& values) {
|
||||||
|
MGP_SetContextValues(&values);
|
||||||
|
}
|
||||||
inline void MGPipeRouteSetVertexAttribDefaults(const MGPVertexAttribDefaults& hdr,
|
inline void MGPipeRouteSetVertexAttribDefaults(const MGPVertexAttribDefaults& hdr,
|
||||||
const MGPAttribValue* tail) {
|
const MGPAttribValue* tail) {
|
||||||
MGP_SetVertexAttribDefaults(&hdr, tail, hdr.Count);
|
MGP_SetVertexAttribDefaults(&hdr, tail, hdr.Count);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ inline constexpr const char* kMGPipeFieldOwnershipNames[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCount] = {
|
inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCount] = {
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetActiveTextureUnit
|
MGPipeFieldOwnership::kRecordSupplied, // GetActiveTextureUnit
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetBlendColor
|
MGPipeFieldOwnership::kRecordSupplied, // GetBlendColor
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetBlendEquationIndexed
|
MGPipeFieldOwnership::kRecordSupplied, // GetBlendEquationIndexed
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetBlendFuncIndexed
|
MGPipeFieldOwnership::kRecordSupplied, // GetBlendFuncIndexed
|
||||||
@@ -43,14 +43,14 @@ inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCou
|
|||||||
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingSlot
|
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingSlot
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPoint
|
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPoint
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPointCount
|
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPointCount
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTouchedBufferBindingPointCount
|
MGPipeFieldOwnership::kRecordSupplied, // GetTouchedBufferBindingPointCount
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetClampReadColor
|
MGPipeFieldOwnership::kRecordSupplied, // GetClampReadColor
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetClearColor
|
MGPipeFieldOwnership::kRecordSupplied, // GetClearColor
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetClearDepth
|
MGPipeFieldOwnership::kRecordSupplied, // GetClearDepth
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetClearStencil
|
MGPipeFieldOwnership::kRecordSupplied, // GetClearStencil
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetColorMaskIndexed
|
MGPipeFieldOwnership::kRecordSupplied, // GetColorMaskIndexed
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetCullFaceMode
|
MGPipeFieldOwnership::kRecordSupplied, // GetCullFaceMode
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetCurrentVertexAttribute
|
MGPipeFieldOwnership::kRecordSupplied, // GetCurrentVertexAttribute
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetDepthFunc
|
MGPipeFieldOwnership::kRecordSupplied, // GetDepthFunc
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetDepthMask
|
MGPipeFieldOwnership::kRecordSupplied, // GetDepthMask
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetDepthRangeIndexed
|
MGPipeFieldOwnership::kRecordSupplied, // GetDepthRangeIndexed
|
||||||
@@ -58,7 +58,7 @@ inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCou
|
|||||||
MGPipeFieldOwnership::kBarrierPulled, // GetImageTextureBinding
|
MGPipeFieldOwnership::kBarrierPulled, // GetImageTextureBinding
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetLineWidth
|
MGPipeFieldOwnership::kRecordSupplied, // GetLineWidth
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetLogicOp
|
MGPipeFieldOwnership::kRecordSupplied, // GetLogicOp
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetMaxTouchedTextureUnit
|
MGPipeFieldOwnership::kRecordSupplied, // GetMaxTouchedTextureUnit
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetMinSampleShadingValue
|
MGPipeFieldOwnership::kRecordSupplied, // GetMinSampleShadingValue
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetPatchDefaultInnerLevel
|
MGPipeFieldOwnership::kRecordSupplied, // GetPatchDefaultInnerLevel
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetPatchDefaultOuterLevel
|
MGPipeFieldOwnership::kRecordSupplied, // GetPatchDefaultOuterLevel
|
||||||
@@ -75,33 +75,33 @@ inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCou
|
|||||||
MGPipeFieldOwnership::kRecordSupplied, // GetProvokingVertexMode
|
MGPipeFieldOwnership::kRecordSupplied, // GetProvokingVertexMode
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetRenderStateParameters
|
MGPipeFieldOwnership::kRecordSupplied, // GetRenderStateParameters
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetRenderStateParametersVersion
|
MGPipeFieldOwnership::kRecordSupplied, // GetRenderStateParametersVersion
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetSamplingResolutionGeneration
|
MGPipeFieldOwnership::kApplierDerived, // GetSamplingResolutionGeneration
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetScissorBox
|
MGPipeFieldOwnership::kRecordSupplied, // GetScissorBox
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetStencilState
|
MGPipeFieldOwnership::kRecordSupplied, // GetStencilState
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTextureBindGeneration
|
MGPipeFieldOwnership::kApplierDerived, // GetTextureBindGeneration
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTextureContextId
|
MGPipeFieldOwnership::kApplierDerived, // GetTextureContextId
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTextureObject
|
MGPipeFieldOwnership::kBarrierPulled, // GetTextureObject
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTextureUnitObject
|
MGPipeFieldOwnership::kBarrierPulled, // GetTextureUnitObject
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTransformFeedbackCapturedVertices
|
MGPipeFieldOwnership::kRecordSupplied, // GetTransformFeedbackCapturedVertices
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTransformFeedbackGeneration
|
MGPipeFieldOwnership::kRecordSupplied, // GetTransformFeedbackGeneration
|
||||||
MGPipeFieldOwnership::kFatal, // GetTransformFeedbackPausedPrimitiveCounter
|
MGPipeFieldOwnership::kFatal, // GetTransformFeedbackPausedPrimitiveCounter
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetTransformFeedbackProgram
|
MGPipeFieldOwnership::kBarrierPulled, // GetTransformFeedbackProgram
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetViewport
|
MGPipeFieldOwnership::kRecordSupplied, // GetViewport
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // GetViewportIndexed
|
MGPipeFieldOwnership::kRecordSupplied, // GetViewportIndexed
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // IsCapabilityEnabled
|
MGPipeFieldOwnership::kRecordSupplied, // IsCapabilityEnabled
|
||||||
MGPipeFieldOwnership::kRecordSupplied, // IsCapabilityEnabledIndexed
|
MGPipeFieldOwnership::kRecordSupplied, // IsCapabilityEnabledIndexed
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // IsTransformFeedbackActive
|
MGPipeFieldOwnership::kRecordSupplied, // IsTransformFeedbackActive
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // IsTransformFeedbackPaused
|
MGPipeFieldOwnership::kRecordSupplied, // IsTransformFeedbackPaused
|
||||||
MGPipeFieldOwnership::kFatal, // InvalidateCompileEnv
|
MGPipeFieldOwnership::kFatal, // InvalidateCompileEnv
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // ValidateProgramName
|
MGPipeFieldOwnership::kBarrierPulled, // ValidateProgramName
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // RecordError
|
MGPipeFieldOwnership::kBarrierPulled, // RecordError
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // GetBoundTransformFeedbackLifetimeId
|
MGPipeFieldOwnership::kRecordSupplied, // GetBoundTransformFeedbackLifetimeId
|
||||||
MGPipeFieldOwnership::kBarrierPulled, // HasOpenTransformFeedbackSpan
|
MGPipeFieldOwnership::kBarrierPulled, // HasOpenTransformFeedbackSpan
|
||||||
};
|
};
|
||||||
|
|
||||||
// The ROADMAP phase whose row retires the pull. "-" for every class but BARRIER-PULLED.
|
// The ROADMAP phase whose row retires the pull. "-" for every class but BARRIER-PULLED.
|
||||||
inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] = {
|
inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] = {
|
||||||
"P3b/P4b", // GetActiveTextureUnit
|
"-", // GetActiveTextureUnit
|
||||||
"-", // GetBlendColor
|
"-", // GetBlendColor
|
||||||
"-", // GetBlendEquationIndexed
|
"-", // GetBlendEquationIndexed
|
||||||
"-", // GetBlendFuncIndexed
|
"-", // GetBlendFuncIndexed
|
||||||
@@ -110,14 +110,14 @@ inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] =
|
|||||||
"P8 (indirect), P9 (readback), P13 (transfer)", // GetBufferBindingSlot
|
"P8 (indirect), P9 (readback), P13 (transfer)", // GetBufferBindingSlot
|
||||||
"P3b/P4b, P7", // GetBufferBindingPoint
|
"P3b/P4b, P7", // GetBufferBindingPoint
|
||||||
"P7/P13", // GetBufferBindingPointCount
|
"P7/P13", // GetBufferBindingPointCount
|
||||||
"P3b/P4b", // GetTouchedBufferBindingPointCount
|
"-", // GetTouchedBufferBindingPointCount
|
||||||
"-", // GetClampReadColor
|
"-", // GetClampReadColor
|
||||||
"-", // GetClearColor
|
"-", // GetClearColor
|
||||||
"-", // GetClearDepth
|
"-", // GetClearDepth
|
||||||
"-", // GetClearStencil
|
"-", // GetClearStencil
|
||||||
"-", // GetColorMaskIndexed
|
"-", // GetColorMaskIndexed
|
||||||
"-", // GetCullFaceMode
|
"-", // GetCullFaceMode
|
||||||
"P3b/P4b", // GetCurrentVertexAttribute
|
"-", // GetCurrentVertexAttribute
|
||||||
"-", // GetDepthFunc
|
"-", // GetDepthFunc
|
||||||
"-", // GetDepthMask
|
"-", // GetDepthMask
|
||||||
"-", // GetDepthRangeIndexed
|
"-", // GetDepthRangeIndexed
|
||||||
@@ -125,7 +125,7 @@ inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] =
|
|||||||
"P3b/P4b, P7", // GetImageTextureBinding
|
"P3b/P4b, P7", // GetImageTextureBinding
|
||||||
"-", // GetLineWidth
|
"-", // GetLineWidth
|
||||||
"-", // GetLogicOp
|
"-", // GetLogicOp
|
||||||
"P3b/P4b", // GetMaxTouchedTextureUnit
|
"-", // GetMaxTouchedTextureUnit
|
||||||
"-", // GetMinSampleShadingValue
|
"-", // GetMinSampleShadingValue
|
||||||
"-", // GetPatchDefaultInnerLevel
|
"-", // GetPatchDefaultInnerLevel
|
||||||
"-", // GetPatchDefaultOuterLevel
|
"-", // GetPatchDefaultOuterLevel
|
||||||
@@ -142,27 +142,27 @@ inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] =
|
|||||||
"-", // GetProvokingVertexMode
|
"-", // GetProvokingVertexMode
|
||||||
"-", // GetRenderStateParameters
|
"-", // GetRenderStateParameters
|
||||||
"-", // GetRenderStateParametersVersion
|
"-", // GetRenderStateParametersVersion
|
||||||
"P3b/P4b", // GetSamplingResolutionGeneration
|
"-", // GetSamplingResolutionGeneration
|
||||||
"-", // GetScissorBox
|
"-", // GetScissorBox
|
||||||
"-", // GetStencilState
|
"-", // GetStencilState
|
||||||
"P3b/P4b", // GetTextureBindGeneration
|
"-", // GetTextureBindGeneration
|
||||||
"P3b/P4b", // GetTextureContextId
|
"-", // GetTextureContextId
|
||||||
"P7", // GetTextureObject
|
"P7", // GetTextureObject
|
||||||
"P3b/P4b, P7", // GetTextureUnitObject
|
"P3b/P4b, P7", // GetTextureUnitObject
|
||||||
"P3b/P4b (Espryt), P7 (Magma)", // GetTransformFeedbackCapturedVertices
|
"-", // GetTransformFeedbackCapturedVertices
|
||||||
"P3b/P4b (Espryt), P7 (Magma)", // GetTransformFeedbackGeneration
|
"-", // GetTransformFeedbackGeneration
|
||||||
"-", // GetTransformFeedbackPausedPrimitiveCounter
|
"-", // GetTransformFeedbackPausedPrimitiveCounter
|
||||||
"P3b/P4b (Espryt), P7 (Magma)", // GetTransformFeedbackProgram
|
"P3b/P4b (Espryt), P7 (Magma)", // GetTransformFeedbackProgram
|
||||||
"-", // GetViewport
|
"-", // GetViewport
|
||||||
"-", // GetViewportIndexed
|
"-", // GetViewportIndexed
|
||||||
"-", // IsCapabilityEnabled
|
"-", // IsCapabilityEnabled
|
||||||
"-", // IsCapabilityEnabledIndexed
|
"-", // IsCapabilityEnabledIndexed
|
||||||
"P3b/P4b (Espryt), P7 (Magma)", // IsTransformFeedbackActive
|
"-", // IsTransformFeedbackActive
|
||||||
"P3b/P4b (Espryt), P7 (Magma)", // IsTransformFeedbackPaused
|
"-", // IsTransformFeedbackPaused
|
||||||
"-", // InvalidateCompileEnv
|
"-", // InvalidateCompileEnv
|
||||||
"P9", // ValidateProgramName
|
"P9", // ValidateProgramName
|
||||||
"P9", // RecordError
|
"P9", // RecordError
|
||||||
"P3b/P4b (Espryt), P7 (Magma)", // GetBoundTransformFeedbackLifetimeId
|
"-", // GetBoundTransformFeedbackLifetimeId
|
||||||
"P7/P9", // HasOpenTransformFeedbackSpan
|
"P7/P9", // HasOpenTransformFeedbackSpan
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -301,8 +301,8 @@ inline constexpr SizeT kMGPipeVerbBoundaryOpCount = 23;
|
|||||||
inline constexpr SizeT kMGPipeVerbBoundaryExemptCount = 3;
|
inline constexpr SizeT kMGPipeVerbBoundaryExemptCount = 3;
|
||||||
|
|
||||||
// The class sizes, as constants a test can pin without recounting the table.
|
// The class sizes, as constants a test can pin without recounting the table.
|
||||||
inline constexpr SizeT kMGPipeRecordSuppliedFieldCount = 32;
|
inline constexpr SizeT kMGPipeRecordSuppliedFieldCount = 41;
|
||||||
inline constexpr SizeT kMGPipeApplierDerivedFieldCount = 1;
|
inline constexpr SizeT kMGPipeApplierDerivedFieldCount = 4;
|
||||||
inline constexpr SizeT kMGPipeBarrierPulledFieldCount = 27;
|
inline constexpr SizeT kMGPipeBarrierPulledFieldCount = 15;
|
||||||
inline constexpr SizeT kMGPipeFatalFieldCount = 3;
|
inline constexpr SizeT kMGPipeFatalFieldCount = 3;
|
||||||
static_assert(kMGPipeRecordSuppliedFieldCount + kMGPipeApplierDerivedFieldCount + kMGPipeBarrierPulledFieldCount + kMGPipeFatalFieldCount == kMGPipeInputFieldCount, "the four class sizes do not partition the field set");
|
static_assert(kMGPipeRecordSuppliedFieldCount + kMGPipeApplierDerivedFieldCount + kMGPipeBarrierPulledFieldCount + kMGPipeFatalFieldCount == kMGPipeInputFieldCount, "the four class sizes do not partition the field set");
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ enum class MGPipeFieldEmitter : Uint8 {
|
|||||||
BindRenderState,
|
BindRenderState,
|
||||||
BindVertexElements,
|
BindVertexElements,
|
||||||
CreateRenderState,
|
CreateRenderState,
|
||||||
|
SetContextValues,
|
||||||
SetDispatchProgram,
|
SetDispatchProgram,
|
||||||
SetDrawProgram,
|
SetDrawProgram,
|
||||||
SetDynamicState,
|
SetDynamicState,
|
||||||
@@ -323,6 +324,7 @@ inline constexpr const char* kMGPipeFieldEmitterNames[] = {
|
|||||||
"BindRenderState",
|
"BindRenderState",
|
||||||
"BindVertexElements",
|
"BindVertexElements",
|
||||||
"CreateRenderState",
|
"CreateRenderState",
|
||||||
|
"SetContextValues",
|
||||||
"SetDispatchProgram",
|
"SetDispatchProgram",
|
||||||
"SetDrawProgram",
|
"SetDrawProgram",
|
||||||
"SetDynamicState",
|
"SetDynamicState",
|
||||||
@@ -334,7 +336,7 @@ inline constexpr const char* kMGPipeFieldEmitterNames[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr MGPipeFieldEmitter kMGPipeFieldEmittedBy[kMGPipeInputFieldCount] = {
|
inline constexpr MGPipeFieldEmitter kMGPipeFieldEmittedBy[kMGPipeInputFieldCount] = {
|
||||||
MGPipeFieldEmitter::kNone, // GetActiveTextureUnit
|
MGPipeFieldEmitter::SetContextValues, // GetActiveTextureUnit
|
||||||
MGPipeFieldEmitter::SetDynamicState, // GetBlendColor
|
MGPipeFieldEmitter::SetDynamicState, // GetBlendColor
|
||||||
MGPipeFieldEmitter::CreateRenderState, // GetBlendEquationIndexed
|
MGPipeFieldEmitter::CreateRenderState, // GetBlendEquationIndexed
|
||||||
MGPipeFieldEmitter::CreateRenderState, // GetBlendFuncIndexed
|
MGPipeFieldEmitter::CreateRenderState, // GetBlendFuncIndexed
|
||||||
@@ -343,7 +345,7 @@ inline constexpr MGPipeFieldEmitter kMGPipeFieldEmittedBy[kMGPipeInputFieldCount
|
|||||||
MGPipeFieldEmitter::kNone, // GetBufferBindingSlot
|
MGPipeFieldEmitter::kNone, // GetBufferBindingSlot
|
||||||
MGPipeFieldEmitter::kNone, // GetBufferBindingPoint
|
MGPipeFieldEmitter::kNone, // GetBufferBindingPoint
|
||||||
MGPipeFieldEmitter::kNone, // GetBufferBindingPointCount
|
MGPipeFieldEmitter::kNone, // GetBufferBindingPointCount
|
||||||
MGPipeFieldEmitter::kNone, // GetTouchedBufferBindingPointCount
|
MGPipeFieldEmitter::SetContextValues, // GetTouchedBufferBindingPointCount
|
||||||
MGPipeFieldEmitter::SetDynamicState, // GetClampReadColor
|
MGPipeFieldEmitter::SetDynamicState, // GetClampReadColor
|
||||||
MGPipeFieldEmitter::SetDynamicState, // GetClearColor
|
MGPipeFieldEmitter::SetDynamicState, // GetClearColor
|
||||||
MGPipeFieldEmitter::SetDynamicState, // GetClearDepth
|
MGPipeFieldEmitter::SetDynamicState, // GetClearDepth
|
||||||
@@ -358,7 +360,7 @@ inline constexpr MGPipeFieldEmitter kMGPipeFieldEmittedBy[kMGPipeInputFieldCount
|
|||||||
MGPipeFieldEmitter::SetShaderImages, // GetImageTextureBinding
|
MGPipeFieldEmitter::SetShaderImages, // GetImageTextureBinding
|
||||||
MGPipeFieldEmitter::SetDynamicState, // GetLineWidth
|
MGPipeFieldEmitter::SetDynamicState, // GetLineWidth
|
||||||
MGPipeFieldEmitter::CreateRenderState, // GetLogicOp
|
MGPipeFieldEmitter::CreateRenderState, // GetLogicOp
|
||||||
MGPipeFieldEmitter::SetSamplerViews, // GetMaxTouchedTextureUnit
|
MGPipeFieldEmitter::SetContextValues, // GetMaxTouchedTextureUnit
|
||||||
MGPipeFieldEmitter::CreateRenderState, // GetMinSampleShadingValue
|
MGPipeFieldEmitter::CreateRenderState, // GetMinSampleShadingValue
|
||||||
MGPipeFieldEmitter::SetPatchState, // GetPatchDefaultInnerLevel
|
MGPipeFieldEmitter::SetPatchState, // GetPatchDefaultInnerLevel
|
||||||
MGPipeFieldEmitter::SetPatchState, // GetPatchDefaultOuterLevel
|
MGPipeFieldEmitter::SetPatchState, // GetPatchDefaultOuterLevel
|
||||||
@@ -382,23 +384,23 @@ inline constexpr MGPipeFieldEmitter kMGPipeFieldEmittedBy[kMGPipeInputFieldCount
|
|||||||
MGPipeFieldEmitter::kNone, // GetTextureContextId
|
MGPipeFieldEmitter::kNone, // GetTextureContextId
|
||||||
MGPipeFieldEmitter::kNone, // GetTextureObject
|
MGPipeFieldEmitter::kNone, // GetTextureObject
|
||||||
MGPipeFieldEmitter::SetSamplerViews, // GetTextureUnitObject
|
MGPipeFieldEmitter::SetSamplerViews, // GetTextureUnitObject
|
||||||
MGPipeFieldEmitter::kNone, // GetTransformFeedbackCapturedVertices
|
MGPipeFieldEmitter::SetContextValues, // GetTransformFeedbackCapturedVertices
|
||||||
MGPipeFieldEmitter::kNone, // GetTransformFeedbackGeneration
|
MGPipeFieldEmitter::SetContextValues, // GetTransformFeedbackGeneration
|
||||||
MGPipeFieldEmitter::kNone, // GetTransformFeedbackPausedPrimitiveCounter
|
MGPipeFieldEmitter::kNone, // GetTransformFeedbackPausedPrimitiveCounter
|
||||||
MGPipeFieldEmitter::kNone, // GetTransformFeedbackProgram
|
MGPipeFieldEmitter::kNone, // GetTransformFeedbackProgram
|
||||||
MGPipeFieldEmitter::SetDynamicState, // GetViewport
|
MGPipeFieldEmitter::SetDynamicState, // GetViewport
|
||||||
MGPipeFieldEmitter::SetDynamicState, // GetViewportIndexed
|
MGPipeFieldEmitter::SetDynamicState, // GetViewportIndexed
|
||||||
MGPipeFieldEmitter::CreateRenderState, // IsCapabilityEnabled
|
MGPipeFieldEmitter::CreateRenderState, // IsCapabilityEnabled
|
||||||
MGPipeFieldEmitter::CreateRenderState, // IsCapabilityEnabledIndexed
|
MGPipeFieldEmitter::CreateRenderState, // IsCapabilityEnabledIndexed
|
||||||
MGPipeFieldEmitter::kNone, // IsTransformFeedbackActive
|
MGPipeFieldEmitter::SetContextValues, // IsTransformFeedbackActive
|
||||||
MGPipeFieldEmitter::kNone, // IsTransformFeedbackPaused
|
MGPipeFieldEmitter::SetContextValues, // IsTransformFeedbackPaused
|
||||||
MGPipeFieldEmitter::kNone, // InvalidateCompileEnv
|
MGPipeFieldEmitter::kNone, // InvalidateCompileEnv
|
||||||
MGPipeFieldEmitter::kNone, // ValidateProgramName
|
MGPipeFieldEmitter::kNone, // ValidateProgramName
|
||||||
MGPipeFieldEmitter::kNone, // RecordError
|
MGPipeFieldEmitter::kNone, // RecordError
|
||||||
MGPipeFieldEmitter::kNone, // GetBoundTransformFeedbackLifetimeId
|
MGPipeFieldEmitter::SetContextValues, // GetBoundTransformFeedbackLifetimeId
|
||||||
MGPipeFieldEmitter::kNone, // HasOpenTransformFeedbackSpan
|
MGPipeFieldEmitter::kNone, // HasOpenTransformFeedbackSpan
|
||||||
};
|
};
|
||||||
inline constexpr SizeT kMGPipeEmittedFieldCount = 40;
|
inline constexpr SizeT kMGPipeEmittedFieldCount = 47;
|
||||||
|
|
||||||
struct MGPipeFilledState {
|
struct MGPipeFilledState {
|
||||||
Uint64 CurrentVerbSerial;
|
Uint64 CurrentVerbSerial;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ struct MGPipeScreen {
|
|||||||
void (*ApplierReset)(const MGPApplierReset* payload);
|
void (*ApplierReset)(const MGPApplierReset* payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
// context: 66 calls. A null entry means the backend does not implement this
|
// context: 67 calls. A null entry means the backend does not implement this
|
||||||
// call and the frontend keeps its own path (plan B section 4.1).
|
// call and the frontend keeps its own path (plan B section 4.1).
|
||||||
struct MGPipeContext {
|
struct MGPipeContext {
|
||||||
void (*QueryCreate)(const MGPQueryDesc* payload);
|
void (*QueryCreate)(const MGPQueryDesc* payload);
|
||||||
@@ -98,11 +98,12 @@ struct MGPipeContext {
|
|||||||
void (*SetStorageBlockBinding)(const MGPStorageBlockBinding* payload, const void* blobBytes, Uint64 blobByteCount);
|
void (*SetStorageBlockBinding)(const MGPStorageBlockBinding* payload, const void* blobBytes, Uint64 blobByteCount);
|
||||||
void (*CopyFramebufferToTexture)(const MGPCopyFromFramebuffer* payload);
|
void (*CopyFramebufferToTexture)(const MGPCopyFromFramebuffer* payload);
|
||||||
void (*ObjectDeath)(const MGPHandleOnly* payload);
|
void (*ObjectDeath)(const MGPHandleOnly* payload);
|
||||||
|
void (*SetContextValues)(const MGPContextValues* payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr SizeT kMGPipeScreenCallCount = 12;
|
inline constexpr SizeT kMGPipeScreenCallCount = 12;
|
||||||
inline constexpr SizeT kMGPipeContextCallCount = 66;
|
inline constexpr SizeT kMGPipeContextCallCount = 67;
|
||||||
inline constexpr SizeT kMGPipeCallCount = 78;
|
inline constexpr SizeT kMGPipeCallCount = 79;
|
||||||
|
|
||||||
// A table that is not exactly its call count of function pointers has grown a
|
// A table that is not exactly its call count of function pointers has grown a
|
||||||
// member that no generator knows about.
|
// member that no generator knows about.
|
||||||
|
|||||||
@@ -328,3 +328,7 @@ inline void MGP_ApplierReset(const MGPApplierReset* payload) {
|
|||||||
inline void MGP_ObjectDeath(const MGPHandleOnly* payload) {
|
inline void MGP_ObjectDeath(const MGPHandleOnly* payload) {
|
||||||
gMGPipeContext.ObjectDeath(payload);
|
gMGPipeContext.ObjectDeath(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void MGP_SetContextValues(const MGPContextValues* payload) {
|
||||||
|
gMGPipeContext.SetContextValues(payload);
|
||||||
|
}
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ inline Bool MGPipeVerify(const MGPStreamOutputBind& a, const MGPStreamOutputBind
|
|||||||
inline Bool MGPipeVerify(const MGPStorageBlockBinding& a, const MGPStorageBlockBinding& b, const char** outField);
|
inline Bool MGPipeVerify(const MGPStorageBlockBinding& a, const MGPStorageBlockBinding& b, const char** outField);
|
||||||
inline Bool MGPipeVerify(const MGPCopyFromFramebuffer& a, const MGPCopyFromFramebuffer& b, const char** outField);
|
inline Bool MGPipeVerify(const MGPCopyFromFramebuffer& a, const MGPCopyFromFramebuffer& b, const char** outField);
|
||||||
inline Bool MGPipeVerify(const MGPApplierReset& a, const MGPApplierReset& b, const char** outField);
|
inline Bool MGPipeVerify(const MGPApplierReset& a, const MGPApplierReset& b, const char** outField);
|
||||||
|
inline Bool MGPipeVerify(const MGPContextValues& a, const MGPContextValues& b, const char** outField);
|
||||||
inline Bool MGPipeVerify(const RenderStateParameters& a, const RenderStateParameters& b, const char** outField);
|
inline Bool MGPipeVerify(const RenderStateParameters& a, const RenderStateParameters& b, const char** outField);
|
||||||
inline Bool MGPipeVerify(const PixelStoreParameters& a, const PixelStoreParameters& b, const char** outField);
|
inline Bool MGPipeVerify(const PixelStoreParameters& a, const PixelStoreParameters& b, const char** outField);
|
||||||
inline Bool MGPipeVerify(const SamplerParameters& a, const SamplerParameters& b, const char** outField);
|
inline Bool MGPipeVerify(const SamplerParameters& a, const SamplerParameters& b, const char** outField);
|
||||||
@@ -262,6 +263,8 @@ struct MGPipeHasFieldVerifier<MGPCopyFromFramebuffer> : std::true_type {};
|
|||||||
template <>
|
template <>
|
||||||
struct MGPipeHasFieldVerifier<MGPApplierReset> : std::true_type {};
|
struct MGPipeHasFieldVerifier<MGPApplierReset> : std::true_type {};
|
||||||
template <>
|
template <>
|
||||||
|
struct MGPipeHasFieldVerifier<MGPContextValues> : std::true_type {};
|
||||||
|
template <>
|
||||||
struct MGPipeHasFieldVerifier<RenderStateParameters> : std::true_type {};
|
struct MGPipeHasFieldVerifier<RenderStateParameters> : std::true_type {};
|
||||||
template <>
|
template <>
|
||||||
struct MGPipeHasFieldVerifier<PixelStoreParameters> : std::true_type {};
|
struct MGPipeHasFieldVerifier<PixelStoreParameters> : std::true_type {};
|
||||||
@@ -670,6 +673,11 @@ inline Bool MGPipeVerify(const MGPApplierReset& a, const MGPApplierReset& b, con
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Bool MGPipeVerify(const MGPContextValues& a, const MGPContextValues& b, const char** outField) {
|
||||||
|
MGP_FIELDS_MGPContextValues(MGP_VERIFY_FIELD)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline Bool MGPipeVerify(const RenderStateParameters& a, const RenderStateParameters& b, const char** outField) {
|
inline Bool MGPipeVerify(const RenderStateParameters& a, const RenderStateParameters& b, const char** outField) {
|
||||||
MGP_FIELDS_RenderStateParameters(MGP_VERIFY_FIELD)
|
MGP_FIELDS_RenderStateParameters(MGP_VERIFY_FIELD)
|
||||||
return true;
|
return true;
|
||||||
@@ -717,4 +725,4 @@ inline Bool MGPipeVerify(const MGPVertexBindingPointWire& a, const MGPVertexBind
|
|||||||
|
|
||||||
#undef MGP_VERIFY_FIELD
|
#undef MGP_VERIFY_FIELD
|
||||||
|
|
||||||
inline constexpr SizeT kMGPipeVerifiedPayloadCount = 78;
|
inline constexpr SizeT kMGPipeVerifiedPayloadCount = 79;
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ enum class MGPWireOp : Uint16 {
|
|||||||
CopyFramebufferToTexture = 76,
|
CopyFramebufferToTexture = 76,
|
||||||
ApplierReset = 77,
|
ApplierReset = 77,
|
||||||
ObjectDeath = 78,
|
ObjectDeath = 78,
|
||||||
kOpCount = 79,
|
SetContextValues = 79,
|
||||||
|
kOpCount = 80,
|
||||||
};
|
};
|
||||||
|
|
||||||
// THE FLAGS, EXPORTED ONCE, INDEXED BY OPCODE (P5 R-13.4). MGPWireRecHeader::Flags is
|
// THE FLAGS, EXPORTED ONCE, INDEXED BY OPCODE (P5 R-13.4). MGPWireRecHeader::Flags is
|
||||||
@@ -248,6 +249,7 @@ inline constexpr Uint32 kMGPipeCallFlags[static_cast<SizeT>(MGPWireOp::kOpCount)
|
|||||||
/* 76 CopyFramebufferToTexture*/ static_cast<Uint32>(kNone),
|
/* 76 CopyFramebufferToTexture*/ static_cast<Uint32>(kNone),
|
||||||
/* 77 ApplierReset */ static_cast<Uint32>(kNone),
|
/* 77 ApplierReset */ static_cast<Uint32>(kNone),
|
||||||
/* 78 ObjectDeath */ static_cast<Uint32>(kNone),
|
/* 78 ObjectDeath */ static_cast<Uint32>(kNone),
|
||||||
|
/* 79 SetContextValues */ static_cast<Uint32>(kNone),
|
||||||
};
|
};
|
||||||
static_assert(sizeof(kMGPipeCallFlags) / sizeof(kMGPipeCallFlags[0]) ==
|
static_assert(sizeof(kMGPipeCallFlags) / sizeof(kMGPipeCallFlags[0]) ==
|
||||||
static_cast<SizeT>(MGPWireOp::kOpCount),
|
static_cast<SizeT>(MGPWireOp::kOpCount),
|
||||||
@@ -925,6 +927,14 @@ static_assert(sizeof(MGPWireRec_ObjectDeath) ==
|
|||||||
((sizeof(MGPWireRecHeader) + sizeof(MGPHandleOnly) + 7u) & ~SizeT(7u)),
|
((sizeof(MGPWireRecHeader) + sizeof(MGPHandleOnly) + 7u) & ~SizeT(7u)),
|
||||||
"MGPWireRec_ObjectDeath gained padding; the wire format moved");
|
"MGPWireRec_ObjectDeath gained padding; the wire format moved");
|
||||||
|
|
||||||
|
struct alignas(8) MGPWireRec_SetContextValues {
|
||||||
|
MGPWireRecHeader Header;
|
||||||
|
MGPContextValues Payload;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(MGPWireRec_SetContextValues) ==
|
||||||
|
((sizeof(MGPWireRecHeader) + sizeof(MGPContextValues) + 7u) & ~SizeT(7u)),
|
||||||
|
"MGPWireRec_SetContextValues gained padding; the wire format moved");
|
||||||
|
|
||||||
[[noreturn]] inline void MGPipeWireProtocolFatal(const char* call, Uint64 size, Uint64 remaining) {
|
[[noreturn]] inline void MGPipeWireProtocolFatal(const char* call, Uint64 size, Uint64 remaining) {
|
||||||
MGLOG_F("MGPipe: protocol corruption applying %s: size=%llu remaining=%llu", call,
|
MGLOG_F("MGPipe: protocol corruption applying %s: size=%llu remaining=%llu", call,
|
||||||
static_cast<unsigned long long>(size), static_cast<unsigned long long>(remaining));
|
static_cast<unsigned long long>(size), static_cast<unsigned long long>(remaining));
|
||||||
@@ -1208,6 +1218,9 @@ inline Bool MGPipeApplyWireRecord(MGPWireOp op, const void* record, Uint64 size,
|
|||||||
case MGPWireOp::ObjectDeath:
|
case MGPWireOp::ObjectDeath:
|
||||||
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_ObjectDeath, "ObjectDeath");
|
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_ObjectDeath, "ObjectDeath");
|
||||||
break;
|
break;
|
||||||
|
case MGPWireOp::SetContextValues:
|
||||||
|
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_SetContextValues, "SetContextValues");
|
||||||
|
break;
|
||||||
case MGPWireOp::kInvalid:
|
case MGPWireOp::kInvalid:
|
||||||
case MGPWireOp::kOpCount:
|
case MGPWireOp::kOpCount:
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-only
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
// The ENCODE TWIN of gMGPipeWireRecordApply: thirty-seven emitters that turn a table call into
|
// The ENCODE TWIN of gMGPipeWireRecordApply: thirty-eight emitters that turn a table call into
|
||||||
// a wire record. Owner: package c1 (P5 ruling R-17). See WireTables.h for the install order
|
// a wire record. Owner: package c1 (P5 ruling R-17). See WireTables.h for the install order
|
||||||
// and MG_Pipe/PipeRoute.h for what R-17 actually cost.
|
// and MG_Pipe/PipeRoute.h for what R-17 actually cost.
|
||||||
//
|
//
|
||||||
// EVERY EMITTER IS THE SAME FOUR STEPS, and the macros below exist so that a reader can check
|
// EVERY EMITTER IS THE SAME FOUR STEPS, and the macros below exist so that a reader can check
|
||||||
// thirty-seven rows against PipeTables.inc in one pass instead of reading thirty-seven bodies:
|
// thirty-eight rows against PipeTables.inc in one pass instead of reading thirty-eight bodies:
|
||||||
//
|
//
|
||||||
// 1. require a session - a slot that fell through to a driver this role does not have is
|
// 1. require a session - a slot that fell through to a driver this role does not have is
|
||||||
// the failure R-4 exists to prevent, and there is no fall-through here either;
|
// the failure R-4 exists to prevent, and there is no fall-through here either;
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
// 4. post the answer, for the rows that have one, into MG_Pipe's reply mailbox.
|
// 4. post the answer, for the rows that have one, into MG_Pipe's reply mailbox.
|
||||||
//
|
//
|
||||||
// WHAT IS DELIBERATELY NOT HERE. b1's `PushPersistentMapsBeforeVerb` / `MarkGpuWritesFor*` are
|
// WHAT IS DELIBERATELY NOT HERE. b1's `PushPersistentMapsBeforeVerb` / `MarkGpuWritesFor*` are
|
||||||
// NOT called from these thirty-seven. They are pre-VERB hooks and these are not verbs: they
|
// NOT called from these thirty-eight. They are pre-VERB hooks and these are not verbs: they
|
||||||
// are the resource, CSO and state records that a verb is later drawn against. The five class-B
|
// are the resource, CSO and state records that a verb is later drawn against. The five class-B
|
||||||
// verbs in EmitTables.cpp call them, once each, immediately before their record, which is the
|
// verbs in EmitTables.cpp call them, once each, immediately before their record, which is the
|
||||||
// ordering b1's B-1 fix depends on. Calling them here as well would push a persistent map
|
// ordering b1's B-1 fix depends on. Calling them here as well would push a persistent map
|
||||||
@@ -196,6 +196,11 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
MGP_WIRE_PLAIN(SetIndexBuffer, MGPIndexBuffer, Context)
|
MGP_WIRE_PLAIN(SetIndexBuffer, MGPIndexBuffer, Context)
|
||||||
MGP_WIRE_PLAIN(SetPixelPackState, MGPPixelPackState, Context)
|
MGP_WIRE_PLAIN(SetPixelPackState, MGPPixelPackState, Context)
|
||||||
MGP_WIRE_PLAIN(SetPatchState, MGPPatchState, Context)
|
MGP_WIRE_PLAIN(SetPatchState, MGPPatchState, Context)
|
||||||
|
// P5c (rv), CONTRACT-P5C.md §5.3: the residual-value record is an ordinary routed
|
||||||
|
// set_* row - a fixed POD, no blob, no tail, no reply. The PRODUCER is transport-gated
|
||||||
|
// (PipeFill.cpp's EmitContextValues), so under monolith this wrapper is never reached;
|
||||||
|
// the server-role arm forwards to the monolith adapter exactly like its siblings.
|
||||||
|
MGP_WIRE_PLAIN(SetContextValues, MGPContextValues, Context)
|
||||||
|
|
||||||
// -- context, mandatory blob --------------------------------------------------
|
// -- context, mandatory blob --------------------------------------------------
|
||||||
MGP_WIRE_BLOB(CreateRenderState, MGPRenderStateDesc, Blob)
|
MGP_WIRE_BLOB(CreateRenderState, MGPRenderStateDesc, Blob)
|
||||||
@@ -541,6 +546,17 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// P5c (rv), CONTRACT-P5C.md §5.3. Whether set_context_values can cross RIGHT NOW: a live,
|
||||||
|
// started session whose tables are not being torn down. PipeFill.cpp gates BOTH halves of
|
||||||
|
// the row on this - the emission and the residual-fill skip - so a configured-but-wireless
|
||||||
|
// transport (the bring-up window, a server-role-only fixture) keeps the pull, and the two
|
||||||
|
// can never disagree about who supplies the eight fields.
|
||||||
|
Bool ContextValuesWireLive() {
|
||||||
|
ClientSession* session = ClientSession::Active();
|
||||||
|
return session != nullptr && session->Started() &&
|
||||||
|
!g_clientTablesUninstalled.load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
ObjectDeathEmit EmitObjectDeathRecord(MG_Pipe::MGPipeKind kind, Uint64 lifetimeId) {
|
ObjectDeathEmit EmitObjectDeathRecord(MG_Pipe::MGPipeKind kind, Uint64 lifetimeId) {
|
||||||
using MG_Pipe::MGPipeHandle;
|
using MG_Pipe::MGPipeHandle;
|
||||||
|
|
||||||
@@ -628,6 +644,7 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
gMGPipeContext.SetVertexAttribDefaults = &Wire_SetVertexAttribDefaults;
|
gMGPipeContext.SetVertexAttribDefaults = &Wire_SetVertexAttribDefaults;
|
||||||
gMGPipeContext.SetPixelPackState = &Wire_SetPixelPackState;
|
gMGPipeContext.SetPixelPackState = &Wire_SetPixelPackState;
|
||||||
gMGPipeContext.SetPatchState = &Wire_SetPatchState;
|
gMGPipeContext.SetPatchState = &Wire_SetPatchState;
|
||||||
|
gMGPipeContext.SetContextValues = &Wire_SetContextValues;
|
||||||
gMGPipeContext.SetResidualValueState = &Wire_SetResidualValueState;
|
gMGPipeContext.SetResidualValueState = &Wire_SetResidualValueState;
|
||||||
gMGPipeContext.SetTextureParams = &Wire_SetTextureParams;
|
gMGPipeContext.SetTextureParams = &Wire_SetTextureParams;
|
||||||
gMGPipeContext.ResourceSubData = &Wire_ResourceSubData;
|
gMGPipeContext.ResourceSubData = &Wire_ResourceSubData;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
// THE CLIENT ARM OF R-17's ROUTING: the encode twin of `gMGPipeWireRecordApply`. Owner: c1.
|
// THE CLIENT ARM OF R-17's ROUTING: the encode twin of `gMGPipeWireRecordApply`. Owner: c1.
|
||||||
//
|
//
|
||||||
// Thirty-seven thin emitters over `ClientSession::EmitAndWait`, installed over the two
|
// Thirty-eight thin emitters over `ClientSession::EmitAndWait`, installed over the two
|
||||||
// generated tables and the escape table that `MG_Pipe/PipeRoute.h` declares, so that under
|
// generated tables and the escape table that `MG_Pipe/PipeRoute.h` declares, so that under
|
||||||
// split every resource, CSO, texture and program record leaves the GL thread as a WIRE RECORD
|
// split every resource, CSO, texture and program record leaves the GL thread as a WIRE RECORD
|
||||||
// instead of executing synchronously against a context the apply thread now owns.
|
// instead of executing synchronously against a context the apply thread now owns.
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
namespace MobileGL::MG_Remote::Client {
|
namespace MobileGL::MG_Remote::Client {
|
||||||
|
|
||||||
// Installs the thirty-seven wire emitters over gMGPipeScreen / gMGPipeContext /
|
// Installs the thirty-eight wire emitters over gMGPipeScreen / gMGPipeContext /
|
||||||
// gMGPipeRouteEscapes and records the arm. Idempotent.
|
// gMGPipeRouteEscapes and records the arm. Idempotent.
|
||||||
void InstallClientWireTables();
|
void InstallClientWireTables();
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
// deletes that reach a process with no session run the applier as they do under monolith.
|
// deletes that reach a process with no session run the applier as they do under monolith.
|
||||||
void ReinstallMonolithAfterTeardown();
|
void ReinstallMonolithAfterTeardown();
|
||||||
|
|
||||||
// How many records the thirty-seven emitters have published. It counts the ROUTED rows
|
// How many records the thirty-eight emitters have published. It counts the ROUTED rows
|
||||||
// only - a resource_create, a set_vertex_buffers, a create_shader_state - and never the
|
// only - a resource_create, a set_vertex_buffers, a create_shader_state - and never the
|
||||||
// five class-B verbs, so it is the one number that says "the resource/CSO/state path really
|
// five class-B verbs, so it is the one number that says "the resource/CSO/state path really
|
||||||
// ran" as opposed to "a Clear crossed".
|
// ran" as opposed to "a Clear crossed".
|
||||||
@@ -106,6 +106,12 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
// caller then makes the direct call the record replaced.
|
// caller then makes the direct call the record replaced.
|
||||||
Bool EmitApplierResetRecord();
|
Bool EmitApplierResetRecord();
|
||||||
|
|
||||||
|
// P5c (rv), CONTRACT-P5C.md §5.3: whether set_context_values can cross right now (a live,
|
||||||
|
// started session, tables not being torn down). PipeFill.cpp gates the record's emission
|
||||||
|
// AND the residual-fill skip for its eight fields on this one answer, so the two halves
|
||||||
|
// can never disagree about who supplies them.
|
||||||
|
Bool ContextValuesWireLive();
|
||||||
|
|
||||||
// The three answers a death notice can produce (§5.2): the record crossed; the client's
|
// The three answers a death notice can produce (§5.2): the record crossed; the client's
|
||||||
// own allocator cannot resolve the dying object (the server never saw it, so there is no
|
// own allocator cannot resolve the dying object (the server never saw it, so there is no
|
||||||
// twin to kill and NOTHING crossed); or no live session could carry the record. The
|
// twin to kill and NOTHING crossed); or no live session could carry the record. The
|
||||||
|
|||||||
@@ -783,6 +783,11 @@ namespace MobileGL::MG_Remote::Server {
|
|||||||
static_cast<GLenum>(bind.Access),
|
static_cast<GLenum>(bind.Access),
|
||||||
static_cast<GLenum>(bind.Format));
|
static_cast<GLenum>(bind.Format));
|
||||||
++m_imageBinds;
|
++m_imageBinds;
|
||||||
|
// P5c (rv): an image bind moves the frontend's texture bind generation, and this verb
|
||||||
|
// carries no set_shader_images alongside it - so the server-side shutter serial the
|
||||||
|
// accessors now answer with (CONTRACT-P5C.md §5.3) moves here, at the one place the
|
||||||
|
// event reaches the applier's side.
|
||||||
|
MG_Pipe::MGPipeApplierNoteTextureStateMoved();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -241,7 +241,8 @@ namespace MobileGL::MG_Remote::Wire {
|
|||||||
X(SetStorageBlockBinding, MGPStorageBlockBinding) \
|
X(SetStorageBlockBinding, MGPStorageBlockBinding) \
|
||||||
X(CopyFramebufferToTexture, MGPCopyFromFramebuffer) \
|
X(CopyFramebufferToTexture, MGPCopyFromFramebuffer) \
|
||||||
X(ApplierReset, MGPApplierReset) \
|
X(ApplierReset, MGPApplierReset) \
|
||||||
X(ObjectDeath, MGPHandleOnly)
|
X(ObjectDeath, MGPHandleOnly) \
|
||||||
|
X(SetContextValues, MGPContextValues)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -2101,6 +2102,17 @@ namespace MobileGL::MG_Remote::Wire {
|
|||||||
return m_verbs != nullptr &&
|
return m_verbs != nullptr &&
|
||||||
m_verbs->OnObjectDeath(*static_cast<const MGPHandleOnly*>(payload));
|
m_verbs->OnObjectDeath(*static_cast<const MGPHandleOnly*>(payload));
|
||||||
|
|
||||||
|
// ---- P5c rv (CONTRACT-P5C.md §5.3): the residual-value record, opcode 79 -------------
|
||||||
|
//
|
||||||
|
// An ordinary set_* row, unlike the two control records beside it: a fixed-width POD
|
||||||
|
// with no blob, no tail and no reply, so the bounds gate is the whole validation and
|
||||||
|
// the arm is the applier entry point - the same shape as set_pixel_pack_state beside
|
||||||
|
// it. There is no sink half and no acceptance answer: the write into gPipeInputs is
|
||||||
|
// the whole effect.
|
||||||
|
case MGPWireOp::SetContextValues:
|
||||||
|
MGPipeApplySetContextValues(*static_cast<const MGPContextValues*>(payload));
|
||||||
|
return true;
|
||||||
|
|
||||||
case MGPWireOp::SetSwapInterval:
|
case MGPWireOp::SetSwapInterval:
|
||||||
// Class C, wave 3 (census-classC.md "static cross"); not a verb (FillPoints.def:21).
|
// Class C, wave 3 (census-classC.md "static cross"); not a verb (FillPoints.def:21).
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -256,8 +256,9 @@ namespace MobileGL {
|
|||||||
// four words on a wire are not the value unless the class travels with them:
|
// four words on a wire are not the value unless the class travels with them:
|
||||||
// glVertexAttrib4f(loc, 1.5f, ...) leaves 1 in intValue and 0x3FC00000 in
|
// glVertexAttrib4f(loc, 1.5f, ...) leaves 1 in intValue and 0x3FC00000 in
|
||||||
// floatValue. set_vertex_attrib_defaults carries this as MGPAttribValue's
|
// floatValue. set_vertex_attrib_defaults carries this as MGPAttribValue's
|
||||||
// ValueClass so the applier can redo the conversion instead of memcpying one
|
// ValueClass AND, since P5c rv (CONTRACT-P5C.md §5.3), all three views
|
||||||
// view into all three.
|
// verbatim - the applier writes each view from its own array rather than
|
||||||
|
// redoing the conversion.
|
||||||
//
|
//
|
||||||
// It is kept BESIDE the array rather than inside CurrentVertexAttributeValue
|
// It is kept BESIDE the array rather than inside CurrentVertexAttributeValue
|
||||||
// because that struct is mirrored into PipeInputs and compared there by a
|
// because that struct is mirrored into PipeInputs and compared there by a
|
||||||
|
|||||||
@@ -197,11 +197,15 @@ TEST_F(FieldOwnershipTest, TheClassSizesPartitionTheFieldSet) {
|
|||||||
EXPECT_EQ(counted[static_cast<SizeT>(MGPipeFieldOwnership::kBarrierPulled)],
|
EXPECT_EQ(counted[static_cast<SizeT>(MGPipeFieldOwnership::kBarrierPulled)],
|
||||||
kMGPipeBarrierPulledFieldCount);
|
kMGPipeBarrierPulledFieldCount);
|
||||||
EXPECT_EQ(counted[static_cast<SizeT>(MGPipeFieldOwnership::kFatal)], kMGPipeFatalFieldCount);
|
EXPECT_EQ(counted[static_cast<SizeT>(MGPipeFieldOwnership::kFatal)], kMGPipeFatalFieldCount);
|
||||||
// The census's own arithmetic (scout-unmigrated-census section 2.1): 31 of the 63 fields
|
// The census's own arithmetic (scout-unmigrated-census section 2.1), updated by P5c rv
|
||||||
// are served by NO pushed record - 24 non-sticky plus the seven sticky - so 32 are.
|
// (CONTRACT-P5C.md §5.3): rv moved the NINE value-class rows to RECORD-SUPPLIED through
|
||||||
EXPECT_EQ(kMGPipeRecordSuppliedFieldCount, SizeT{32});
|
// set_context_values / the amended set_vertex_attrib_defaults and the three texture
|
||||||
|
// shutters to APPLIER-DERIVED, so 22 of the 63 fields are served by NO pushed record -
|
||||||
|
// 15 BARRIER-PULLED (the object class: nine non-sticky rows plus six of the seven sticky
|
||||||
|
// forwards), four APPLIER-DERIVED and three FATAL - and 41 are.
|
||||||
|
EXPECT_EQ(kMGPipeRecordSuppliedFieldCount, SizeT{41});
|
||||||
EXPECT_EQ(kMGPipeApplierDerivedFieldCount + kMGPipeBarrierPulledFieldCount + kMGPipeFatalFieldCount,
|
EXPECT_EQ(kMGPipeApplierDerivedFieldCount + kMGPipeBarrierPulledFieldCount + kMGPipeFatalFieldCount,
|
||||||
SizeT{31});
|
SizeT{22});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FieldOwnershipTest, EveryBarrierPulledRowNamesTheRetiringPhase) {
|
TEST_F(FieldOwnershipTest, EveryBarrierPulledRowNamesTheRetiringPhase) {
|
||||||
@@ -217,36 +221,56 @@ TEST_F(FieldOwnershipTest, EveryBarrierPulledRowNamesTheRetiringPhase) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The 21 the reduced path actually reads (scout-unmigrated-census section 3: the union of
|
// The 21 the reduced path actually reads (scout-unmigrated-census section 3: the union of
|
||||||
// kClear's 7, kDraw's 19 and kReadback's 12). Twenty of them are BARRIER-PULLED; the
|
// kClear's 7, kDraw's 19 and kReadback's 12) - AS P5c rv LEFT THEM (CONTRACT-P5C.md §5.3):
|
||||||
// twenty-first is GetPixelStoreParameters, whose PACK half the applier writes and whose UNPACK
|
// NINE moved to RECORD-SUPPLIED through set_context_values (the two texture-unit counters,
|
||||||
// half has no carrier and no backend reader at all.
|
// the touched-count array, the five XFB values) plus GetCurrentVertexAttribute through the
|
||||||
|
// amended set_vertex_attrib_defaults payload, and the three texture shutters moved to
|
||||||
|
// APPLIER-DERIVED ("a shutter, not a value: the server answers from its own Serial"). What
|
||||||
|
// remains BARRIER-PULLED is EXACTLY the object class - nine non-sticky fields whose storage
|
||||||
|
// is a frontend heap reference no record can carry - plus GetPixelStoreParameters, whose
|
||||||
|
// PACK half the applier writes and whose UNPACK half has no carrier and no backend reader at
|
||||||
|
// all.
|
||||||
TEST_F(FieldOwnershipTest, TheReducedPathsUnmigratedFieldsAreAllAccountedFor) {
|
TEST_F(FieldOwnershipTest, TheReducedPathsUnmigratedFieldsAreAllAccountedFor) {
|
||||||
const MGPipeInputField pulled[] = {
|
const MGPipeInputField pulled[] = {
|
||||||
MGPipeInputField::GetActiveTextureUnit,
|
|
||||||
MGPipeInputField::GetBoundVertexArray,
|
MGPipeInputField::GetBoundVertexArray,
|
||||||
MGPipeInputField::GetBufferBindingSlot,
|
MGPipeInputField::GetBufferBindingSlot,
|
||||||
MGPipeInputField::GetBufferBindingPoint,
|
MGPipeInputField::GetBufferBindingPoint,
|
||||||
MGPipeInputField::GetTouchedBufferBindingPointCount,
|
|
||||||
MGPipeInputField::GetCurrentVertexAttribute,
|
|
||||||
MGPipeInputField::GetFramebufferBindingSlot,
|
MGPipeInputField::GetFramebufferBindingSlot,
|
||||||
MGPipeInputField::GetImageTextureBinding,
|
MGPipeInputField::GetImageTextureBinding,
|
||||||
MGPipeInputField::GetMaxTouchedTextureUnit,
|
|
||||||
MGPipeInputField::GetProgramForDraw,
|
|
||||||
MGPipeInputField::GetSamplingResolutionGeneration,
|
|
||||||
MGPipeInputField::GetTextureBindGeneration,
|
|
||||||
MGPipeInputField::GetTextureContextId,
|
|
||||||
MGPipeInputField::GetTextureUnitObject,
|
MGPipeInputField::GetTextureUnitObject,
|
||||||
MGPipeInputField::GetTransformFeedbackCapturedVertices,
|
MGPipeInputField::GetProgramForDraw,
|
||||||
MGPipeInputField::GetTransformFeedbackGeneration,
|
MGPipeInputField::GetProgramForDispatch,
|
||||||
MGPipeInputField::GetTransformFeedbackProgram,
|
MGPipeInputField::GetTransformFeedbackProgram,
|
||||||
MGPipeInputField::GetBoundTransformFeedbackLifetimeId,
|
|
||||||
MGPipeInputField::IsTransformFeedbackActive,
|
|
||||||
MGPipeInputField::IsTransformFeedbackPaused,
|
|
||||||
};
|
};
|
||||||
for (const auto field : pulled) {
|
for (const auto field : pulled) {
|
||||||
EXPECT_EQ(MGPipeFieldOwnershipOf(field), MGPipeFieldOwnership::kBarrierPulled)
|
EXPECT_EQ(MGPipeFieldOwnershipOf(field), MGPipeFieldOwnership::kBarrierPulled)
|
||||||
<< kMGPipeInputFieldNames[Index(field)] << " left the reduced path's debt";
|
<< kMGPipeInputFieldNames[Index(field)] << " left the reduced path's debt";
|
||||||
}
|
}
|
||||||
|
// rv's exit line, pinned as a SET and not only as nine rows: the non-sticky
|
||||||
|
// BARRIER-PULLED list above is ALL the non-sticky debt - value-class membership is zero
|
||||||
|
// (CONTRACT-P5C.md §7 table 2) - and the only other BARRIER-PULLED rows are six of the
|
||||||
|
// seven sticky forwards (the seventh, InvalidateCompileEnv, is FATAL since P5c ev).
|
||||||
|
const MGPipeInputField pulledSticky[] = {
|
||||||
|
MGPipeInputField::GetBufferBindingPointCount,
|
||||||
|
MGPipeInputField::GetProgramObject,
|
||||||
|
MGPipeInputField::GetTextureObject,
|
||||||
|
MGPipeInputField::HasOpenTransformFeedbackSpan,
|
||||||
|
MGPipeInputField::ValidateProgramName,
|
||||||
|
MGPipeInputField::RecordError,
|
||||||
|
};
|
||||||
|
SizeT pulledCount = 0;
|
||||||
|
for (SizeT i = 0; i < kMGPipeInputFieldCount; ++i) {
|
||||||
|
const auto field = static_cast<MGPipeInputField>(i);
|
||||||
|
if (kMGPipeFieldOwnership[i] != MGPipeFieldOwnership::kBarrierPulled) continue;
|
||||||
|
++pulledCount;
|
||||||
|
Bool named = false;
|
||||||
|
for (const auto f : pulled) named = named || field == f;
|
||||||
|
for (const auto f : pulledSticky) named = named || field == f;
|
||||||
|
EXPECT_TRUE(named) << kMGPipeInputFieldNames[i]
|
||||||
|
<< " is BARRIER-PULLED and not in the pinned object-class list";
|
||||||
|
}
|
||||||
|
EXPECT_EQ(pulledCount, 15u) << "9 non-sticky object rows + 6 sticky forwards";
|
||||||
|
EXPECT_EQ(pulledCount, kMGPipeBarrierPulledFieldCount);
|
||||||
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetPixelStoreParameters),
|
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetPixelStoreParameters),
|
||||||
MGPipeFieldOwnership::kApplierDerived);
|
MGPipeFieldOwnership::kApplierDerived);
|
||||||
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetPixelStoreParameters, 0u),
|
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetPixelStoreParameters, 0u),
|
||||||
@@ -271,6 +295,36 @@ TEST_F(FieldOwnershipTest, TheReducedPathsUnmigratedFieldsAreAllAccountedFor) {
|
|||||||
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetProgramForDispatch),
|
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetProgramForDispatch),
|
||||||
MGPipeFieldOwnershipOf(MGPipeInputField::GetProgramForDraw))
|
MGPipeFieldOwnershipOf(MGPipeInputField::GetProgramForDraw))
|
||||||
<< "GetProgramForDispatch is GetProgramForDraw's twin and must share its class";
|
<< "GetProgramForDispatch is GetProgramForDraw's twin and must share its class";
|
||||||
|
|
||||||
|
// AND THE NINE rv RETIRED, asserted in their NEW classes rather than deleted: a row that
|
||||||
|
// quietly fell back to BARRIER-PULLED is exactly what this list is for.
|
||||||
|
const MGPipeInputField suppliedByContextValues[] = {
|
||||||
|
MGPipeInputField::GetActiveTextureUnit,
|
||||||
|
MGPipeInputField::GetMaxTouchedTextureUnit,
|
||||||
|
MGPipeInputField::GetTouchedBufferBindingPointCount,
|
||||||
|
MGPipeInputField::IsTransformFeedbackActive,
|
||||||
|
MGPipeInputField::IsTransformFeedbackPaused,
|
||||||
|
MGPipeInputField::GetTransformFeedbackGeneration,
|
||||||
|
MGPipeInputField::GetBoundTransformFeedbackLifetimeId,
|
||||||
|
MGPipeInputField::GetTransformFeedbackCapturedVertices,
|
||||||
|
};
|
||||||
|
for (const auto field : suppliedByContextValues) {
|
||||||
|
EXPECT_EQ(MGPipeFieldOwnershipOf(field), MGPipeFieldOwnership::kRecordSupplied)
|
||||||
|
<< kMGPipeInputFieldNames[Index(field)] << " no longer rides set_context_values";
|
||||||
|
}
|
||||||
|
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetCurrentVertexAttribute),
|
||||||
|
MGPipeFieldOwnership::kRecordSupplied)
|
||||||
|
<< "the amended set_vertex_attrib_defaults payload carries all three views";
|
||||||
|
const MGPipeInputField shutters[] = {
|
||||||
|
MGPipeInputField::GetSamplingResolutionGeneration,
|
||||||
|
MGPipeInputField::GetTextureBindGeneration,
|
||||||
|
MGPipeInputField::GetTextureContextId,
|
||||||
|
};
|
||||||
|
for (const auto field : shutters) {
|
||||||
|
EXPECT_EQ(MGPipeFieldOwnershipOf(field), MGPipeFieldOwnership::kApplierDerived)
|
||||||
|
<< kMGPipeInputFieldNames[Index(field)]
|
||||||
|
<< " is a shutter: the server answers from its own Serial";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FieldOwnershipTest, TheSevenStickyForwardsAgreeWithTheirFieldRows) {
|
TEST_F(FieldOwnershipTest, TheSevenStickyForwardsAgreeWithTheirFieldRows) {
|
||||||
@@ -395,19 +449,76 @@ TEST_F(FieldOwnershipTest, ARecordSuppliedFieldIsReadableAfterAServerStamp) {
|
|||||||
(void)gPipeInputs.GetRenderStateParameters();
|
(void)gPipeInputs.GetRenderStateParameters();
|
||||||
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
||||||
// The pixel store is in kReadback's class, not kClear's, so its readable half is exercised
|
// The pixel store is in kReadback's class, not kClear's, so its readable half is exercised
|
||||||
// under the verb that actually reads it.
|
// under the verb that actually reads it. And P5c rv's record-supplied rows join it there:
|
||||||
|
// GetActiveTextureUnit is exactly the read that used to count into `rsp`.
|
||||||
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
||||||
(void)gPipeInputs.GetPixelStoreParameters(false); // the half that has a carrier
|
(void)gPipeInputs.GetPixelStoreParameters(false); // the half that has a carrier
|
||||||
|
(void)gPipeInputs.GetActiveTextureUnit(); // P5c rv: set_context_values carries it
|
||||||
|
(void)gPipeInputs.GetMaxTouchedTextureUnit();
|
||||||
|
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
||||||
|
// And a shutter answers the applier's own Serial under a server stamp (APPLIER-DERIVED),
|
||||||
|
// not the client's residual-fill copy: still zero pulls, and the answer MOVES when the
|
||||||
|
// applier's texture state does.
|
||||||
|
(void)gPipeInputs.GetTextureBindGeneration();
|
||||||
|
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
||||||
|
}
|
||||||
|
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3): the residual-value record's applier write, read back through
|
||||||
|
// the accessors a backend uses, under the stamps that publish them - and the three texture
|
||||||
|
// shutters answering the applier's own serials rather than the client's fill. kReadback's
|
||||||
|
// class carries the two texture-unit counters, kDraw's the rest.
|
||||||
|
TEST_F(FieldOwnershipTest, SetContextValuesLandsInPipeInputsAndTheShuttersAnswerTheApplier) {
|
||||||
|
MGPContextValues values{};
|
||||||
|
values.ActiveTextureUnit = 5;
|
||||||
|
values.MaxTouchedTextureUnit = 23;
|
||||||
|
values.TouchedBufferBindingPointCount[static_cast<Uint32>(BufferTarget::Uniform)] = 7;
|
||||||
|
values.IsTransformFeedbackActive = 1;
|
||||||
|
values.IsTransformFeedbackPaused = 0;
|
||||||
|
values.TransformFeedbackGeneration = 0x1112131415161718ull;
|
||||||
|
values.BoundTransformFeedbackLifetimeId = 0x2122232425262728ull;
|
||||||
|
values.TransformFeedbackCapturedVertices = 0x3132333435363738ull;
|
||||||
|
MGPipeApplySetContextValues(values);
|
||||||
|
|
||||||
|
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetActiveTextureUnit(), 5);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetMaxTouchedTextureUnit(), 23);
|
||||||
|
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTouchedBufferBindingPointCount(BufferTarget::Uniform), SizeT{7});
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTouchedBufferBindingPointCount(BufferTarget::Vertex), SizeT{0});
|
||||||
|
EXPECT_TRUE(gPipeInputs.IsTransformFeedbackActive());
|
||||||
|
EXPECT_FALSE(gPipeInputs.IsTransformFeedbackPaused());
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTransformFeedbackGeneration(), 0x1112131415161718ull);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetBoundTransformFeedbackLifetimeId(), 0x2122232425262728ull);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTransformFeedbackCapturedVertices(), 0x3132333435363738ull);
|
||||||
|
// Eight record-supplied reads and not one residual pull.
|
||||||
|
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
||||||
|
|
||||||
|
// The three shutters answer the applier's own serials under a stamped verb. They are
|
||||||
|
// SHUTTERS - the value matters only in that it MOVES when the server's texture state does
|
||||||
|
// and never walks backwards - so the pin is the identity with the applier's counters, not
|
||||||
|
// any particular number.
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTextureBindGeneration(), MGPipeApplierTextureShutterSerial());
|
||||||
|
EXPECT_EQ(gPipeInputs.GetSamplingResolutionGeneration(), MGPipeApplierTextureShutterSerial());
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTextureContextId(), MGPipeApplierContextSerial());
|
||||||
|
const Uint64 before = MGPipeApplierTextureShutterSerial();
|
||||||
|
MGPipeApplierNoteTextureStateMoved();
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTextureBindGeneration(), before + 1)
|
||||||
|
<< "a texture-state apply moved the serial but the shutter did not answer with it";
|
||||||
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FieldOwnershipTest, ABarrierPulledReadAfterAServerStampIsCountedNotFatal) {
|
TEST_F(FieldOwnershipTest, ABarrierPulledReadAfterAServerStampIsCountedNotFatal) {
|
||||||
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
// P5c rv: the exemplars are OBJECT-class now - the value rows this case used to read
|
||||||
|
// (GetActiveTextureUnit / GetTextureContextId / GetMaxTouchedTextureUnit) are
|
||||||
|
// RECORD-SUPPLIED / APPLIER-DERIVED since rv, and reading them here would count nothing.
|
||||||
|
// The three below are all of kDraw's class, all SharedPtr reads, and all safe on
|
||||||
|
// never-filled storage.
|
||||||
|
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||||
ASSERT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
ASSERT_EQ(MGPipeResidualPullCount(), Uint64{0});
|
||||||
(void)gPipeInputs.GetActiveTextureUnit();
|
(void)gPipeInputs.GetBoundVertexArray();
|
||||||
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{1});
|
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{1});
|
||||||
(void)gPipeInputs.GetTextureContextId();
|
(void)gPipeInputs.GetProgramForDraw();
|
||||||
(void)gPipeInputs.GetMaxTouchedTextureUnit();
|
(void)gPipeInputs.GetTransformFeedbackProgram();
|
||||||
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{3});
|
EXPECT_EQ(MGPipeResidualPullCount(), Uint64{3});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,16 +563,18 @@ TEST_F(FieldOwnershipTest, TheAppliersOwnClearDisarmsTheStampWithoutTheClientsFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The verb's own may-read table still holds on the server: kClear does not read
|
// The verb's own may-read table still holds on the server: kClear does not read
|
||||||
// GetActiveTextureUnit, so reading it there is a stale answer rather than a residual pull,
|
// GetProgramForDraw, so reading it there is a stale answer rather than a residual pull,
|
||||||
// and it stays Fatal. Counting it would trade a loud staleness for a quiet one.
|
// and it stays Fatal. Counting it would trade a loud staleness for a quiet one.
|
||||||
|
// (P5c rv: the exemplar moved - GetActiveTextureUnit is RECORD-SUPPLIED since rv and would
|
||||||
|
// say nothing about the pulled set here.)
|
||||||
TEST_F(FieldOwnershipTest, ABarrierPulledFieldOutsideTheVerbsClassIsStillFatal) {
|
TEST_F(FieldOwnershipTest, ABarrierPulledFieldOutsideTheVerbsClassIsStillFatal) {
|
||||||
#if MGTEST_HAVE_FORK
|
#if MGTEST_HAVE_FORK
|
||||||
const ChildResult r = RunInChild([] {
|
const ChildResult r = RunInChild([] {
|
||||||
MGPipeServerStampVerbBoundary(MGPipeVerb::Clear);
|
MGPipeServerStampVerbBoundary(MGPipeVerb::Clear);
|
||||||
(void)gPipeInputs.GetActiveTextureUnit(); // BARRIER-PULLED, but not in kClear's class
|
(void)gPipeInputs.GetProgramForDraw(); // BARRIER-PULLED, but not in kClear's class
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log;
|
ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log;
|
||||||
EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetActiveTextureUnit@Clear\"}"), std::string::npos)
|
EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetProgramForDraw@Clear\"}"), std::string::npos)
|
||||||
<< r.Log;
|
<< r.Log;
|
||||||
EXPECT_EQ(r.Log.find("BARRIER-PULLED"), std::string::npos) << r.Log;
|
EXPECT_EQ(r.Log.find("BARRIER-PULLED"), std::string::npos) << r.Log;
|
||||||
#else
|
#else
|
||||||
@@ -473,8 +586,8 @@ TEST_F(FieldOwnershipTest, ResidualPullsReachThePublishedPerFrameCounter) {
|
|||||||
namespace PS = MG_Util::PipeStats;
|
namespace PS = MG_Util::PipeStats;
|
||||||
PS::SetEnabledForTesting(true);
|
PS::SetEnabledForTesting(true);
|
||||||
PS::ResetForTesting();
|
PS::ResetForTesting();
|
||||||
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||||
(void)gPipeInputs.GetActiveTextureUnit();
|
(void)gPipeInputs.GetBoundVertexArray();
|
||||||
EXPECT_EQ(PS::FrameCalls(PS::CallClass::ResidualPulls), Uint64{1});
|
EXPECT_EQ(PS::FrameCalls(PS::CallClass::ResidualPulls), Uint64{1});
|
||||||
EXPECT_NE(PS::FormatWindowLine().find("rsp="), std::string::npos) << PS::FormatWindowLine();
|
EXPECT_NE(PS::FormatWindowLine().find("rsp="), std::string::npos) << PS::FormatWindowLine();
|
||||||
PS::ResetForTesting();
|
PS::ResetForTesting();
|
||||||
@@ -484,28 +597,30 @@ TEST_F(FieldOwnershipTest, ResidualPullsReachThePublishedPerFrameCounter) {
|
|||||||
#if MGTEST_HAVE_FORK
|
#if MGTEST_HAVE_FORK
|
||||||
|
|
||||||
// R-7.3's proof that the instrumentation can go red. An instrumentation that cannot is
|
// R-7.3's proof that the instrumentation can go red. An instrumentation that cannot is
|
||||||
// decoration, and the set it counts is not empty.
|
// decoration, and the set it counts is not empty. (P5c rv: the exemplar is object-class now -
|
||||||
|
// the value rows this case was written against ride set_context_values and answer
|
||||||
|
// RECORD-SUPPLIED.)
|
||||||
TEST_F(FieldOwnershipTest, StrictErrorsTurnsABarrierPulledReadIntoANamedAbort) {
|
TEST_F(FieldOwnershipTest, StrictErrorsTurnsABarrierPulledReadIntoANamedAbort) {
|
||||||
const ChildResult r = RunInChild([] {
|
const ChildResult r = RunInChild([] {
|
||||||
MG_Config::Ipc.StrictErrors = true;
|
MG_Config::Ipc.StrictErrors = true;
|
||||||
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||||
(void)gPipeInputs.GetActiveTextureUnit();
|
(void)gPipeInputs.GetBoundVertexArray();
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log;
|
ASSERT_TRUE(DiedOfAbort(r)) << DescribeStatus(r) << "\n" << r.Log;
|
||||||
EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetActiveTextureUnit@ReadPixels\"}"),
|
EXPECT_NE(r.Log.find("Fatal{UnmigratedPipeInput, \"GetBoundVertexArray@DrawArrays\"}"),
|
||||||
std::string::npos)
|
std::string::npos)
|
||||||
<< r.Log;
|
<< r.Log;
|
||||||
EXPECT_NE(r.Log.find("BARRIER-PULLED"), std::string::npos) << r.Log;
|
EXPECT_NE(r.Log.find("BARRIER-PULLED"), std::string::npos) << r.Log;
|
||||||
EXPECT_NE(r.Log.find("MOBILEGL_IPC_STRICT_ERRORS=1"), std::string::npos) << r.Log;
|
EXPECT_NE(r.Log.find("MOBILEGL_IPC_STRICT_ERRORS=1"), std::string::npos) << r.Log;
|
||||||
// The strict line names the phase that owes the answer; a strict abort that did not would
|
// The strict line names the phase that owes the answer; a strict abort that did not would
|
||||||
// leave the reader exactly where the gate found them.
|
// leave the reader exactly where the gate found them.
|
||||||
EXPECT_NE(r.Log.find("retires in P3b/P4b"), std::string::npos) << r.Log;
|
EXPECT_NE(r.Log.find("retires in P8]"), std::string::npos) << r.Log;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FieldOwnershipTest, TheSameReadWithoutStrictErrorsSurvivesAndIsCounted) {
|
TEST_F(FieldOwnershipTest, TheSameReadWithoutStrictErrorsSurvivesAndIsCounted) {
|
||||||
const ChildResult r = RunInChild([] {
|
const ChildResult r = RunInChild([] {
|
||||||
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||||
(void)gPipeInputs.GetActiveTextureUnit();
|
(void)gPipeInputs.GetBoundVertexArray();
|
||||||
if (MGPipeResidualPullCount() != 1) ::_exit(7);
|
if (MGPipeResidualPullCount() != 1) ::_exit(7);
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(ExitedWith(r, 0)) << DescribeStatus(r) << "\n" << r.Log;
|
ASSERT_TRUE(ExitedWith(r, 0)) << DescribeStatus(r) << "\n" << r.Log;
|
||||||
|
|||||||
@@ -127,10 +127,11 @@ TEST(PipeCatalogue, GeneratedTablesHoldTheWholeCatalogue) {
|
|||||||
// The per-class counts PipeCalls.def documents in its header.
|
// The per-class counts PipeCalls.def documents in its header.
|
||||||
// kScreen is 11 + P5c's applier_reset (MG_Remote/CONTRACT-P5C.md §5.1); kCtxObject is
|
// kScreen is 11 + P5c's applier_reset (MG_Remote/CONTRACT-P5C.md §5.1); kCtxObject is
|
||||||
// 9 + P5c's object_death (§5.2), the framebuffer family's first wire delete opcode.
|
// 9 + P5c's object_death (§5.2), the framebuffer family's first wire delete opcode.
|
||||||
|
// kCtxState is 17 + P5c rv's set_context_values (§5.3), the residual-value record.
|
||||||
EXPECT_EQ(ClassCount<kScreen>(), 12u);
|
EXPECT_EQ(ClassCount<kScreen>(), 12u);
|
||||||
EXPECT_EQ(ClassCount<kCtxQuery>(), 8u);
|
EXPECT_EQ(ClassCount<kCtxQuery>(), 8u);
|
||||||
EXPECT_EQ(ClassCount<kCtxCso>(), 13u);
|
EXPECT_EQ(ClassCount<kCtxCso>(), 13u);
|
||||||
EXPECT_EQ(ClassCount<kCtxState>(), 17u);
|
EXPECT_EQ(ClassCount<kCtxState>(), 18u);
|
||||||
EXPECT_EQ(ClassCount<kCtxObject>(), 10u);
|
EXPECT_EQ(ClassCount<kCtxObject>(), 10u);
|
||||||
// 13 + the five P5b-appended verbs (MG_Remote/CONTRACT-P5B.md): bind_shader_image,
|
// 13 + the five P5b-appended verbs (MG_Remote/CONTRACT-P5B.md): bind_shader_image,
|
||||||
// patch_parameter, bind_stream_output, set_storage_block_binding,
|
// patch_parameter, bind_stream_output, set_storage_block_binding,
|
||||||
@@ -142,11 +143,12 @@ TEST(PipeCatalogue, GeneratedTablesHoldTheWholeCatalogue) {
|
|||||||
// migrated, keep pulling" means (plan B section 4.1).
|
// migrated, keep pulling" means (plan B section 4.1).
|
||||||
//
|
//
|
||||||
// UNTIL P5 R-17 THAT WAS EVERY ROW, and this case said so. It is now EXACTLY THE 41 ROWS WITH
|
// UNTIL P5 R-17 THAT WAS EVERY ROW, and this case said so. It is now EXACTLY THE 41 ROWS WITH
|
||||||
// NO MGPipeApply* ENTRY POINT (78 - the 37 that have one; the number was 34 at P5, 39 after
|
// NO MGPipeApply* ENTRY POINT (79 - the 38 that have one; the number was 34 at P5, 39 after
|
||||||
// P5b's five sink-only verbs): the other 37 have an applier, R-17 installs adapters over them,
|
// P5b's five sink-only verbs, and rv's set_context_values grew BOTH sides of the difference):
|
||||||
|
// the other 38 have an applier, R-17 installs adapters over them,
|
||||||
// and a null there would no longer mean "keep pulling" - `MG_Impl/Pipe`'s call sites go through
|
// and a null there would no longer mean "keep pulling" - `MG_Impl/Pipe`'s call sites go through
|
||||||
// the thunks, so a null would mean "call through a null pointer". The number is asserted rather
|
// the thunks, so a null would mean "call through a null pointer". The number is asserted rather
|
||||||
// than the emptiness, because "37 installed" and "34 still null" are the two halves of a
|
// than the emptiness, because "38 installed" and "41 still null" are the two halves of a
|
||||||
// partition and a case that checked only one of them would pass an installer that had
|
// partition and a case that checked only one of them would pass an installer that had
|
||||||
// overwritten rows it does not own.
|
// overwritten rows it does not own.
|
||||||
// THE NAME IS KEPT, AND SO IS THE STATEMENT IT MAKES - only the ROWS it makes it about have
|
// THE NAME IS KEPT, AND SO IS THE STATEMENT IT MAKES - only the ROWS it makes it about have
|
||||||
@@ -209,8 +211,9 @@ TEST(PipeCatalogue, ExactlyTheRoutedRowsAreInstalledAndTheRestAreStillNull) {
|
|||||||
EXPECT_EQ(installed + nulls, static_cast<SizeT>(kMGPipeCallCount));
|
EXPECT_EQ(installed + nulls, static_cast<SizeT>(kMGPipeCallCount));
|
||||||
|
|
||||||
#if MOBILEGL_PIPE_PUSH
|
#if MOBILEGL_PIPE_PUSH
|
||||||
// 33 + 4 = 37, and the split is the honest shape of R-17 rather than an implementation
|
// 34 + 4 = 38, and the split is the honest shape of R-17 rather than an implementation
|
||||||
// detail: 37 is the number of MGPipeApply* entry points PipeApply.h declares, 33 of them
|
// detail: 38 is the number of MGPipeApply* entry points PipeApply.h declares (37 at P5, and
|
||||||
|
// P5c rv's set_context_values - CONTRACT-P5C.md §5.3 - is the 38th), 34 of them
|
||||||
// fit a GENERATED row and go in the two tables, and FOUR cannot be expressed by any
|
// fit a GENERATED row and go in the two tables, and FOUR cannot be expressed by any
|
||||||
// generated signature and go in the hand-written escape table beside them
|
// generated signature and go in the hand-written escape table beside them
|
||||||
// (ResourceRespecify's uncarried initialBytes, ResourceFlushRange's likewise,
|
// (ResourceRespecify's uncarried initialBytes, ResourceFlushRange's likewise,
|
||||||
@@ -220,8 +223,8 @@ TEST(PipeCatalogue, ExactlyTheRoutedRowsAreInstalledAndTheRestAreStillNull) {
|
|||||||
// BOTH NUMBERS ARE ASSERTED. If the escape table were left out of this case, moving a row
|
// BOTH NUMBERS ARE ASSERTED. If the escape table were left out of this case, moving a row
|
||||||
// out of the generated tables and forgetting to install its escape would read as a smaller
|
// out of the generated tables and forgetting to install its escape would read as a smaller
|
||||||
// "installed" count and nothing else - and the call site would take a null.
|
// "installed" count and nothing else - and the call site would take a null.
|
||||||
EXPECT_EQ(installed, 33u) << "the routed rows and the applier's entry points disagree";
|
EXPECT_EQ(installed, 34u) << "the routed rows and the applier's entry points disagree";
|
||||||
EXPECT_EQ(nulls, static_cast<SizeT>(kMGPipeCallCount) - 33u);
|
EXPECT_EQ(nulls, static_cast<SizeT>(kMGPipeCallCount) - 34u);
|
||||||
const void* const* escapes = reinterpret_cast<const void* const*>(&gMGPipeRouteEscapes);
|
const void* const* escapes = reinterpret_cast<const void* const*>(&gMGPipeRouteEscapes);
|
||||||
SizeT escapesInstalled = 0;
|
SizeT escapesInstalled = 0;
|
||||||
for (SizeT i = 0; i < sizeof(MGPipeRouteEscapes) / sizeof(void*); ++i) {
|
for (SizeT i = 0; i < sizeof(MGPipeRouteEscapes) / sizeof(void*); ++i) {
|
||||||
@@ -229,7 +232,7 @@ TEST(PipeCatalogue, ExactlyTheRoutedRowsAreInstalledAndTheRestAreStillNull) {
|
|||||||
}
|
}
|
||||||
EXPECT_EQ(escapesInstalled, 4u) << "an escape row is null; its call site would take a null "
|
EXPECT_EQ(escapesInstalled, 4u) << "an escape row is null; its call site would take a null "
|
||||||
"pointer rather than fall back to anything";
|
"pointer rather than fall back to anything";
|
||||||
EXPECT_EQ(installed + escapesInstalled, 37u)
|
EXPECT_EQ(installed + escapesInstalled, 38u)
|
||||||
<< "the two tables plus the escapes must be exactly PipeApply.h's entry points";
|
<< "the two tables plus the escapes must be exactly PipeApply.h's entry points";
|
||||||
|
|
||||||
// And the rows that MUST still be null, named rather than counted: these are calls with no
|
// And the rows that MUST still be null, named rather than counted: these are calls with no
|
||||||
@@ -576,9 +579,15 @@ TEST(PipeCatalogue, LateArrivalsAreAppendedWithoutRenumbering) {
|
|||||||
// and object_death a kCtxObject one; both carry no blob, no reply and no tail.
|
// and object_death a kCtxObject one; both carry no blob, no reply and no tail.
|
||||||
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::ApplierReset), 77);
|
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::ApplierReset), 77);
|
||||||
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::ObjectDeath), 78);
|
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::ObjectDeath), 78);
|
||||||
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::kOpCount), 79);
|
// P5c rv (§5.3) appended the residual-value record AFTER the two control records, by the
|
||||||
|
// same rule: opcode 79, and nothing before it moved. It is an ordinary kCtxState set_* row
|
||||||
|
// - fixed POD, no blob, no tail, no reply - with an MGPipeApply* entry point, which the two
|
||||||
|
// control records deliberately do not have.
|
||||||
|
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::SetContextValues), 79);
|
||||||
|
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::kOpCount), 80);
|
||||||
EXPECT_EQ(MGPipeCallFlagsFor(MGPWireOp::ApplierReset), static_cast<Uint32>(kNone));
|
EXPECT_EQ(MGPipeCallFlagsFor(MGPWireOp::ApplierReset), static_cast<Uint32>(kNone));
|
||||||
EXPECT_EQ(MGPipeCallFlagsFor(MGPWireOp::ObjectDeath), static_cast<Uint32>(kNone));
|
EXPECT_EQ(MGPipeCallFlagsFor(MGPWireOp::ObjectDeath), static_cast<Uint32>(kNone));
|
||||||
|
EXPECT_EQ(MGPipeCallFlagsFor(MGPWireOp::SetContextValues), static_cast<Uint32>(kNone));
|
||||||
// And the P5b rows carry what their contract says: one blob (the block name) and nothing
|
// And the P5b rows carry what their contract says: one blob (the block name) and nothing
|
||||||
// else, and the extended draw row keeps its two flags.
|
// else, and the extended draw row keeps its two flags.
|
||||||
EXPECT_EQ(MGPipeCallFlagsFor(MGPWireOp::SetStorageBlockBinding), static_cast<Uint32>(kHasBlob));
|
EXPECT_EQ(MGPipeCallFlagsFor(MGPWireOp::SetStorageBlockBinding), static_cast<Uint32>(kHasBlob));
|
||||||
@@ -601,6 +610,14 @@ TEST(PipeCatalogue, LateArrivalsAreAppendedWithoutRenumbering) {
|
|||||||
// struct to pin - the 16 bytes are pinned above with the handle family.
|
// struct to pin - the 16 bytes are pinned above with the handle family.
|
||||||
EXPECT_EQ(sizeof(MGPApplierReset), 8u);
|
EXPECT_EQ(sizeof(MGPApplierReset), 8u);
|
||||||
EXPECT_EQ(sizeof(MGPHandleOnly), 16u);
|
EXPECT_EQ(sizeof(MGPHandleOnly), 16u);
|
||||||
|
// rv's two (§5.3/§7.6): the residual-value POD - 2 + 15 Uint32s, 2 Uint8s and 2 pad bytes,
|
||||||
|
// then the three Uint64s - and the AMENDED attribute carrier, which grew 24 -> 56 to carry
|
||||||
|
// all three views verbatim (the frontend's cross-view conversion is the authoritative
|
||||||
|
// answer; the applier no longer reconverts).
|
||||||
|
EXPECT_EQ(sizeof(MGPContextValues), 96u);
|
||||||
|
EXPECT_EQ(sizeof(MGPContextValues::TouchedBufferBindingPointCount), 60u);
|
||||||
|
EXPECT_EQ(sizeof(MGPAttribValue), 56u);
|
||||||
|
EXPECT_EQ(sizeof(MGPVertexAttribDefaults), 8u);
|
||||||
// The two draw-flag bits P5b's d1 arms are exclusive by contract and distinct by value.
|
// The two draw-flag bits P5b's d1 arms are exclusive by contract and distinct by value.
|
||||||
EXPECT_EQ(static_cast<Uint32>(kDrawIsIndirect), 1u << 5);
|
EXPECT_EQ(static_cast<Uint32>(kDrawIsIndirect), 1u << 5);
|
||||||
EXPECT_EQ(static_cast<Uint32>(kDrawHasUserIndices) & static_cast<Uint32>(kDrawIsIndirect), 0u);
|
EXPECT_EQ(static_cast<Uint32>(kDrawHasUserIndices) & static_cast<Uint32>(kDrawIsIndirect), 0u);
|
||||||
@@ -799,8 +816,9 @@ TEST(PipeCatalogue, SixValueStructsHaveFieldLists) {
|
|||||||
// MGPPatchParameter, MGPStreamOutputBind, MGPStorageBlockBinding, MGPCopyFromFramebuffer),
|
// MGPPatchParameter, MGPStreamOutputBind, MGPStorageBlockBinding, MGPCopyFromFramebuffer),
|
||||||
// each with its own field list, so the comparator sees every one of them: 77. P5c appended
|
// each with its own field list, so the comparator sees every one of them: 77. P5c appended
|
||||||
// applier_reset's MGPApplierReset (CONTRACT-P5C.md §5.1) - object_death reuses
|
// applier_reset's MGPApplierReset (CONTRACT-P5C.md §5.1) - object_death reuses
|
||||||
// MGPHandleOnly, which has had a list since P0 - so: 78.
|
// MGPHandleOnly, which has had a list since P0 - and rv added set_context_values'
|
||||||
EXPECT_EQ(kMGPipeVerifiedPayloadCount, 78u);
|
// MGPContextValues (§5.3): 79.
|
||||||
|
EXPECT_EQ(kMGPipeVerifiedPayloadCount, 79u);
|
||||||
static_assert(MGPipeHasFieldVerifier<RenderStateParameters>::value);
|
static_assert(MGPipeHasFieldVerifier<RenderStateParameters>::value);
|
||||||
static_assert(MGPipeHasFieldVerifier<PixelStoreParameters>::value);
|
static_assert(MGPipeHasFieldVerifier<PixelStoreParameters>::value);
|
||||||
static_assert(MGPipeHasFieldVerifier<PerBufferBlendState>::value);
|
static_assert(MGPipeHasFieldVerifier<PerBufferBlendState>::value);
|
||||||
|
|||||||
@@ -1304,6 +1304,9 @@ namespace {
|
|||||||
// set_vertex_attrib_defaults: a var-tail call, and the one consumer of the set-hash
|
// set_vertex_attrib_defaults: a var-tail call, and the one consumer of the set-hash
|
||||||
// suppressor. The tail is in ascending location order and Count matches Mask, which
|
// suppressor. The tail is in ascending location order and Count matches Mask, which
|
||||||
// is the contract the applier now enforces in every build rather than in a debug one.
|
// is the contract the applier now enforces in every build rather than in a debug one.
|
||||||
|
// P5c rv: each entry carries all THREE views verbatim (CONTRACT-P5C.md §5.3) and the
|
||||||
|
// applier writes each view from its own array - a float-written attribute keeps the
|
||||||
|
// frontend's converted int/uint words, which is what the pre-rv shape could not do.
|
||||||
{
|
{
|
||||||
MG_Test::ScopedPipeVerb draw(MGPipeVerb::DrawArrays);
|
MG_Test::ScopedPipeVerb draw(MGPipeVerb::DrawArrays);
|
||||||
MGPVertexAttribDefaults hdr{};
|
MGPVertexAttribDefaults hdr{};
|
||||||
@@ -1311,16 +1314,26 @@ namespace {
|
|||||||
hdr.Count = 2;
|
hdr.Count = 2;
|
||||||
MGPAttribValue tail[2]{};
|
MGPAttribValue tail[2]{};
|
||||||
tail[0].Location = 2;
|
tail[0].Location = 2;
|
||||||
|
tail[0].ValueClass = MG_State::GLState::kVertexAttribValueClassFloat;
|
||||||
const float first[4] = {1.5f, 2.5f, 3.5f, 4.5f};
|
const float first[4] = {1.5f, 2.5f, 3.5f, 4.5f};
|
||||||
std::memcpy(tail[0].Data, first, sizeof(first));
|
std::memcpy(tail[0].FloatView, first, sizeof(first));
|
||||||
|
const Int32 firstInt[4] = {1, 2, 3, 4}; // the frontend's conversion of 1.5f & co
|
||||||
|
std::memcpy(tail[0].IntView, firstInt, sizeof(firstInt));
|
||||||
tail[1].Location = 9;
|
tail[1].Location = 9;
|
||||||
|
tail[1].ValueClass = MG_State::GLState::kVertexAttribValueClassFloat;
|
||||||
const float second[4] = {-1.f, 0.f, 0.5f, 1.f};
|
const float second[4] = {-1.f, 0.f, 0.5f, 1.f};
|
||||||
std::memcpy(tail[1].Data, second, sizeof(second));
|
std::memcpy(tail[1].FloatView, second, sizeof(second));
|
||||||
|
const Int32 secondInt[4] = {-1, 0, 0, 1};
|
||||||
|
std::memcpy(tail[1].IntView, secondInt, sizeof(secondInt));
|
||||||
MGPipeApplySetVertexAttribDefaults(hdr, tail);
|
MGPipeApplySetVertexAttribDefaults(hdr, tail);
|
||||||
|
|
||||||
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).floatValue[0], 1.5f);
|
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).floatValue[0], 1.5f);
|
||||||
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).floatValue[3], 4.5f);
|
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).floatValue[3], 4.5f);
|
||||||
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(9).floatValue[2], 0.5f);
|
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(9).floatValue[2], 0.5f);
|
||||||
|
// ... and the CONVERTED views are the record's, not a memcpy of the float bits:
|
||||||
|
// 1.5f's bits are 0x3FC00000, and the frontend's int view of it is 1.
|
||||||
|
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(2).intValue[0], 1);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetCurrentVertexAttribute(9).intValue[0], -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete_render_state: the record stops being live and a bound handle stops being
|
// delete_render_state: the record stops being live and a bound handle stops being
|
||||||
|
|||||||
@@ -892,30 +892,35 @@ namespace {
|
|||||||
const MGPAttribValue value = PayloadFor(3);
|
const MGPAttribValue value = PayloadFor(3);
|
||||||
EXPECT_EQ(value.Location, 3u);
|
EXPECT_EQ(value.Location, 3u);
|
||||||
EXPECT_EQ(value.ValueClass, MG_State::GLState::kVertexAttribValueClassFloat);
|
EXPECT_EQ(value.ValueClass, MG_State::GLState::kVertexAttribValueClassFloat);
|
||||||
EXPECT_EQ(value.Data[0], Word(1.5f));
|
EXPECT_EQ(value.FloatView[0], Word(1.5f));
|
||||||
EXPECT_EQ(value.Data[1], Word(-2.5f));
|
EXPECT_EQ(value.FloatView[1], Word(-2.5f));
|
||||||
// The defect this exists to stop: 1.5f's int VIEW is 1, and a carrier that sent the
|
// P5c rv: the record carries ALL THREE VIEWS VERBATIM (CONTRACT-P5C.md §5.3), so the
|
||||||
// float bits while calling them class 0 for every attribute would be sending
|
// frontend's converted int view travels too - 1.5f's int VIEW is 1, and the carrier
|
||||||
// 0x3FC00000 where the frontend holds 1.
|
// that used to send the float bits into all three views would be sending 0x3FC00000
|
||||||
EXPECT_NE(value.Data[0], static_cast<Uint32>(Ctx().GetCurrentVertexAttribute(3).intValue[0]));
|
// where the frontend holds 1.
|
||||||
|
EXPECT_EQ(value.IntView[0],
|
||||||
|
static_cast<Uint32>(Ctx().GetCurrentVertexAttribute(3).intValue[0]));
|
||||||
|
EXPECT_NE(value.FloatView[0], value.IntView[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TrackerAttribPayload, AnIntWriteCarriesTheIntWordsAndNamesItsClass) {
|
TEST_F(TrackerAttribPayload, AnIntWriteCarriesTheIntWordsAndNamesItsClass) {
|
||||||
Ctx().SetCurrentVertexAttributeInt(5, Array<Int32, 4>{7, -9, 11, 13});
|
Ctx().SetCurrentVertexAttributeInt(5, Array<Int32, 4>{7, -9, 11, 13});
|
||||||
const MGPAttribValue value = PayloadFor(5);
|
const MGPAttribValue value = PayloadFor(5);
|
||||||
EXPECT_EQ(value.ValueClass, MG_State::GLState::kVertexAttribValueClassInt);
|
EXPECT_EQ(value.ValueClass, MG_State::GLState::kVertexAttribValueClassInt);
|
||||||
EXPECT_EQ(static_cast<Int32>(value.Data[0]), 7);
|
EXPECT_EQ(static_cast<Int32>(value.IntView[0]), 7);
|
||||||
EXPECT_EQ(static_cast<Int32>(value.Data[1]), -9);
|
EXPECT_EQ(static_cast<Int32>(value.IntView[1]), -9);
|
||||||
// and NOT the float view the frontend converted it into
|
// and the float view is the frontend's CONVERSION of it, not the int bits
|
||||||
EXPECT_NE(value.Data[0], Word(7.0f));
|
EXPECT_EQ(value.FloatView[0], Word(7.0f));
|
||||||
|
EXPECT_NE(value.IntView[0], Word(7.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TrackerAttribPayload, AUintWriteCarriesTheUintWordsAndNamesItsClass) {
|
TEST_F(TrackerAttribPayload, AUintWriteCarriesTheUintWordsAndNamesItsClass) {
|
||||||
Ctx().SetCurrentVertexAttributeUint(6, Array<Uint32, 4>{4000000000u, 2u, 3u, 4u});
|
Ctx().SetCurrentVertexAttributeUint(6, Array<Uint32, 4>{4000000000u, 2u, 3u, 4u});
|
||||||
const MGPAttribValue value = PayloadFor(6);
|
const MGPAttribValue value = PayloadFor(6);
|
||||||
EXPECT_EQ(value.ValueClass, MG_State::GLState::kVertexAttribValueClassUint);
|
EXPECT_EQ(value.ValueClass, MG_State::GLState::kVertexAttribValueClassUint);
|
||||||
EXPECT_EQ(value.Data[0], 4000000000u);
|
EXPECT_EQ(value.UintView[0], 4000000000u);
|
||||||
EXPECT_NE(value.Data[0], Word(4000000000.0f));
|
EXPECT_EQ(value.FloatView[0], Word(4000000000.0f));
|
||||||
|
EXPECT_NE(value.UintView[0], Word(4000000000.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The class is PER ATTRIBUTE and it is the last writer's, not the context's - a payload
|
// The class is PER ATTRIBUTE and it is the last writer's, not the context's - a payload
|
||||||
@@ -925,9 +930,9 @@ namespace {
|
|||||||
Ctx().SetCurrentVertexAttributeInt(2, Array<Int32, 4>{1, 2, 3, 4});
|
Ctx().SetCurrentVertexAttributeInt(2, Array<Int32, 4>{1, 2, 3, 4});
|
||||||
EXPECT_EQ(PayloadFor(1).ValueClass, MG_State::GLState::kVertexAttribValueClassFloat);
|
EXPECT_EQ(PayloadFor(1).ValueClass, MG_State::GLState::kVertexAttribValueClassFloat);
|
||||||
EXPECT_EQ(PayloadFor(2).ValueClass, MG_State::GLState::kVertexAttribValueClassInt);
|
EXPECT_EQ(PayloadFor(2).ValueClass, MG_State::GLState::kVertexAttribValueClassInt);
|
||||||
// Same numbers, different classes, so the same four words mean different things:
|
// Same numbers, different classes, so the WRITTEN views differ: 1.0f is 0x3F800000
|
||||||
// 1.0f is 0x3F800000 and the integer 1 is 0x00000001.
|
// and the integer 1 is 0x00000001.
|
||||||
EXPECT_NE(PayloadFor(1).Data[0], PayloadFor(2).Data[0]);
|
EXPECT_NE(PayloadFor(1).FloatView[0], PayloadFor(2).IntView[0]);
|
||||||
// An attribute nobody wrote answers Float, which is what the GL default (0,0,0,1) is.
|
// An attribute nobody wrote answers Float, which is what the GL default (0,0,0,1) is.
|
||||||
EXPECT_EQ(PayloadFor(7).ValueClass, MG_State::GLState::kVertexAttribValueClassFloat);
|
EXPECT_EQ(PayloadFor(7).ValueClass, MG_State::GLState::kVertexAttribValueClassFloat);
|
||||||
// and a later write of the other class moves the class of THAT attribute only
|
// and a later write of the other class moves the class of THAT attribute only
|
||||||
|
|||||||
@@ -38,6 +38,10 @@
|
|||||||
#include <Config.h>
|
#include <Config.h>
|
||||||
#include <MG_Remote/Server/PipeApplier.h>
|
#include <MG_Remote/Server/PipeApplier.h>
|
||||||
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
|
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3): set_context_values' round trip reads the applied record back
|
||||||
|
// out of gPipeInputs, which needs the stamp machinery (a RECORD-SUPPLIED read outside a
|
||||||
|
// server-stamped verb is the monolith answer's business, and this fixture has no client fill).
|
||||||
|
#include <MG_Backend/MGPipe/PipeInputs.h>
|
||||||
// P5c ct: object_death's round trip releases REAL Espryt twin-table entries, so the suite
|
// P5c ct: object_death's round trip releases REAL Espryt twin-table entries, so the suite
|
||||||
// drives the same registries the sink dispatches to (Managers.h). A suite that substituted a
|
// drives the same registries the sink dispatches to (Managers.h). A suite that substituted a
|
||||||
// mock here would pin the dispatch and nothing about the release (R-16).
|
// mock here would pin the dispatch and nothing about the release (R-16).
|
||||||
@@ -1326,6 +1330,52 @@ TEST_F(PipeWireCodecTest, ObjectDeathReachesTheSinkWithItsHandleAndKind) {
|
|||||||
EXPECT_EQ(wire.Decoder().AppliedSeq(), static_cast<Uint64>(kKindCount));
|
EXPECT_EQ(wire.Decoder().AppliedSeq(), static_cast<Uint64>(kKindCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================================================
|
||||||
|
// P5c rv (MG_Remote/CONTRACT-P5C.md §5.3): the residual-value record round-trips
|
||||||
|
// =====================================================================================
|
||||||
|
//
|
||||||
|
// Not a sink row: the decoder's arm runs the REAL applier (MGPipeApplySetContextValues), so
|
||||||
|
// the round trip is read back out of gPipeInputs - under a server stamp, because a
|
||||||
|
// RECORD-SUPPLIED read outside one is the pre-stamp behaviour this build still tests
|
||||||
|
// elsewhere, and the fields' own poison would otherwise (correctly) refuse the read.
|
||||||
|
|
||||||
|
TEST_F(PipeWireCodecTest, SetContextValuesRoundTripsIntoPipeInputs) {
|
||||||
|
Wire2 wire;
|
||||||
|
MGPContextValues values{};
|
||||||
|
values.ActiveTextureUnit = 9;
|
||||||
|
values.MaxTouchedTextureUnit = 41;
|
||||||
|
for (Uint32 t = 0; t < 15; ++t) values.TouchedBufferBindingPointCount[t] = 100 + t;
|
||||||
|
values.IsTransformFeedbackActive = 1;
|
||||||
|
values.IsTransformFeedbackPaused = 1;
|
||||||
|
values.TransformFeedbackGeneration = 0xA1A2A3A4A5A6A7A8ull;
|
||||||
|
values.BoundTransformFeedbackLifetimeId = 0xB1B2B3B4B5B6B7B8ull;
|
||||||
|
values.TransformFeedbackCapturedVertices = 0xC1C2C3C4C5C6C7C8ull;
|
||||||
|
ASSERT_NE(wire.Encoder().EncodeRecord(MGPWireOp::SetContextValues, &values, sizeof(values)),
|
||||||
|
kInvalidSeq);
|
||||||
|
bool applied = false;
|
||||||
|
ASSERT_TRUE(wire.PumpOne(&applied));
|
||||||
|
EXPECT_TRUE(applied);
|
||||||
|
EXPECT_EQ(wire.Decoder().AppliedSeq(), 1u);
|
||||||
|
|
||||||
|
// kReadback's class carries the two texture-unit counters, kDraw's the rest
|
||||||
|
// (FillPoints.def) - the stamp is what publishes a RECORD-SUPPLIED field for the read.
|
||||||
|
MGPipeServerStampVerbBoundary(MGPipeVerb::ReadPixels);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetActiveTextureUnit(), 9);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetMaxTouchedTextureUnit(), 41);
|
||||||
|
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||||
|
for (Uint32 t = 0; t < 15; ++t) {
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTouchedBufferBindingPointCount(static_cast<BufferTarget>(t)),
|
||||||
|
SizeT{100 + t})
|
||||||
|
<< "target " << t;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(gPipeInputs.IsTransformFeedbackActive());
|
||||||
|
EXPECT_TRUE(gPipeInputs.IsTransformFeedbackPaused());
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTransformFeedbackGeneration(), 0xA1A2A3A4A5A6A7A8ull);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetBoundTransformFeedbackLifetimeId(), 0xB1B2B3B4B5B6B7B8ull);
|
||||||
|
EXPECT_EQ(gPipeInputs.GetTransformFeedbackCapturedVertices(), 0xC1C2C3C4C5C6C7C8ull);
|
||||||
|
MGPipeServerClearVerbBoundary();
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// P5b t2 (MG_Remote/CONTRACT-P5B.md §2 t2). c0b's cases above round-trip each row once; these
|
// P5b t2 (MG_Remote/CONTRACT-P5B.md §2 t2). c0b's cases above round-trip each row once; these
|
||||||
// pin the fields t2's EMITTERS actually fill and the one ordering property the span family has.
|
// pin the fields t2's EMITTERS actually fill and the one ordering property the span family has.
|
||||||
|
|||||||
@@ -1064,7 +1064,7 @@ TEST(PipeRouting, AnErrorStatusIsNotFoldedIntoAcceptedOrRefused) {
|
|||||||
#endif // MGTEST_HAVE_FORK
|
#endif // MGTEST_HAVE_FORK
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// B3 / codex 9: the CLIENT arm's 37 rows are observed, not just the monolith install
|
// B3 / codex 9: the CLIENT arm's 38 rows are observed, not just the monolith install
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -1127,6 +1127,11 @@ TEST(PipeRouting, TheInstalledClientArmIsWireAndNotMonolithAndEveryRoutedRowMove
|
|||||||
C1F_MOVED(Context, SetVertexAttribDefaults);
|
C1F_MOVED(Context, SetVertexAttribDefaults);
|
||||||
C1F_MOVED(Context, SetPixelPackState);
|
C1F_MOVED(Context, SetPixelPackState);
|
||||||
C1F_MOVED(Context, SetPatchState);
|
C1F_MOVED(Context, SetPatchState);
|
||||||
|
// P5c rv (CONTRACT-P5C.md §5.3): the residual-value record is the 34th routed row - an
|
||||||
|
// ordinary set_* row with an MGPipeApply* entry point, so it rides BOTH tables like its
|
||||||
|
// siblings (its producer is transport-gated in PipeFill.cpp, which is a different gate's
|
||||||
|
// business).
|
||||||
|
C1F_MOVED(Context, SetContextValues);
|
||||||
C1F_MOVED(Context, SetResidualValueState);
|
C1F_MOVED(Context, SetResidualValueState);
|
||||||
C1F_MOVED(Context, SetTextureParams);
|
C1F_MOVED(Context, SetTextureParams);
|
||||||
C1F_MOVED(Context, ResourceSubData);
|
C1F_MOVED(Context, ResourceSubData);
|
||||||
@@ -1140,8 +1145,9 @@ TEST(PipeRouting, TheInstalledClientArmIsWireAndNotMonolithAndEveryRoutedRowMove
|
|||||||
C1F_ESCAPE(CreateShaderState);
|
C1F_ESCAPE(CreateShaderState);
|
||||||
#undef C1F_ESCAPE
|
#undef C1F_ESCAPE
|
||||||
const SizeT movedContext = CountDifferingCells(gMGPipeContext, MGPipeMonolithContext());
|
const SizeT movedContext = CountDifferingCells(gMGPipeContext, MGPipeMonolithContext());
|
||||||
EXPECT_EQ(movedScreen + movedContext, 33u)
|
EXPECT_EQ(movedScreen + movedContext, 34u)
|
||||||
<< "exactly the 33 generated routed rows must differ from the monolith adapters; "
|
<< "exactly the 34 generated routed rows must differ from the monolith adapters "
|
||||||
|
"(33 at P5, + set_context_values at P5c rv); "
|
||||||
<< movedScreen + movedContext
|
<< movedScreen + movedContext
|
||||||
<< " did, so a row was left on the monolith adapter (it would run the applier on the GL "
|
<< " did, so a row was left on the monolith adapter (it would run the applier on the GL "
|
||||||
"thread under split) or an unrouted row was overwritten";
|
"thread under split) or an unrouted row was overwritten";
|
||||||
|
|||||||
+20
-1
@@ -462,6 +462,25 @@ def check_field_lists_cover_struct_members(field_lists, payloads, header_texts=N
|
|||||||
ACCESSOR_READ_RE = re.compile(r"\b(?:MGB_CTX|pGLContext)\s*->\s*(\w+)")
|
ACCESSOR_READ_RE = re.compile(r"\b(?:MGB_CTX|pGLContext)\s*->\s*(\w+)")
|
||||||
|
|
||||||
|
|
||||||
|
# The scanner's NAMED exemptions: accessors a backend reads through MGB_CTX-> / pGLContext->
|
||||||
|
# that are NOT PipeInputs fields and never will be, each with the reason written down. A name
|
||||||
|
# here is a DEBT ENTRY, not a silence: it exists so the gate can tell "scoped, named, phased"
|
||||||
|
# from "forgot the row".
|
||||||
|
#
|
||||||
|
# P5c (the tx/ev/hd merge): the G6 frontend-keyed registry's framebuffer arm - two probes a
|
||||||
|
# backend makes inside MGPipeFrontendKeyedRegistryScope (CONTRACT-P5C.md section 3.1's second
|
||||||
|
# named exemption: the registry probes ride the scope, an unwrapped probe still aborts, and
|
||||||
|
# the scope retires with the twin tables at P3b/P4b). They are object-registry lookups, not
|
||||||
|
# PipeInputs state reads, so no Coverage.def row can ever describe them - a row there is a
|
||||||
|
# field in the fill table, and these have no storage to fill.
|
||||||
|
SCAN_EXEMPT_ACCESSORS = {
|
||||||
|
"GetFramebufferObject": "P5c G6 registry probe (the default framebuffer's object), inside "
|
||||||
|
"MGPipeFrontendKeyedRegistryScope; retires with the twin tables (P3b/P4b)",
|
||||||
|
"FindFramebufferObjectByLifetimeId": "P5c G6 registry probe, inside "
|
||||||
|
"MGPipeFrontendKeyedRegistryScope; retires with the twin tables (P3b/P4b)",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def scan_live_accessors(accessors, backend_dir=None, verbose=True):
|
def scan_live_accessors(accessors, backend_dir=None, verbose=True):
|
||||||
"""Every accessor a backend reads through MGB_CTX-> or pGLContext-> (comments and
|
"""Every accessor a backend reads through MGB_CTX-> or pGLContext-> (comments and
|
||||||
strings masked) must have a Coverage.def row - a read without a row is a PipeInputs
|
strings masked) must have a Coverage.def row - a read without a row is a PipeInputs
|
||||||
@@ -479,7 +498,7 @@ def scan_live_accessors(accessors, backend_dir=None, verbose=True):
|
|||||||
masked = mask_comments_and_strings(read(path))
|
masked = mask_comments_and_strings(read(path))
|
||||||
for match in ACCESSOR_READ_RE.finditer(masked):
|
for match in ACCESSOR_READ_RE.finditer(masked):
|
||||||
read_names.setdefault(match.group(1), set()).add(os.path.relpath(path, REPO_ROOT))
|
read_names.setdefault(match.group(1), set()).add(os.path.relpath(path, REPO_ROOT))
|
||||||
unknown = sorted(n for n in read_names if n not in known)
|
unknown = sorted(n for n in read_names if n not in known and n not in SCAN_EXEMPT_ACCESSORS)
|
||||||
if unknown:
|
if unknown:
|
||||||
sys.exit("Coverage.def: accessor(s) read by a backend with no row: %s"
|
sys.exit("Coverage.def: accessor(s) read by a backend with no row: %s"
|
||||||
% ", ".join("%s (%s)" % (n, ", ".join(sorted(read_names[n]))) for n in unknown))
|
% ", ".join("%s (%s)" % (n, ", ".join(sorted(read_names[n]))) for n in unknown))
|
||||||
|
|||||||
@@ -558,10 +558,13 @@ def self_test():
|
|||||||
# substring is not decoration: see expect_trip.
|
# substring is not decoration: see expect_trip.
|
||||||
|
|
||||||
# 1. THE HEADLINE CONTROL (exit gate E4): take one field out of the table. It is in no
|
# 1. THE HEADLINE CONTROL (exit gate E4): take one field out of the table. It is in no
|
||||||
# class, and that is a build failure rather than a silent default.
|
# class, and that is a build failure rather than a silent default. GetBoundVertexArray is
|
||||||
dropped = edit(r"X\(GetActiveTextureUnit," + GAP + r"BARRIER_PULLED," + GAP + r"\"[^\"]*\","
|
# the control's field since P5c rv (it keeps a hand-written BARRIER_PULLED row; the value
|
||||||
+ GAP + r"\"[^\"]*\"\)", "", "remove GetActiveTextureUnit's row")
|
# rows the first version used are RECORD_SUPPLIED-derived now, so they have no row to
|
||||||
controls = [("a field in NO class (GetActiveTextureUnit's row removed)",
|
# edit).
|
||||||
|
dropped = edit(r"X\(GetBoundVertexArray," + GAP + r"BARRIER_PULLED," + GAP + r"\"[^\"]*\","
|
||||||
|
+ GAP + r"\"[^\"]*\"\)", "", "remove GetBoundVertexArray's row")
|
||||||
|
controls = [("a field in NO class (GetBoundVertexArray's row removed)",
|
||||||
"field(s) in NO class",
|
"field(s) in NO class",
|
||||||
lambda: run(own_text=dropped))]
|
lambda: run(own_text=dropped))]
|
||||||
|
|
||||||
@@ -575,9 +578,9 @@ def self_test():
|
|||||||
lambda: run(own_text=doubled)))
|
lambda: run(own_text=doubled)))
|
||||||
|
|
||||||
# 3. A row naming something that is not a field at all.
|
# 3. A row naming something that is not a field at all.
|
||||||
typo = edit(r"X\(GetActiveTextureUnit,", "X(GetActiveTextureUnitt,", "misspell a field name")
|
typo = edit(r"X\(GetBoundVertexArray,", "X(GetBoundVertexArrayy,", "misspell a field name")
|
||||||
controls.append(("a row naming a non-field",
|
controls.append(("a row naming a non-field",
|
||||||
"GetActiveTextureUnitt, which is not a PipeInputs field",
|
"GetBoundVertexArrayy, which is not a PipeInputs field",
|
||||||
lambda: run(own_text=typo)))
|
lambda: run(own_text=typo)))
|
||||||
|
|
||||||
# 4. A BARRIER_PULLED row with no retiring phase: the debt is only sized if every row
|
# 4. A BARRIER_PULLED row with no retiring phase: the debt is only sized if every row
|
||||||
@@ -585,17 +588,17 @@ def self_test():
|
|||||||
# THE REPLACEMENT IS NOT A RAW STRING. It was, and the backslashes survived into the
|
# THE REPLACEMENT IS NOT A RAW STRING. It was, and the backslashes survived into the
|
||||||
# substitution, mangled the row past ROW_RE's reach and made this control a silent
|
# substitution, mangled the row past ROW_RE's reach and made this control a silent
|
||||||
# duplicate of #1 for a whole round.
|
# duplicate of #1 for a whole round.
|
||||||
unphased = edit(r"(X\(GetActiveTextureUnit," + GAP + r"BARRIER_PULLED,)" + GAP + r"\"[^\"]*\",",
|
unphased = edit(r"(X\(GetBoundVertexArray," + GAP + r"BARRIER_PULLED,)" + GAP + r"\"[^\"]*\",",
|
||||||
"\\1 \"-\",", "blank a BARRIER_PULLED row's retiring phase")
|
"\\1 \"-\",", "blank a BARRIER_PULLED row's retiring phase")
|
||||||
controls.append(("a BARRIER_PULLED row with no retiring phase",
|
controls.append(("a BARRIER_PULLED row with no retiring phase",
|
||||||
"GetActiveTextureUnit is BARRIER_PULLED and names no retiring phase",
|
"GetBoundVertexArray is BARRIER_PULLED and names no retiring phase",
|
||||||
lambda: run(own_text=unphased)))
|
lambda: run(own_text=unphased)))
|
||||||
|
|
||||||
# 5. A class that is not one of the four.
|
# 5. A class that is not one of the four.
|
||||||
bogus = edit(r"(X\(GetActiveTextureUnit,)" + GAP + r"BARRIER_PULLED,",
|
bogus = edit(r"(X\(GetBoundVertexArray,)" + GAP + r"BARRIER_PULLED,",
|
||||||
"\\1 SOMEHOW_FINE,", "introduce a fifth class")
|
"\\1 SOMEHOW_FINE,", "introduce a fifth class")
|
||||||
controls.append(("a fifth class",
|
controls.append(("a fifth class",
|
||||||
"GetActiveTextureUnit is in class SOMEHOW_FINE",
|
"GetBoundVertexArray is in class SOMEHOW_FINE",
|
||||||
lambda: run(own_text=bogus)))
|
lambda: run(own_text=bogus)))
|
||||||
|
|
||||||
# 6. A sticky forward that lost its own row - the seven most dangerous fields are exactly
|
# 6. A sticky forward that lost its own row - the seven most dangerous fields are exactly
|
||||||
@@ -699,9 +702,9 @@ def self_test():
|
|||||||
"the field set (%d of %d)" % (total, len(accessors)))
|
"the field set (%d of %d)" % (total, len(accessors)))
|
||||||
if len(sticky) != 7:
|
if len(sticky) != 7:
|
||||||
sys.exit("gen_pipe_field_ownership: self-test: Coverage.def no longer has seven sticky fields")
|
sys.exit("gen_pipe_field_ownership: self-test: Coverage.def no longer has seven sticky fields")
|
||||||
if len(refused) != 9:
|
if len(refused) != 7:
|
||||||
sys.exit("gen_pipe_field_ownership: self-test: EmittedCallSuppliesTheWholeField refuses %d "
|
sys.exit("gen_pipe_field_ownership: self-test: EmittedCallSuppliesTheWholeField refuses %d "
|
||||||
"fields, not the nine the contract's derivation is written against" % len(refused))
|
"fields, not the seven the contract's derivation is written against" % len(refused))
|
||||||
if trips == 0:
|
if trips == 0:
|
||||||
sys.exit("gen_pipe_field_ownership: self-test: no negative control tripped - the gates are "
|
sys.exit("gen_pipe_field_ownership: self-test: no negative control tripped - the gates are "
|
||||||
"not checking anything")
|
"not checking anything")
|
||||||
@@ -710,7 +713,7 @@ def self_test():
|
|||||||
% (len(controls) - trips, len(controls)))
|
% (len(controls) - trips, len(controls)))
|
||||||
print("gen_pipe_field_ownership: self-test: %d negative-control trip(s), each asserted against "
|
print("gen_pipe_field_ownership: self-test: %d negative-control trip(s), each asserted against "
|
||||||
"its OWN message; harness control OK; positive control OK "
|
"its OWN message; harness control OK; positive control OK "
|
||||||
"(%d fields partitioned, 7 sticky forwards, 9 refusals)" % (trips, total))
|
"(%d fields partitioned, 7 sticky forwards, 7 refusals)" % (trips, total))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user