mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 00:28:31 +09:00
[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:
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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)
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user