[Feat] (MG_Pipe, P5b): append the five P5b verb rows at opcodes 72..76, arm draw_vbo with the kDrawIsIndirect second tail, give resource_copy_region its two GL names and the clear discriminants one spelling, and stamp every P5b verb boundary

This commit is contained in:
2026-09-16 11:15:45 -04:00
parent c9878d69f3
commit 4dd4027e80
9 changed files with 447 additions and 27 deletions
+26 -10
View File
@@ -236,17 +236,20 @@
// row below with a reason. "Verb-shaped" is the union of two mechanical tests, both derived:
// (a) PipeCalls.def gives the call kind kCtxVerb - the catalogue's own word for it;
// (b) the call's name is also an MGPipeVerb name in FillPoints.def.
// Twelve rows and three exemptions cover all fifteen. Only four of the twelve can arrive in P5
// (CONTRACT §7 class B minus Present); the other eight are Fatal{UnmigratedVerb} today and are
// mapped ANYWAY, because the failure mode of an absent row is silent: the applier would run the
// record under the PREVIOUS verb's serial, mask and name, and a field inside that mask would
// read FRESH while holding the previous verb's value.
// Eighteen rows and three exemptions cover all twenty-one (P5: twelve and three; P5b appended
// the five kCtxVerb rows 72..76 and settled ResourceCopyRegion). Only four of the rows could
// arrive in P5 (CONTRACT §7 class B minus Present); the rest are Fatal{UnmigratedVerb} on the
// client until a P5b migration package flips them and are mapped ANYWAY, because the failure
// mode of an absent row is silent: the applier would run the record under the PREVIOUS verb's
// serial, mask and name, and a field inside that mask would read FRESH while holding the
// previous verb's value.
//
// NOT MECHANICALLY DETECTABLE, and so not claimed: a call that is a verb boundary, is not
// kCtxVerb, and whose name differs from its verb's. `ResourceCopyRegion` is the one in the tree
// (its verbs are CopyImageSubData / CopyTexSubImage2D / CopyTexImage2D - three of them, which is
// why it cannot be a row without a rule for choosing). The phase that emits it adds its row and
// decides which verb it is.
// kCtxVerb, and whose name differs from its verb's. `ResourceCopyRegion` WAS the one in the
// tree (its verbs could have been CopyImageSubData / CopyTexSubImage2D / CopyTexImage2D). P5b
// decided: resource_copy_region is glCopyImageSubData only, and the two framebuffer-sourced
// copies have their own row (copy_framebuffer_to_texture), so the choice is a row here rather
// than a rule in a reader's head.
#define MGP_VERB_OP_LIST(X) \
/* CONTRACT §7 class B - the four that can actually arrive in P5. */ \
X(Clear, Clear) \
@@ -263,7 +266,20 @@
X(PauseStreamOutput, PauseTransformFeedback) \
X(ResumeStreamOutput, ResumeTransformFeedback) \
X(GenerateMipmap, GenerateMipmap) \
X(GetTextureImage, GetTextureImage)
X(GetTextureImage, GetTextureImage) \
/* P5b (MG_Remote/CONTRACT-P5B.md). The ONE renamed, non-kCtxVerb boundary the file above */ \
/* said "the phase that emits it adds its row and decides which verb it is": P5b rules */ \
/* resource_copy_region = glCopyImageSubData ONLY; the two framebuffer-sourced copies */ \
/* (CopyTexImage2D / CopyTexSubImage2D) are copy_framebuffer_to_texture below, stamped as */ \
/* CopyTexImage2D - both are kBlitOrCopy, one mask, and a row can name one verb. */ \
X(ResourceCopyRegion, CopyImageSubData) \
/* The five P5b-appended verbs, opcodes 72..76, each stamped as the GLFunctionsTable verb */ \
/* it reproduces. */ \
X(BindShaderImage, BindImageTexture) \
X(PatchParameter, PatchParameteri) \
X(BindStreamOutput, BindTransformFeedback) \
X(SetStorageBlockBinding, ShaderStorageBlockBinding) \
X(CopyFramebufferToTexture, CopyTexImage2D)
// X(Op, Why) - verb-shaped calls that are deliberately NOT stamp points.
//
+217 -5
View File
@@ -1247,15 +1247,39 @@ namespace MobileGL::MG_Pipe {
};
MGP_ASSERT_POD(MGPReadback, 24);
// resource_copy_region = glCopyImageSubData (P5b, CONTRACT-P5B.md i1). The record had no
// producer and no consumer before P5b, so its shape is settled here for the first time:
//
// Src / Dst the two endpoints' handles - kind Texture, or kind Renderbuffer when the
// matching *Target is GL_RENDERBUFFER. The handle is the identity.
// SrcTarget / the GL target enum the APPLICATION named, verbatim (GL_TEXTURE_2D,
// DstTarget GL_TEXTURE_CUBE_MAP, GL_RENDERBUFFER, ...); every one fits a Uint16.
// Espryt's own MakeGLESCopyImageEndpoint does the ES lowering
// (DirectGLES.cpp) and must keep seeing the enum the app passed.
// SrcBox {SrcX, SrcY, SrcZ, Width, Height, Depth} of the copied region.
// SrcGlName / THE P5b DEBT, stated rather than hidden. GLFunctionsTable::
// DstGlName CopyImageSubData takes two CopyImageEndpoints, each a frontend SharedPtr,
// and the server has none. Under inproc and the verb barrier the server
// rebuilds a TEXTURE endpoint from the GL name through the barrier-pulled
// sticky forward MGB_CTX->GetTextureObject(name) (counted in `rsp`,
// retired by P7 / P3b-P4b when the backend takes handles). A GL name is
// NEVER an identity (section 4.2.1); it is the lookup key of a pull the
// handle beside it will replace. No forward hands out a renderbuffer,
// so a RENDERBUFFER endpoint is refused by name in P5b
// (Fatal{UnmigratedVerb, "CopyImageSubData+RENDERBUFFER"}, ID-57's shape).
//
// 64 -> 72: the two names did not fit the four pad bytes, and the record had no wire history
// to preserve.
struct MGPCopyRegion {
MGPipeHandle Src, Dst;
MGPBox SrcBox;
Int32 DstX, DstY, DstZ;
Uint16 SrcTarget, DstTarget;
Uint16 SrcLevel, DstLevel;
Uint32 SrcGlName, DstGlName;
Uint32 Pad0;
};
MGP_ASSERT_POD(MGPCopyRegion, 64);
MGP_ASSERT_POD(MGPCopyRegion, 72);
struct MGPBlit {
MGPipeHandle ReadFbo, DrawFbo;
@@ -1270,16 +1294,61 @@ namespace MobileGL::MG_Pipe {
// glClearNamedFramebuffer* entry points (section 4.4.4).
struct MGPClear {
MGPipeHandle Fbo;
Uint32 Kind; // Whole | Color | Depth | Stencil | DepthStencil
Uint32 Kind; // kMGPipeClearKind*, below
Int32 DrawBufferIndex;
Uint32 BufferMask; // GL_COLOR_BUFFER_BIT etc. for the whole-framebuffer form
Uint32 ValueClass; // Float | Int | Uint
Uint32 ValueClass; // kMGPipeClearValueClass*, below
Uint32 ColorValue[4];
Float DepthValue;
Int32 StencilValue;
};
MGP_ASSERT_POD(MGPClear, 48);
// MGPClear's two discriminants, and THE ONLY SPELLING OF THEM (P5b, CONTRACT-P5B.md f1).
// Through P5 the list lived in this struct's comment and both the client emitter
// (MG_Remote/Client/EmitTables.h) and the server sink (MG_Remote/Server/PipeApplier.h)
// minted their own copy of the numbers, each flagged "this belongs in MGPipeTypes.h". A
// disagreement between the two copies is a clear of the wrong attachment with the wrong
// value type, which renders plausibly - table 0's "a decoder that open-codes it is the
// class-1 defect". Both files now alias these.
//
// Kind is the comment's order, left to right. ValueClass reuses the numbering
// MG_State/GLState/Core.h gives the identical three-way split on MGPAttribValue::ValueClass.
//
// WHICH GL ENTRY POINT PRODUCES WHICH KIND, so the emitter and the sink cannot disagree:
// glClear(mask) Whole, BufferMask = mask, DrawBufferIndex = -1
// glClearBuffer{f,i,ui}v(GL_COLOR, i, v) Color, DrawBufferIndex = i, ValueClass by suffix
// glClearBufferfv(GL_DEPTH, 0, &d) Depth, DepthValue = d
// glClearBufferiv(GL_STENCIL, 0, &s) Stencil, StencilValue = s
// glClearBufferfi(GL_DEPTH_STENCIL, 0, d, s) DepthStencil, DepthValue = d, StencilValue = s
// The four glClearNamedFramebuffer* forms are the same rows with Fbo = the named
// framebuffer's handle (preceded by its MGPipeFramebufferTarget::Named record, ID-19);
// the bound forms carry Fbo = kMGPipeNullHandle, "the bound draw framebuffer".
inline constexpr Uint32 kMGPipeClearKindWhole = 0;
inline constexpr Uint32 kMGPipeClearKindColor = 1;
inline constexpr Uint32 kMGPipeClearKindDepth = 2;
inline constexpr Uint32 kMGPipeClearKindStencil = 3;
inline constexpr Uint32 kMGPipeClearKindDepthStencil = 4;
inline constexpr Uint32 kMGPipeClearKindCount = 5;
inline constexpr Uint32 kMGPipeClearValueClassFloat = 0;
inline constexpr Uint32 kMGPipeClearValueClassInt = 1;
inline constexpr Uint32 kMGPipeClearValueClassUint = 2;
inline constexpr Uint32 kMGPipeClearValueClassCount = 3;
// generate_mipmap = glGenerateMipmap (P5b, CONTRACT-P5B.md f1). First producer and first
// consumer in P5b, so the fields are settled here:
// Res the texture bound to the active unit at `Target`, resolved on the client. The
// server's backend slot takes only the GL target and resolves the bound texture
// itself through the barrier-pulled unit state (kTextureOp's may-read mask), so
// Res is the P8 form's identity and is not what the P5b sink dispatches on.
// Target the GL texture target enum VERBATIM (GL_TEXTURE_2D 0x0DE1, GL_TEXTURE_3D
// 0x806F, GL_TEXTURE_CUBE_MAP 0x8513, GL_TEXTURE_2D_ARRAY 0x8C1A ...), which
// is what GLFunctionsTable::GenerateMipmap takes; every GL texture target fits
// a Uint16 and the sink passes it straight through. NOT MGPipeResourceTarget:
// there is no resource-target -> GL-enum inverse in the tree to spend on it.
// BaseLevel / the plan the client computed from GL_TEXTURE_BASE_LEVEL and the level count:
// LevelCount informational in P5b (the backend derives its own), load-bearing in P8's
// "generate_mipmap plan + CPU fallback texels" row.
struct MGPMipPlan {
MGPipeHandle Res;
Uint16 Target, BaseLevel, LevelCount, Pad0;
@@ -1307,6 +1376,14 @@ namespace MobileGL::MG_Pipe {
kDrawIndicesAreClient = 1u << 2,
kDrawHasIndexRange = 1u << 3,
kDrawHasXfbCount = 1u << 4,
// P5b (CONTRACT-P5B.md d1): the draw's ranges come from a GL_DRAW_INDIRECT_BUFFER and
// the record's SECOND TAIL is one MGPDrawIndirect rather than an MGHostSpan. The two
// flags are EXCLUSIVE - an indirect draw takes its indices from the bound element
// buffer by GL rule, so it can never carry user indices - and a record that sets both
// is Fatal{ProtocolCorruption} at the layout. NumDraws is 0 for an indirect draw: the
// server never reads the indirect buffer to learn a count and the client never sends
// ranges it does not have.
kDrawIsIndirect = 1u << 5,
};
// = pipe_draw_info. Today's twenty draw entry points collapse onto this one call, with
@@ -1341,8 +1418,22 @@ namespace MobileGL::MG_Pipe {
};
MGP_ASSERT_POD(MGPDrawRange, 12);
// Present when the draw is indirect. The client resolves the COUNT itself, so the
// server never reads an indirect command block to learn how many draws there are.
// Present when the draw is indirect: draw_vbo's second tail under kDrawIsIndirect (P5b,
// CONTRACT-P5B.md d1), 8-aligned behind the (empty) range tail exactly where the user-index
// span would sit. The client resolves the COUNT itself, so the server never reads an
// indirect command block to learn how many draws there are:
// glMultiDraw*Indirect DrawCount = drawcount, ParameterBuffer = null
// glMultiDraw*IndirectCount DrawCount = maxdrawcount, ParameterBuffer = the bound
// GL_PARAMETER_BUFFER, ParameterOffset = drawcount (the byte
// offset the GL call spells as GLintptr drawcount). The server's
// backend slot takes exactly that pair and reads the real count
// where it does today; nothing about the parameter buffer's
// CONTENT crosses. (ROADMAP P8's HostResolve.cpp is where a
// client-side count resolve would live if a backend ever needed
// the number rather than the buffer; no backend does.)
// Buffer / Offset / Stride the bound GL_DRAW_INDIRECT_BUFFER handle, the command byte
// offset the GL call passed as `indirect`, and the stride (0 =
// tightly packed, as GL spells it - the backend normalises).
struct MGPDrawIndirect {
MGPipeHandle Buffer;
MGPipeHandle ParameterBuffer;
@@ -1407,6 +1498,127 @@ namespace MobileGL::MG_Pipe {
};
MGP_ASSERT_POD(MGPSwapInterval, 8);
// ---------------------------------------------------------------------------------
// P5b: the five appended rows (MG_Remote/CONTRACT-P5B.md). APPENDED, never inserted:
// the wire opcode is a call's position in PipeCalls.def, so these sit after
// FenceWaitServer at opcodes 72..76 and no earlier opcode moved.
//
// Every one of them is a GLFunctionsTable VERB the class-C census measured as a first
// blocker and for which no existing row could carry the call. Four of the five exist
// because the backend slot does REAL WORK AT THE CALL rather than at the next validate,
// so a validate-time set record (set_shader_images, set_patch_state) cannot stand in for
// it: Espryt's BindImageTexture syncs the unit's binding to the driver on the spot,
// PatchParameteri pushes glPatchParameteri, BindTransformFeedback rebinds the driver
// object and invalidates the capture-binding shadows, and ShaderStorageBlockBinding
// pushes a rebinding onto an already-built driver program. The fifth,
// copy_framebuffer_to_texture, is a copy WITH the read framebuffer as its source, which
// resource_copy_region (resource -> resource) cannot express.
//
// NONE OF THEM HAS AN MGPipeApply* ENTRY POINT AND NONE GAINS ONE. They reach
// MG_Remote::Wire::WireVerbSink like the five P5 class-B verbs (the census's correction:
// a verb reaches the sink, not an applier), and under monolith they have no producer at
// all - the backend's own slot is called directly, byte for byte as today (G2/G14).
// ---------------------------------------------------------------------------------
// bind_shader_image = glBindImageTexture (P5b i1). The arguments VERBATIM plus the handle:
// Res the texture's handle (kind Texture); kMGPipeNullHandle for texture 0.
// Unit the image unit.
// GlName the GL texture name the app passed - what the ES backend slot is handed as
// `texture` and what it currently ignores ((void)texture); never an identity.
// Level / Layer / Layered / Access / Format the GL arguments verbatim. Access is the
// GL token (GL_READ_ONLY 0x88B8, GL_WRITE_ONLY 0x88B9, GL_READ_WRITE 0x88BA),
// NOT MGPImageView's three-value encoding: this record reproduces a call, and
// the encoding belongs to the validate-time set record, which still travels
// beside it. Format is the GL internal-format enum.
// The server's slot reads the unit's binding from the barrier-pulled GetImageTextureBinding
// (kTextureOp's mask) exactly as it does in monolith; the record is the verb boundary and
// the stamp, and the fields are what P7 / P3b-P4b will dispatch on instead.
struct MGPImageBind {
MGPipeHandle Res;
Uint32 Unit;
Uint32 GlName;
Int32 Level;
Int32 Layer;
Uint32 Access;
Uint32 Format;
Uint8 Layered;
Uint8 Pad0[7];
};
MGP_ASSERT_POD(MGPImageBind, 40);
// patch_parameter = glPatchParameteri (P5b t2). Pname is GL_PATCH_VERTICES - the only
// pname that reaches the backend slot; the frontend answers GL_PATCH_DEFAULT_*_LEVEL itself
// (GL_Drawing.cpp's PatchParameterfv) and bakes them into set_patch_state. It is carried
// verbatim so the sink reproduces the call and not a reading of it. set_patch_state (op 43)
// still travels at the next validate: it is the applier's working-block copy, this is the
// driver push Espryt does at the call, and the two are two pushes today too.
struct MGPPatchParameter {
Uint32 Pname;
Int32 Value;
};
MGP_ASSERT_POD(MGPPatchParameter, 8);
// bind_stream_output = glBindTransformFeedback (P5b t2). The XFB object namespace is the
// frontend's and has no wire lifetime (no create/delete row); Espryt keys its driver
// objects by the GL NAME (XfbImpl::g_xfbObjects[name]) and the D21 rekey by the lifetime
// id, so both cross. Name 0 is the default object. A GL name is never an identity; here it
// is the key the backend has always used, carried so the backend need not change.
struct MGPStreamOutputBind {
Uint32 GlName;
Uint32 Pad0;
Uint64 LifetimeId;
};
MGP_ASSERT_POD(MGPStreamOutputBind, 16);
// set_storage_block_binding = glShaderStorageBlockBinding (P5b i1). The block is named,
// not indexed: BackendObject.h says why - the application's index is the frontend
// interface-query enumeration's and no backend shares that index space, the NAME is the
// one coordinate all three agree on. The name is bytes of unbounded length, so it rides
// the ONE client -> server byte carrier, SEG_STAGE, as a kHasBlob blob: Name.Size is
// strlen + 1 (the NUL travels), never 0.
// ShaderCso the program's CSO handle - the identity, and what P7 dispatches on.
// GlName the GL program name the backend slot takes; under inproc the slot resolves
// it through the barrier-pulled sticky forward GetProgramObject(name)
// (`rsp`, retired by P9). The P5b debt, stated.
// Binding storageBlockBinding.
struct MGPStorageBlockBinding {
MGPipeHandle ShaderCso;
Uint32 GlName;
Uint32 Binding;
MGPBlobRef Name;
};
MGP_ASSERT_POD(MGPStorageBlockBinding, 40);
// copy_framebuffer_to_texture = glCopyTexImage2D / glCopyTexSubImage2D (P5b f1). The
// source is the READ framebuffer the server already has bound (set_framebuffer_state), so
// no source handle crosses; the destination is the texture bound to the active unit at
// Target, which the backend slot resolves through the barrier-pulled unit state exactly as
// generate_mipmap does. glCopyTexImage2D (SubImage = 0) also REDEFINES the level, and the
// frontend's own TexImage2D_State has already emitted that level's resource_respecify
// (GL_Texture.cpp's CopyTexImage2D validator) before the backend slot is reached, so the
// record carries the copy and nothing about storage.
// Dst the destination texture's handle (P8 form; the P5b sink does not
// dispatch on it).
// Target the GL texture target enum verbatim (a 2D target or a cube face).
// Level the destination level.
// InternalFormat glCopyTexImage2D's internalformat (GL enum); 0 for the sub-image form.
// X, Y, Width, Height the read-framebuffer rectangle.
// XOffset, YOffset the sub-image form's destination origin; 0 for the image form.
// SubImage 0 = glCopyTexImage2D, 1 = glCopyTexSubImage2D (unmeasured; shares
// the row because the two calls differ in exactly these two fields).
struct MGPCopyFromFramebuffer {
MGPipeHandle Dst;
Uint32 Target;
Int32 Level;
Uint32 InternalFormat;
Int32 X, Y;
Int32 Width, Height;
Int32 XOffset, YOffset;
Uint8 SubImage;
Uint8 Pad0[3];
};
MGP_ASSERT_POD(MGPCopyFromFramebuffer, 48);
// ---------------------------------------------------------------------------------
// Reverse channel payloads (section 7.1)
// ---------------------------------------------------------------------------------
+37 -5
View File
@@ -47,8 +47,11 @@
// kCtxCso 13 CSO create/bind/delete
// kCtxState 17 16 of the 17 set_* calls + the temporary set_residual_value_state
// kCtxObject 9 set_texture_params (the 17th set_*) + 8 object-scoped transfers
// kCtxVerb 13 3 context-reading transfer calls + the 10 commands
// total 71
// kCtxVerb 18 3 context-reading transfer calls + the 10 commands, plus the five
// P5b-appended verbs (bind_shader_image, patch_parameter,
// bind_stream_output, set_storage_block_binding,
// copy_framebuffer_to_texture - MG_Remote/CONTRACT-P5B.md)
// total 76
//
// 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:
@@ -78,9 +81,16 @@
// QueryTimestamp, QueryCounter and FenceWaitServer, APPENDED at the end of the list -
// not slotted into their groups - because the wire opcode is the position, so a record
// that arrives late goes last. 71 unique records.
// - P5b appended FIVE more after them (opcodes 72..76), for the same reason and by the same
// rule: five GLFunctionsTable verbs the class-C census measured as first blockers - the
// image bind, the patch parameter, the XFB object bind, the storage-block rebinding and
// the framebuffer-to-texture copy - for which no existing row could carry the call.
// 76 unique records. The catalogue footer's "ShaderStorageBlockBinding is folded into the
// reflection archive" is CORRECTED by the row: the archive carries the bindings the
// program LINKED with, and glShaderStorageBlockBinding moves one AFTER link.
// ---------------------------------------------------------------------------------------
#define MGP_CALL_LIST_DOCUMENTED_COUNT 71
#define MGP_CALL_LIST_DOCUMENTED_COUNT 76
// clang-format off
#define MGP_CALL_LIST(X) \
@@ -201,7 +211,26 @@
X(QueryCounter, MGPQueryDesc, kCtxQuery, kNone) \
/* glWaitSync - WaitSync, the GPU-side wait, distinct from FenceWait's client-side one. */ \
/* TimeoutNs is GL_TIMEOUT_IGNORED by contract. */ \
X(FenceWaitServer, MGPFenceWait, kScreen, kNone)
X(FenceWaitServer, MGPFenceWait, kScreen, kNone) \
/* ---- APPENDED BY P5b (MG_Remote/CONTRACT-P5B.md): five GLFunctionsTable verbs the ---- */ \
/* ---- class-C census measured as first blockers and that no existing row could carry. ---- */ \
/* ---- Opcodes 72..76. Every one reaches WireVerbSink, none has an MGPipeApply* entry ---- */ \
/* ---- point, and under monolith none has a producer - the backend slot is called ---- */ \
/* ---- directly, as today. The payload comments in MGPipeTypes.h say why each exists. ---- */ \
/* glBindImageTexture - Espryt syncs the unit's binding to the driver AT THE CALL */ \
/* (SyncImageTextureBinding), so the validate-time set_shader_images cannot stand in. */ \
X(BindShaderImage, MGPImageBind, kCtxVerb, kNone) \
/* glPatchParameteri(GL_PATCH_VERTICES) - Espryt pushes glPatchParameteri at the call. */ \
X(PatchParameter, MGPPatchParameter, kCtxVerb, kNone) \
/* glBindTransformFeedback - the driver object rebind and the capture-binding shadow */ \
/* invalidation happen at the call; the XFB namespace has no wire lifetime. */ \
X(BindStreamOutput, MGPStreamOutputBind, kCtxVerb, kNone) \
/* glShaderStorageBlockBinding - the block NAME is the coordinate all three sides share */ \
/* (BackendObject.h), and a name is bytes: kHasBlob, staged whole in SEG_STAGE, NUL included. */ \
X(SetStorageBlockBinding, MGPStorageBlockBinding, kCtxVerb, kHasBlob) \
/* glCopyTexImage2D / glCopyTexSubImage2D - a copy whose SOURCE is the read framebuffer, */ \
/* which resource_copy_region (resource -> resource) cannot express. */ \
X(CopyFramebufferToTexture, MGPCopyFromFramebuffer, kCtxVerb, kNone)
// clang-format on
// Explicitly NOT migrated (plan 4.4.6 / appendix A "explicit deletions"):
@@ -215,7 +244,10 @@
// - GetProgramiv. GL_COMPUTE_WORK_GROUP_SIZE is a FRONTEND link artifact
// (ProgramObject::GetComputeLocalSize, what GL_Program.cpp has always answered from), not
// a backend answer at all; nothing a backend knows about a program crosses this way.
// - ShaderStorageBlockBinding (folded into MGPProgramDesc's reflection archive),
// - ShaderStorageBlockBinding WAS listed here as "folded into MGPProgramDesc's reflection
// archive". P5b's set_storage_block_binding row (opcode 75) replaces that: the archive
// carries the bindings as LINKED, and the call moves one after link, which the backend
// applies to an already-built driver program (DirectGLES.cpp ShaderStorageBlockBinding).
// set_pixel_unpack_state (no such state crosses the line - plan 4.6 D5), a
// compressed-format concept, pipe_transfer, and the stage dimension of set_sampler_views
// (MobileGL's texture unit space is merged, not per stage - plan 4.4.3).
+25 -1
View File
@@ -185,8 +185,11 @@
#define MGP_FIELDS_MGPReadback(F) \
F(Res) F(Offset) F(Size)
// P5b (CONTRACT-P5B.md i1): the two GL names are the barrier-pulled lookup keys the sink
// rebuilds the CopyImageEndpoints from; listed like any member, so a verify build sees them.
#define MGP_FIELDS_MGPCopyRegion(F) \
F(Src) F(Dst) F(SrcBox) F(DstX) F(DstY) F(DstZ) F(SrcTarget) F(DstTarget) F(SrcLevel) F(DstLevel)
F(Src) F(Dst) F(SrcBox) F(DstX) F(DstY) F(DstZ) F(SrcTarget) F(DstTarget) F(SrcLevel) F(DstLevel) \
F(SrcGlName) F(DstGlName)
#define MGP_FIELDS_MGPBlit(F) \
F(ReadFbo) F(DrawFbo) F(SrcX0) F(SrcY0) F(SrcX1) F(SrcY1) F(DstX0) F(DstY0) F(DstX1) F(DstY1) \
@@ -240,6 +243,25 @@
#define MGP_FIELDS_MGPSurfaceInfo(F) \
F(Width) F(Height) F(InternalFormat) F(Samples) F(Layers) F(IsDefault)
// ---- P5b's five appended rows (MG_Remote/CONTRACT-P5B.md). Pad-named members excluded, as
// everywhere; MGPStorageBlockBinding's Name is an MGPBlobRef and recurses into that list.
#define MGP_FIELDS_MGPImageBind(F) \
F(Res) F(Unit) F(GlName) F(Level) F(Layer) F(Access) F(Format) F(Layered)
#define MGP_FIELDS_MGPPatchParameter(F) \
F(Pname) F(Value)
#define MGP_FIELDS_MGPStreamOutputBind(F) \
F(GlName) F(LifetimeId)
#define MGP_FIELDS_MGPStorageBlockBinding(F) \
F(ShaderCso) F(GlName) F(Binding) F(Name)
#define MGP_FIELDS_MGPCopyFromFramebuffer(F) \
F(Dst) F(Target) F(Level) F(InternalFormat) F(X) F(Y) F(Width) F(Height) F(XOffset) F(YOffset) \
F(SubImage)
// ---- 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
// comparator has to see INTO them: with these lists the memcmp fallback of MGPipeFieldEqual is
@@ -355,6 +377,8 @@
P(MGPDrawRange) P(MGPDrawIndirect) P(MGPGridInfo) P(MGPMemoryBarrier) P(MGPStreamOutputBegin) \
P(MGPXfbAccounting) P(MGPStreamOutputControl) P(MGPFlush) P(MGPPresent) P(MGPSwapInterval) \
P(MGPSurfaceInfo) \
P(MGPImageBind) P(MGPPatchParameter) P(MGPStreamOutputBind) P(MGPStorageBlockBinding) \
P(MGPCopyFromFramebuffer) \
P(RenderStateParameters) P(PixelStoreParameters) P(SamplerParameters) P(PerBufferBlendState) \
P(StencilFaceState) \
P(DynamicBackendParameters) P(MGHostSpan) \
@@ -281,12 +281,18 @@ constexpr MGPipeVerb MGPipeVerbForWireOp(MGPWireOp op) {
case MGPWireOp::ResumeStreamOutput: return MGPipeVerb::ResumeTransformFeedback;
case MGPWireOp::GenerateMipmap: return MGPipeVerb::GenerateMipmap;
case MGPWireOp::GetTextureImage: return MGPipeVerb::GetTextureImage;
case MGPWireOp::ResourceCopyRegion: return MGPipeVerb::CopyImageSubData;
case MGPWireOp::BindShaderImage: return MGPipeVerb::BindImageTexture;
case MGPWireOp::PatchParameter: return MGPipeVerb::PatchParameteri;
case MGPWireOp::BindStreamOutput: return MGPipeVerb::BindTransformFeedback;
case MGPWireOp::SetStorageBlockBinding: return MGPipeVerb::ShaderStorageBlockBinding;
case MGPWireOp::CopyFramebufferToTexture: return MGPipeVerb::CopyTexImage2D;
default:
return MGPipeVerb::kVerbCount;
}
}
inline constexpr SizeT kMGPipeVerbBoundaryOpCount = 12;
inline constexpr SizeT kMGPipeVerbBoundaryOpCount = 18;
inline constexpr SizeT kMGPipeVerbBoundaryExemptCount = 3;
// The class sizes, as constants a test can pin without recounting the table.
+8 -3
View File
@@ -28,7 +28,7 @@ struct MGPipeScreen {
void (*FenceWaitServer)(const MGPFenceWait* payload);
};
// context: 60 calls. A null entry means the backend does not implement this
// context: 65 calls. A null entry means the backend does not implement this
// call and the frontend keeps its own path (plan B section 4.1).
struct MGPipeContext {
void (*QueryCreate)(const MGPQueryDesc* payload);
@@ -91,11 +91,16 @@ struct MGPipeContext {
void (*SetSwapInterval)(const MGPSwapInterval* payload);
void (*QueryTimestamp)(const MGPTimestampRequest* payload, MGPReplySlot* reply);
void (*QueryCounter)(const MGPQueryDesc* payload);
void (*BindShaderImage)(const MGPImageBind* payload);
void (*PatchParameter)(const MGPPatchParameter* payload);
void (*BindStreamOutput)(const MGPStreamOutputBind* payload);
void (*SetStorageBlockBinding)(const MGPStorageBlockBinding* payload, const void* blobBytes, Uint64 blobByteCount);
void (*CopyFramebufferToTexture)(const MGPCopyFromFramebuffer* payload);
};
inline constexpr SizeT kMGPipeScreenCallCount = 11;
inline constexpr SizeT kMGPipeContextCallCount = 60;
inline constexpr SizeT kMGPipeCallCount = 71;
inline constexpr SizeT kMGPipeContextCallCount = 65;
inline constexpr SizeT kMGPipeCallCount = 76;
// A table that is not exactly its call count of function pointers has grown a
// member that no generator knows about.
+20
View File
@@ -300,3 +300,23 @@ inline void MGP_QueryCounter(const MGPQueryDesc* payload) {
inline void MGP_FenceWaitServer(const MGPFenceWait* payload) {
gMGPipeScreen.FenceWaitServer(payload);
}
inline void MGP_BindShaderImage(const MGPImageBind* payload) {
gMGPipeContext.BindShaderImage(payload);
}
inline void MGP_PatchParameter(const MGPPatchParameter* payload) {
gMGPipeContext.PatchParameter(payload);
}
inline void MGP_BindStreamOutput(const MGPStreamOutputBind* payload) {
gMGPipeContext.BindStreamOutput(payload);
}
inline void MGP_SetStorageBlockBinding(const MGPStorageBlockBinding* payload, const void* blobBytes, Uint64 blobByteCount) {
gMGPipeContext.SetStorageBlockBinding(payload, blobBytes, blobByteCount);
}
inline void MGP_CopyFramebufferToTexture(const MGPCopyFromFramebuffer* payload) {
gMGPipeContext.CopyFramebufferToTexture(payload);
}
+41 -1
View File
@@ -107,6 +107,11 @@ inline Bool MGPipeVerify(const MGPFlush& a, const MGPFlush& b, const char** outF
inline Bool MGPipeVerify(const MGPPresent& a, const MGPPresent& b, const char** outField);
inline Bool MGPipeVerify(const MGPSwapInterval& a, const MGPSwapInterval& b, const char** outField);
inline Bool MGPipeVerify(const MGPSurfaceInfo& a, const MGPSurfaceInfo& b, const char** outField);
inline Bool MGPipeVerify(const MGPImageBind& a, const MGPImageBind& b, const char** outField);
inline Bool MGPipeVerify(const MGPPatchParameter& a, const MGPPatchParameter& b, const char** outField);
inline Bool MGPipeVerify(const MGPStreamOutputBind& a, const MGPStreamOutputBind& 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 RenderStateParameters& a, const RenderStateParameters& 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);
@@ -244,6 +249,16 @@ struct MGPipeHasFieldVerifier<MGPSwapInterval> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<MGPSurfaceInfo> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<MGPImageBind> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<MGPPatchParameter> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<MGPStreamOutputBind> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<MGPStorageBlockBinding> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<MGPCopyFromFramebuffer> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<RenderStateParameters> : std::true_type {};
template <>
struct MGPipeHasFieldVerifier<PixelStoreParameters> : std::true_type {};
@@ -622,6 +637,31 @@ inline Bool MGPipeVerify(const MGPSurfaceInfo& a, const MGPSurfaceInfo& b, const
return true;
}
inline Bool MGPipeVerify(const MGPImageBind& a, const MGPImageBind& b, const char** outField) {
MGP_FIELDS_MGPImageBind(MGP_VERIFY_FIELD)
return true;
}
inline Bool MGPipeVerify(const MGPPatchParameter& a, const MGPPatchParameter& b, const char** outField) {
MGP_FIELDS_MGPPatchParameter(MGP_VERIFY_FIELD)
return true;
}
inline Bool MGPipeVerify(const MGPStreamOutputBind& a, const MGPStreamOutputBind& b, const char** outField) {
MGP_FIELDS_MGPStreamOutputBind(MGP_VERIFY_FIELD)
return true;
}
inline Bool MGPipeVerify(const MGPStorageBlockBinding& a, const MGPStorageBlockBinding& b, const char** outField) {
MGP_FIELDS_MGPStorageBlockBinding(MGP_VERIFY_FIELD)
return true;
}
inline Bool MGPipeVerify(const MGPCopyFromFramebuffer& a, const MGPCopyFromFramebuffer& b, const char** outField) {
MGP_FIELDS_MGPCopyFromFramebuffer(MGP_VERIFY_FIELD)
return true;
}
inline Bool MGPipeVerify(const RenderStateParameters& a, const RenderStateParameters& b, const char** outField) {
MGP_FIELDS_RenderStateParameters(MGP_VERIFY_FIELD)
return true;
@@ -669,4 +709,4 @@ inline Bool MGPipeVerify(const MGPVertexBindingPointWire& a, const MGPVertexBind
#undef MGP_VERIFY_FIELD
inline constexpr SizeT kMGPipeVerifiedPayloadCount = 72;
inline constexpr SizeT kMGPipeVerifiedPayloadCount = 77;
+66 -1
View File
@@ -141,7 +141,12 @@ enum class MGPWireOp : Uint16 {
QueryTimestamp = 69,
QueryCounter = 70,
FenceWaitServer = 71,
kOpCount = 72,
BindShaderImage = 72,
PatchParameter = 73,
BindStreamOutput = 74,
SetStorageBlockBinding = 75,
CopyFramebufferToTexture = 76,
kOpCount = 77,
};
// THE FLAGS, EXPORTED ONCE, INDEXED BY OPCODE (P5 R-13.4). MGPWireRecHeader::Flags is
@@ -234,6 +239,11 @@ inline constexpr Uint32 kMGPipeCallFlags[static_cast<SizeT>(MGPWireOp::kOpCount)
/* 69 QueryTimestamp */ static_cast<Uint32>(kReplySlot),
/* 70 QueryCounter */ static_cast<Uint32>(kNone),
/* 71 FenceWaitServer */ static_cast<Uint32>(kNone),
/* 72 BindShaderImage */ static_cast<Uint32>(kNone),
/* 73 PatchParameter */ static_cast<Uint32>(kNone),
/* 74 BindStreamOutput */ static_cast<Uint32>(kNone),
/* 75 SetStorageBlockBinding */ static_cast<Uint32>(kHasBlob),
/* 76 CopyFramebufferToTexture*/ static_cast<Uint32>(kNone),
};
static_assert(sizeof(kMGPipeCallFlags) / sizeof(kMGPipeCallFlags[0]) ==
static_cast<SizeT>(MGPWireOp::kOpCount),
@@ -855,6 +865,46 @@ static_assert(sizeof(MGPWireRec_FenceWaitServer) ==
((sizeof(MGPWireRecHeader) + sizeof(MGPFenceWait) + 7u) & ~SizeT(7u)),
"MGPWireRec_FenceWaitServer gained padding; the wire format moved");
struct alignas(8) MGPWireRec_BindShaderImage {
MGPWireRecHeader Header;
MGPImageBind Payload;
};
static_assert(sizeof(MGPWireRec_BindShaderImage) ==
((sizeof(MGPWireRecHeader) + sizeof(MGPImageBind) + 7u) & ~SizeT(7u)),
"MGPWireRec_BindShaderImage gained padding; the wire format moved");
struct alignas(8) MGPWireRec_PatchParameter {
MGPWireRecHeader Header;
MGPPatchParameter Payload;
};
static_assert(sizeof(MGPWireRec_PatchParameter) ==
((sizeof(MGPWireRecHeader) + sizeof(MGPPatchParameter) + 7u) & ~SizeT(7u)),
"MGPWireRec_PatchParameter gained padding; the wire format moved");
struct alignas(8) MGPWireRec_BindStreamOutput {
MGPWireRecHeader Header;
MGPStreamOutputBind Payload;
};
static_assert(sizeof(MGPWireRec_BindStreamOutput) ==
((sizeof(MGPWireRecHeader) + sizeof(MGPStreamOutputBind) + 7u) & ~SizeT(7u)),
"MGPWireRec_BindStreamOutput gained padding; the wire format moved");
struct alignas(8) MGPWireRec_SetStorageBlockBinding {
MGPWireRecHeader Header;
MGPStorageBlockBinding Payload;
};
static_assert(sizeof(MGPWireRec_SetStorageBlockBinding) ==
((sizeof(MGPWireRecHeader) + sizeof(MGPStorageBlockBinding) + 7u) & ~SizeT(7u)),
"MGPWireRec_SetStorageBlockBinding gained padding; the wire format moved");
struct alignas(8) MGPWireRec_CopyFramebufferToTexture {
MGPWireRecHeader Header;
MGPCopyFromFramebuffer Payload;
};
static_assert(sizeof(MGPWireRec_CopyFramebufferToTexture) ==
((sizeof(MGPWireRecHeader) + sizeof(MGPCopyFromFramebuffer) + 7u) & ~SizeT(7u)),
"MGPWireRec_CopyFramebufferToTexture gained padding; the wire format moved");
[[noreturn]] inline void MGPipeWireProtocolFatal(const char* call, Uint64 size, Uint64 remaining) {
MGLOG_F("MGPipe: protocol corruption applying %s: size=%llu remaining=%llu", call,
static_cast<unsigned long long>(size), static_cast<unsigned long long>(remaining));
@@ -1117,6 +1167,21 @@ inline Bool MGPipeApplyWireRecord(MGPWireOp op, const void* record, Uint64 size,
case MGPWireOp::FenceWaitServer:
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_FenceWaitServer, "FenceWaitServer");
break;
case MGPWireOp::BindShaderImage:
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_BindShaderImage, "BindShaderImage");
break;
case MGPWireOp::PatchParameter:
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_PatchParameter, "PatchParameter");
break;
case MGPWireOp::BindStreamOutput:
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_BindStreamOutput, "BindStreamOutput");
break;
case MGPWireOp::SetStorageBlockBinding:
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_SetStorageBlockBinding, "SetStorageBlockBinding");
break;
case MGPWireOp::CopyFramebufferToTexture:
MGP_WIRE_CHECK_BOUNDS(MGPWireRec_CopyFramebufferToTexture, "CopyFramebufferToTexture");
break;
case MGPWireOp::kInvalid:
case MGPWireOp::kOpCount:
default: