mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat] (Pipe): give the six value structs G4 field lists and assert the lists cover their members - the memcmp fallback is now a compile error, floats in vector types compare bitwise
- PipeFields.def gains MGP_FIELDS_RenderStateParameters (65 members), PixelStoreParameters (8), PerBufferBlendState (7), StencilFaceState (7), DynamicBackendParameters (85) and MGHostSpan (Ptr, Seg, Size, Offset), all appended to MGP_VERIFY_PAYLOAD_LIST: kMGPipeVerifiedPayloadCount 63 -> 69, and ResidualValueBlock / MGPPixelPackState / MGPCaps are now compared field by field all the way down.
- gen_verify: MEMCMP_FALLBACK_TYPES is empty and the generic MGPipeFieldEqual's last branch is static_assert(sizeof(T) == 0) - a struct without a field list is a compile error, not a padding false positive; Array<T, N> gets an element-wise overload, and a VecBase-derived vector (FloatVec4, IntVec4, BoolVec4...) is detected by a probe and compared bitwise over its data, because VecBase::operator== is IEEE == and a derived-to-base overload would lose resolution to the exact-match generic template.
- check_field_lists_cover_struct_members(): for every payload in MGP_VERIFY_PAYLOAD_LIST, parse `struct <Name> {` out of MGPipeTypes.h / MGPipeValueTypes.h / MGPipeHostSpan.h / BackendObject.h (comments and strings masked, statics, functions, nested types and Pad<n> members excluded) and refuse a member without an F(...) or an F(...) that is not a member; runs in both modes, so it is a pipe-gates gate.
- scan_live_accessors(): every MGB_CTX-> / pGLContext-> read under MG_Backend must have a Coverage.def row (rows nobody reads are printed: today only the dead GetBoundTransformFeedbackName).
- --self-test: six negative controls (struct member without F, F without member, payload without struct, verb missing from FillPoints.def, verb outside GLFunctionsTable, field row naming a non-accessor) that must each trip, plus a positive control; zero trips is itself an error.
This commit is contained in:
@@ -12,9 +12,11 @@
|
||||
// exactly what makes a memcmp of RenderStateParameters false-DIFFER
|
||||
// (DirectGLES.cpp documents that behaviour where it does the same comparison itself).
|
||||
//
|
||||
// Hand maintained alongside MGPipeTypes.h. Adding a field to a payload without adding it
|
||||
// here makes the comparator blind to it; that gap closes in P1, when the verify harness
|
||||
// goes live and the comparator's coverage is itself asserted.
|
||||
// Hand maintained alongside MGPipeTypes.h, MGPipeValueTypes.h, MGPipeHostSpan.h and
|
||||
// MG_Backend/BackendObject.h. Adding a member to one of these structs without adding it here
|
||||
// would make the comparator blind to it, so gen_pipe.py asserts - in both modes, hence in
|
||||
// pipe-gates - that every list below names exactly the direct data members of its struct
|
||||
// (P1 brief D8; a member named Pad<n> is padding and is not listed).
|
||||
//
|
||||
// clang-format off
|
||||
|
||||
@@ -218,6 +220,77 @@
|
||||
#define MGP_FIELDS_MGPSurfaceInfo(F) \
|
||||
F(Width) F(Height) F(InternalFormat) F(Samples) F(Layers) F(IsDefault)
|
||||
|
||||
// ---- 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
|
||||
// gone (a struct without a list is a compile error), and gen_pipe.py asserts every list names
|
||||
// every direct data member of its struct - Pad-named members are padding and excluded - so a
|
||||
// member added to RenderStateParameters without a row here fails pipe-gates.
|
||||
|
||||
#define MGP_FIELDS_RenderStateParameters(F) \
|
||||
F(Viewports) F(LineWidth) F(PointSize) F(PatchVertices) F(PatchDefaultOuterLevel) \
|
||||
F(PatchDefaultInnerLevel) F(PolygonOffsetFactor) F(PolygonOffsetUnits) F(PolygonOffsetClamp) \
|
||||
F(ClipOrigin) F(ClipDepthMode) F(BlendStates) F(LogicOp) F(DepthTestEnabled) F(DepthFunc) \
|
||||
F(DepthMask) F(ColorMasks) F(ClearColor) F(ClearDepth) F(ClearStencil) F(BlendColor) \
|
||||
F(DepthRanges) F(SampleCoverageValue) F(SampleCoverageInvert) F(SampleMaskValue) \
|
||||
F(MinSampleShadingValue) F(StencilStates) F(CullFaceEnabled) F(CullFaceModeSetting) \
|
||||
F(FrontFaceModeSetting) F(ProvokingVertexModeSetting) F(LineSmoothHint) F(PolygonSmoothHint) \
|
||||
F(TextureCompressionHint) F(FragmentShaderDerivativeHint) F(PointFadeThresholdSize) \
|
||||
F(PointSpriteCoordOrigin) F(ClampReadColor) F(PolygonModeFront) F(PolygonModeBack) \
|
||||
F(PrimitiveRestartIndex) F(ColorLogicOpEnabled) F(DebugOutputEnabled) \
|
||||
F(DebugOutputSynchronousEnabled) F(DitherEnabled) F(LineSmoothEnabled) F(MultisampleEnabled) \
|
||||
F(PolygonOffsetFillEnabled) F(PolygonOffsetLineEnabled) F(PolygonOffsetPointEnabled) \
|
||||
F(PolygonSmoothEnabled) F(PrimitiveRestartEnabled) F(PrimitiveRestartFixedIndexEnabled) \
|
||||
F(RasterizerDiscardEnabled) F(SampleAlphaToCoverageEnabled) F(SampleAlphaToOneEnabled) \
|
||||
F(SampleCoverageEnabled) F(SampleMaskEnabled) F(SampleShadingEnabled) F(StencilTestEnabled) \
|
||||
F(ProgramPointSizeEnabled) F(ScissorTestEnabledMask) F(ScissorBoxes) F(ScissorBoxWrittenMask) \
|
||||
F(ClipDistanceEnabledMask)
|
||||
|
||||
#define MGP_FIELDS_PixelStoreParameters(F) \
|
||||
F(SwapBytes) F(LSBFirst) F(RowLength) F(ImageHeight) F(SkipPixels) F(SkipRows) F(SkipImages) \
|
||||
F(Alignment)
|
||||
|
||||
#define MGP_FIELDS_PerBufferBlendState(F) \
|
||||
F(Enabled) F(SrcFactorRGB) F(DstFactorRGB) F(SrcFactorAlpha) F(DstFactorAlpha) F(ColorEquation) \
|
||||
F(AlphaEquation)
|
||||
|
||||
#define MGP_FIELDS_StencilFaceState(F) \
|
||||
F(Func) F(Ref) F(ValueMask) F(WriteMask) F(FailOp) F(PassDepthFailOp) F(PassDepthPassOp)
|
||||
|
||||
#define MGP_FIELDS_DynamicBackendParameters(F) \
|
||||
F(UniformBufferOffsetAlignment) F(ShaderStorageBufferOffsetAlignment) F(MaxTextureMaxAnisotropy) \
|
||||
F(AliasedLineWidthRangeMin) F(AliasedLineWidthRangeMax) F(SmoothLineWidthRangeMin) \
|
||||
F(SmoothLineWidthRangeMax) F(SmoothLineWidthGranularity) F(PointSizeRangeMin) \
|
||||
F(PointSizeRangeMax) F(PointSizeGranularity) F(Max3DTextureSize) F(MaxArrayTextureLayers) \
|
||||
F(MaxCubeMapTextureSize) F(MaxFramebufferWidth) F(MaxFramebufferHeight) F(MaxFramebufferLayers) \
|
||||
F(MaxRenderbufferSize) F(MaxTextureSize) F(MaxColorTextureSamples) F(MaxDepthTextureSamples) \
|
||||
F(MaxFramebufferSamples) F(MaxIntegerSamples) F(MaxSamples) F(MaxSampleMaskWords) \
|
||||
F(MaxPatchVertices) F(MaxTessGenLevel) F(MinProgramTextureGatherOffset) \
|
||||
F(MaxProgramTextureGatherOffset) F(MaxTextureImageUnits) F(MaxVertexTextureImageUnits) \
|
||||
F(MaxComputeTextureImageUnits) F(MaxCombinedTextureImageUnits) F(MaxVertexAttribs) \
|
||||
F(MaxComputeShaderStorageBlocks) F(MaxCombinedShaderStorageBlocks) \
|
||||
F(MaxVertexShaderStorageBlocks) F(MaxTessControlShaderStorageBlocks) \
|
||||
F(MaxTessEvaluationShaderStorageBlocks) F(MaxGeometryShaderStorageBlocks) \
|
||||
F(MaxFragmentShaderStorageBlocks) F(MaxComputeUniformBlocks) F(MaxComputeWorkGroupInvocations) \
|
||||
F(MaxComputeWorkGroupCount) F(MaxComputeWorkGroupSize) F(MaxShaderStorageBufferBindings) \
|
||||
F(MaxTextureBufferSize) F(TextureBufferOffsetAlignment) F(MaxUniformBufferBindings) \
|
||||
F(MaxUniformBlockSize) F(MaxImageUnits) F(MaxCombinedImageUniforms) F(MaxVertexImageUniforms) \
|
||||
F(MaxGeometryImageUniforms) F(MaxFragmentImageUniforms) F(MaxComputeImageUniforms) \
|
||||
F(MaxDrawBuffers) F(MaxColorAttachments) F(MaxClipDistances) F(MaxCullDistances) \
|
||||
F(MaxCombinedClipAndCullDistances) F(MaxViewports) F(LayerProvokingVertex) \
|
||||
F(ViewportIndexProvokingVertex) F(MaxViewportWidth) F(MaxViewportHeight) \
|
||||
F(ViewportBoundsRangeMin) F(ViewportBoundsRangeMax) F(ViewportSubpixelBits) \
|
||||
F(MinFragmentInterpolationOffset) F(MaxFragmentInterpolationOffset) \
|
||||
F(FragmentInterpolationOffsetBits) F(SupportsWideLines) \
|
||||
F(SupportsDistinctDepthStencilAttachments) F(PerLayerFramebufferAttachmentTargets) \
|
||||
F(SupportsShaderFloat64) F(SupportsFloat64VertexAttributes) F(SupportsTessellationPointSize) \
|
||||
F(SupportsGeometryPointSize) F(MaxShaderStorageBlockSize) F(SubgroupSize) \
|
||||
F(SubgroupSupportedStages) F(SubgroupSupportedFeatures) F(SubgroupQuadOperationsInAllStages) \
|
||||
F(GpuVendor)
|
||||
|
||||
#define MGP_FIELDS_MGHostSpan(F) \
|
||||
F(Ptr) F(Seg) F(Size) F(Offset)
|
||||
|
||||
// Every payload above, in the order the comparator is generated. Keep in sync with the
|
||||
// macros; gen_pipe.py reads THIS list to know what to emit.
|
||||
#define MGP_VERIFY_PAYLOAD_LIST(P) \
|
||||
@@ -233,6 +306,8 @@
|
||||
P(MGPCopyRegion) P(MGPBlit) P(MGPClear) P(MGPMipPlan) P(MGPReadbackInfo) P(MGPDrawInfo) \
|
||||
P(MGPDrawRange) P(MGPDrawIndirect) P(MGPGridInfo) P(MGPMemoryBarrier) P(MGPStreamOutputBegin) \
|
||||
P(MGPXfbAccounting) P(MGPStreamOutputControl) P(MGPFlush) P(MGPPresent) P(MGPSwapInterval) \
|
||||
P(MGPSurfaceInfo)
|
||||
P(MGPSurfaceInfo) \
|
||||
P(RenderStateParameters) P(PixelStoreParameters) P(PerBufferBlendState) P(StencilFaceState) \
|
||||
P(DynamicBackendParameters) P(MGHostSpan)
|
||||
|
||||
// clang-format on
|
||||
|
||||
@@ -27,6 +27,23 @@
|
||||
template <class T>
|
||||
struct MGPipeHasFieldVerifier : std::false_type {};
|
||||
|
||||
// A vector type (FloatVec4, IntVec4, BoolVec4...) is detected through its VecBase and
|
||||
// compared BITWISE over its data: VecBase::operator== is IEEE ==, under which a NaN patch
|
||||
// level would differ from itself. The probe rather than an overload because a
|
||||
// derived-to-base conversion loses overload resolution to the exact-match generic template.
|
||||
template <class Derived, class T, SizeT N>
|
||||
std::true_type MGPipeVecBaseProbe(const VecBase<Derived, T, N>*);
|
||||
std::false_type MGPipeVecBaseProbe(const void*);
|
||||
template <class T>
|
||||
inline constexpr Bool kMGPipeIsVecBase = decltype(MGPipeVecBaseProbe(static_cast<const T*>(nullptr)))::value;
|
||||
|
||||
template <class T>
|
||||
inline Bool MGPipeFieldEqual(const T& a, const T& b);
|
||||
template <class T, SizeT N>
|
||||
inline Bool MGPipeFieldEqual(const Array<T, N>& a, const Array<T, N>& b);
|
||||
template <class T, SizeT N>
|
||||
inline Bool MGPipeFieldEqual(const T (&a)[N], const T (&b)[N]);
|
||||
|
||||
inline Bool MGPipeVerify(const MGPBlobRef& a, const MGPBlobRef& b, const char** outField);
|
||||
inline Bool MGPipeVerify(const MGPRange& a, const MGPRange& b, const char** outField);
|
||||
inline Bool MGPipeVerify(const MGPBox& a, const MGPBox& b, const char** outField);
|
||||
@@ -90,6 +107,12 @@ 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 RenderStateParameters& a, const RenderStateParameters& b, const char** outField);
|
||||
inline Bool MGPipeVerify(const PixelStoreParameters& a, const PixelStoreParameters& b, const char** outField);
|
||||
inline Bool MGPipeVerify(const PerBufferBlendState& a, const PerBufferBlendState& b, const char** outField);
|
||||
inline Bool MGPipeVerify(const StencilFaceState& a, const StencilFaceState& b, const char** outField);
|
||||
inline Bool MGPipeVerify(const DynamicBackendParameters& a, const DynamicBackendParameters& b, const char** outField);
|
||||
inline Bool MGPipeVerify(const MGHostSpan& a, const MGHostSpan& b, const char** outField);
|
||||
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<MGPBlobRef> : std::true_type {};
|
||||
@@ -217,12 +240,26 @@ template <>
|
||||
struct MGPipeHasFieldVerifier<MGPSwapInterval> : std::true_type {};
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<MGPSurfaceInfo> : std::true_type {};
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<RenderStateParameters> : std::true_type {};
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<PixelStoreParameters> : std::true_type {};
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<PerBufferBlendState> : std::true_type {};
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<StencilFaceState> : std::true_type {};
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<DynamicBackendParameters> : std::true_type {};
|
||||
template <>
|
||||
struct MGPipeHasFieldVerifier<MGHostSpan> : std::true_type {};
|
||||
|
||||
template <class T>
|
||||
inline Bool MGPipeFieldEqual(const T& a, const T& b) {
|
||||
if constexpr (MGPipeHasFieldVerifier<T>::value) {
|
||||
const char* unusedField = nullptr;
|
||||
return MGPipeVerify(a, b, &unusedField);
|
||||
} else if constexpr (kMGPipeIsVecBase<T>) {
|
||||
return std::memcmp(a.data.data(), b.data.data(), sizeof(a.data)) == 0;
|
||||
} else if constexpr (std::is_floating_point_v<T>) {
|
||||
return std::memcmp(&a, &b, sizeof(T)) == 0;
|
||||
} else if constexpr (std::is_scalar_v<T> || std::is_enum_v<T>) {
|
||||
@@ -230,15 +267,23 @@ inline Bool MGPipeFieldEqual(const T& a, const T& b) {
|
||||
} else if constexpr (requires(const T& x, const T& y) { x == y; }) {
|
||||
return a == b;
|
||||
} else {
|
||||
// MEMCMP FALLBACK. Only reached by the payload members that are still value structs
|
||||
// without a field list (RenderStateParameters, PixelStoreParameters,
|
||||
// DynamicBackendParameters) and by MGHostSpan. P0.5 moved the first two into
|
||||
// MGPipeValueTypes.h; P1 gives them field lists of their own, at which point this
|
||||
// branch stops being reachable from any payload.
|
||||
return std::memcmp(&a, &b, sizeof(T)) == 0;
|
||||
// NO MEMCMP FALLBACK. Every value struct has a field list in PipeFields.def since P1
|
||||
// (and gen_pipe.py asserts each list covers its struct's members); a type reaching
|
||||
// this branch is one nobody gave a field list, and a memcmp would false-differ on
|
||||
// its padding. A compile error is the honest answer.
|
||||
static_assert(sizeof(T) == 0, "no field list in PipeFields.def for this type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, SizeT N>
|
||||
inline Bool MGPipeFieldEqual(const Array<T, N>& a, const Array<T, N>& b) {
|
||||
for (SizeT i = 0; i < N; ++i) {
|
||||
if (!MGPipeFieldEqual(a[i], b[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, SizeT N>
|
||||
inline Bool MGPipeFieldEqual(const T (&a)[N], const T (&b)[N]) {
|
||||
for (SizeT i = 0; i < N; ++i) {
|
||||
@@ -568,6 +613,36 @@ inline Bool MGPipeVerify(const MGPSurfaceInfo& a, const MGPSurfaceInfo& b, const
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Bool MGPipeVerify(const RenderStateParameters& a, const RenderStateParameters& b, const char** outField) {
|
||||
MGP_FIELDS_RenderStateParameters(MGP_VERIFY_FIELD)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Bool MGPipeVerify(const PixelStoreParameters& a, const PixelStoreParameters& b, const char** outField) {
|
||||
MGP_FIELDS_PixelStoreParameters(MGP_VERIFY_FIELD)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Bool MGPipeVerify(const PerBufferBlendState& a, const PerBufferBlendState& b, const char** outField) {
|
||||
MGP_FIELDS_PerBufferBlendState(MGP_VERIFY_FIELD)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Bool MGPipeVerify(const StencilFaceState& a, const StencilFaceState& b, const char** outField) {
|
||||
MGP_FIELDS_StencilFaceState(MGP_VERIFY_FIELD)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Bool MGPipeVerify(const DynamicBackendParameters& a, const DynamicBackendParameters& b, const char** outField) {
|
||||
MGP_FIELDS_DynamicBackendParameters(MGP_VERIFY_FIELD)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Bool MGPipeVerify(const MGHostSpan& a, const MGHostSpan& b, const char** outField) {
|
||||
MGP_FIELDS_MGHostSpan(MGP_VERIFY_FIELD)
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef MGP_VERIFY_FIELD
|
||||
|
||||
inline constexpr SizeT kMGPipeVerifiedPayloadCount = 63;
|
||||
inline constexpr SizeT kMGPipeVerifiedPayloadCount = 69;
|
||||
|
||||
Reference in New Issue
Block a user