mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Refactor] (Pipe, State): extract MGPipeValueTypes.h - move the render-state, sampler and vertex value types and their enums out of MG_State/GLState so MG_Pipe no longer reaches RenderState.h; pure move, member order and namespaces unchanged
- ROADMAP P0.5 / ARCHITECTURE.md value-header manifest: MGPipeTypes.h embedded RenderStateParameters and PixelStoreParameters through RenderState.h, which drags FramebufferObject.h and the whole texture/renderbuffer/sampler chain into MG_Pipe; purity gate A (no MG_State/MG_Impl/MG_Backend/MG_Remote in the closure) could not be armed for anything in MG_Pipe while that include existed. - MGPipeValueTypes.h is a verbatim cut, comments included: the eleven RenderState.h enums (all of them - a split would be the maintenance trap), PixelStoreParameters, PerBufferBlendState, StencilFaceState, RenderStateParameters (member order untouched: DirectGLES' offsetof spans and PipeSpanTable.inc name the members), the six SamplerObject.h enums and SamplerParameters (BorderColorForm stays Uint8, it sets the tail padding), and VertexAttribute / VertexBufferBindingPoint / VertexAttributeVersion, which keep namespace MobileGL::MG_State::GLState with a forward-declared BufferObject so no mangled name changes. - MAX_DRAW_BUFFERS becomes inline constexpr kMGMaxDrawBuffers in namespace MobileGL and FramebufferObject::MAX_DRAW_BUFFERS is defined from it, so the eighty existing spellings keep working and the two cannot drift. No other constant is added. - The four MG_State headers become forwarders (include the value header, keep their class definitions); RenderState.cpp gains a direct FramebufferObject.h include because it spells FramebufferObject::MAX_DRAW_BUFFERS and only ever got that header transitively. No other TU lost a transitive include: the full build (Release, clang, tests + integration tests) passed without touching anything under MG_Backend, MG_Impl or MG_Util. - DynamicBackendParameters does NOT move (SizeT members and TextureTarget-taking member functions make that a type change, not a move); MGPipeTypes.h keeps its BackendObject.h include and the debt comment now says so, which is why gate A asserts MGPipeValueTypes.h rather than MGPipeTypes.h. - New trip wires in the header: trivially-copyable + exact sizeof for PixelStoreParameters/PerBufferBlendState/StencilFaceState (28), SamplerParameters (100), VertexAttributeVersion (6), RenderStateParameters (1168, standard layout, BlendStates before LogicOp, BlendStates sized by kMGMaxDrawBuffers). Their runtime twins ValueTypeLayoutsArePinned and the carrier check ResidualBlockIsExactlyItsTwoValueStructsPlusPatchTail (Pack at 1168, CapabilityBits at 1200) are added to PipeCatalogueTest without a new include. - gen_pipe.py's "field lists of their own in P0.5" comment now says P1 (the comparator needs std::array<struct> support first); PipeVerify.inc regenerated. - Verified: ctest -L unit 1460/1460 and -L integration-gpu green; ctest -N names a superset of feat/disaggregated@6672778b (two added, none lost); one definition per moved type; the -H closure of the new header contains no MG_State/MG_Backend/ MG_Impl/MG_Remote header and the header compiles alone; nm --defined-only -S against the base libMobileGL.so: 0 added / 0 removed / 0 resized, .text byte-identical, the only differing bytes are the build-id and two stamp strings.
This commit is contained in:
@@ -22,19 +22,19 @@
|
|||||||
// these structs (generated/PipeWire.inc) are memcpy'd; a field silently changing width is a
|
// these structs (generated/PipeWire.inc) are memcpy'd; a field silently changing width is a
|
||||||
// protocol break that no test would otherwise see.
|
// protocol break that no test would otherwise see.
|
||||||
//
|
//
|
||||||
// P0.5 DEBT, recorded here so it is impossible to miss: two payloads reach into headers
|
// P0.5 DEBT, half repaid. The MG_State half is gone: ResidualValueBlock's
|
||||||
// this directory is eventually forbidden to see - MGPCaps embeds MG_Backend's
|
// RenderStateParameters and PixelStoreParameters now come from MGPipeValueTypes.h, so
|
||||||
// DynamicBackendParameters, and ResidualValueBlock embeds MG_State's RenderStateParameters
|
// this header no longer reaches into MG_State. What remains is MGPCaps embedding
|
||||||
// and PixelStoreParameters. Both are deliberate: the caps block IS that struct (section
|
// MG_Backend's DynamicBackendParameters - deliberate, the caps block IS that struct
|
||||||
// 4.4.1) and the residual block is the migration carrier for Track V (section 6.3). P0.5
|
// (section 4.4.1) - and that one include is what still keeps purity gate A (section
|
||||||
// extracts MGPipeValueTypes.h and both includes below go away; until then purity gate A
|
// 10.3) off this header; the gate asserts MGPipeValueTypes.h instead. The caps block
|
||||||
// (section 10.3) cannot be armed for this header.
|
// needs fixed-width members before it can move (a type change, not a move): P1/P7.
|
||||||
#include <MG_Backend/BackendObject.h>
|
#include <MG_Backend/BackendObject.h>
|
||||||
#include <MG_State/GLState/RenderState/RenderState.h>
|
#include "MGPipeValueTypes.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_Pipe {
|
namespace MobileGL::MG_Pipe {
|
||||||
using MG_Backend::DynamicBackendParameters;
|
using MG_Backend::DynamicBackendParameters;
|
||||||
// Both live directly in namespace MobileGL today; P0.5 moves them into
|
// Both live directly in namespace MobileGL and, since P0.5, are declared in
|
||||||
// MG_Pipe/MGPipeValueTypes.h.
|
// MG_Pipe/MGPipeValueTypes.h.
|
||||||
using MobileGL::PixelStoreParameters;
|
using MobileGL::PixelStoreParameters;
|
||||||
using MobileGL::RenderStateParameters;
|
using MobileGL::RenderStateParameters;
|
||||||
|
|||||||
@@ -0,0 +1,549 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Pipe/MGPipeValueTypes.h
|
||||||
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
|
// Licensed under the GNU Lesser General Public License v3.0:
|
||||||
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
// End of Source File Header
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef MOBILEGL_MG_PIPE_VALUE_TYPES_H // belt and braces: this file is reachable both as
|
||||||
|
#define MOBILEGL_MG_PIPE_VALUE_TYPES_H // <MG_Pipe/...> and <...> (CMakeLists.txt:531,535)
|
||||||
|
#include <Includes.h>
|
||||||
|
#include <MG_Util/Math/VectorTypes.h> // includes only <Includes.h> + <cstring>
|
||||||
|
#include <cstddef> // offsetof
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
// The value types MG_Pipe payloads embed (plan B section 6.3; ARCHITECTURE.md section on
|
||||||
|
// the value header): the render-state, pixel-store, sampler and vertex-attribute value
|
||||||
|
// structs and the enums they are made of. They lived in MG_State::GLState until P0.5;
|
||||||
|
// the MG_State headers that used to define them now include this file, so every existing
|
||||||
|
// spelling (namespace and name) compiles unchanged.
|
||||||
|
//
|
||||||
|
// PURITY: nothing from MG_State, MG_Impl, MG_Backend or MG_Remote -
|
||||||
|
// scripts/check_include_closure.py probe "value-header" (ROADMAP P0.5; ARCHITECTURE.md
|
||||||
|
// section 10.3 gate A). Adding one turns CI red. MG_Pipe never includes MG_State back.
|
||||||
|
|
||||||
|
namespace MobileGL {
|
||||||
|
// GL_MAX_DRAW_BUFFERS as MobileGL advertises it. FramebufferObject::MAX_DRAW_BUFFERS is
|
||||||
|
// defined from this constant, so the two cannot drift.
|
||||||
|
inline constexpr Uint kMGMaxDrawBuffers = 8;
|
||||||
|
|
||||||
|
enum class BlendFactor {
|
||||||
|
Zero,
|
||||||
|
One,
|
||||||
|
SrcColor,
|
||||||
|
OneMinusSrcColor,
|
||||||
|
DstColor,
|
||||||
|
OneMinusDstColor,
|
||||||
|
SrcAlpha,
|
||||||
|
OneMinusSrcAlpha,
|
||||||
|
DstAlpha,
|
||||||
|
OneMinusDstAlpha,
|
||||||
|
ConstantColor,
|
||||||
|
OneMinusConstantColor,
|
||||||
|
ConstantAlpha,
|
||||||
|
OneMinusConstantAlpha,
|
||||||
|
// Dual-source blend factors (GL_SRC1_*, glBindFragDataLocationIndexed); require the
|
||||||
|
// dualSrcBlend device feature.
|
||||||
|
Src1Color,
|
||||||
|
OneMinusSrc1Color,
|
||||||
|
Src1Alpha,
|
||||||
|
OneMinusSrc1Alpha,
|
||||||
|
BlendFactorCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BlendEquation {
|
||||||
|
Add,
|
||||||
|
Subtract,
|
||||||
|
ReverseSubtract,
|
||||||
|
Min,
|
||||||
|
Max,
|
||||||
|
BlendEquationCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class LogicOperation {
|
||||||
|
Clear,
|
||||||
|
And,
|
||||||
|
AndReverse,
|
||||||
|
Copy,
|
||||||
|
AndInverted,
|
||||||
|
Noop,
|
||||||
|
Xor,
|
||||||
|
Or,
|
||||||
|
Nor,
|
||||||
|
Equiv,
|
||||||
|
Invert,
|
||||||
|
OrReverse,
|
||||||
|
CopyInverted,
|
||||||
|
OrInverted,
|
||||||
|
Nand,
|
||||||
|
Set,
|
||||||
|
LogicOperationCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DepthTestFunc {
|
||||||
|
Never,
|
||||||
|
Less,
|
||||||
|
Equal,
|
||||||
|
LessEqual,
|
||||||
|
Greater,
|
||||||
|
NotEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
Always,
|
||||||
|
DepthTestFuncCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class StencilOperation {
|
||||||
|
Keep,
|
||||||
|
Zero,
|
||||||
|
Replace,
|
||||||
|
IncrementClamp,
|
||||||
|
DecrementClamp,
|
||||||
|
Invert,
|
||||||
|
IncrementWrap,
|
||||||
|
DecrementWrap,
|
||||||
|
StencilOperationCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class StencilFace {
|
||||||
|
Front,
|
||||||
|
Back,
|
||||||
|
StencilFaceCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PixelStoreParam {
|
||||||
|
// Pack Parameters
|
||||||
|
PackAlignment,
|
||||||
|
PackRowLength,
|
||||||
|
PackImageHeight,
|
||||||
|
PackSkipRows,
|
||||||
|
PackSkipPixels,
|
||||||
|
PackSkipImages,
|
||||||
|
PackSwapBytes,
|
||||||
|
PackLSBFirst,
|
||||||
|
|
||||||
|
// Unpack Parameters
|
||||||
|
UnpackAlignment,
|
||||||
|
UnpackRowLength,
|
||||||
|
UnpackImageHeight,
|
||||||
|
UnpackSkipRows,
|
||||||
|
UnpackSkipPixels,
|
||||||
|
UnpackSkipImages,
|
||||||
|
UnpackSwapBytes,
|
||||||
|
UnpackLSBFirst,
|
||||||
|
|
||||||
|
PixelStoreParamCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CullFaceMode {
|
||||||
|
Front,
|
||||||
|
Back,
|
||||||
|
FrontAndBack,
|
||||||
|
CullFaceModeCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class FrontFaceMode {
|
||||||
|
CounterClockwise,
|
||||||
|
Clockwise,
|
||||||
|
FrontFaceModeCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ProvokingVertexMode {
|
||||||
|
FirstVertex,
|
||||||
|
LastVertex,
|
||||||
|
ProvokingVertexModeCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CapabilityInput {
|
||||||
|
Blend,
|
||||||
|
ClipDistance0,
|
||||||
|
ClipDistance1,
|
||||||
|
ClipDistance2,
|
||||||
|
ClipDistance3,
|
||||||
|
ClipDistance4,
|
||||||
|
ClipDistance5,
|
||||||
|
ClipDistance6,
|
||||||
|
ClipDistance7,
|
||||||
|
ColorLogicOp,
|
||||||
|
CullFace,
|
||||||
|
DebugOutput,
|
||||||
|
DebugOutputSynchronous,
|
||||||
|
DepthClamp,
|
||||||
|
DepthTest,
|
||||||
|
Dither,
|
||||||
|
FramebufferSrgb,
|
||||||
|
LineSmooth,
|
||||||
|
Multisample,
|
||||||
|
PolygonOffsetFill,
|
||||||
|
PolygonOffsetLine,
|
||||||
|
PolygonOffsetPoint,
|
||||||
|
PolygonSmooth,
|
||||||
|
PrimitiveRestart,
|
||||||
|
PrimitiveRestartFixedIndex,
|
||||||
|
RasterizerDiscard,
|
||||||
|
SampleAlphaToCoverage,
|
||||||
|
SampleAlphaToOne,
|
||||||
|
SampleCoverage,
|
||||||
|
SampleShading,
|
||||||
|
SampleMask,
|
||||||
|
ScissorTest,
|
||||||
|
StencilTest,
|
||||||
|
TextureCubeMapSeamless,
|
||||||
|
ProgramPointSize,
|
||||||
|
CapabilityInputCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PixelStoreParameters {
|
||||||
|
Bool SwapBytes = false;
|
||||||
|
Bool LSBFirst = false;
|
||||||
|
Int RowLength = 0;
|
||||||
|
Int ImageHeight = 0;
|
||||||
|
Int SkipPixels = 0;
|
||||||
|
Int SkipRows = 0;
|
||||||
|
Int SkipImages = 0;
|
||||||
|
Int Alignment = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PerBufferBlendState {
|
||||||
|
Bool Enabled = false;
|
||||||
|
BlendFactor SrcFactorRGB = BlendFactor::One;
|
||||||
|
BlendFactor DstFactorRGB = BlendFactor::Zero;
|
||||||
|
BlendFactor SrcFactorAlpha = BlendFactor::One;
|
||||||
|
BlendFactor DstFactorAlpha = BlendFactor::Zero;
|
||||||
|
BlendEquation ColorEquation = BlendEquation::Add;
|
||||||
|
BlendEquation AlphaEquation = BlendEquation::Add;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StencilFaceState {
|
||||||
|
DepthTestFunc Func = DepthTestFunc::Always;
|
||||||
|
Int Ref = 0;
|
||||||
|
Uint32 ValueMask = 0xffffffffu;
|
||||||
|
Uint32 WriteMask = 0xffffffffu;
|
||||||
|
StencilOperation FailOp = StencilOperation::Keep;
|
||||||
|
StencilOperation PassDepthFailOp = StencilOperation::Keep;
|
||||||
|
StencilOperation PassDepthPassOp = StencilOperation::Keep;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderStateParameters {
|
||||||
|
// ARB_viewport_array / GL 4.6 core 13.6.1: the viewport, the scissor rectangle, the depth
|
||||||
|
// range and the scissor-test enable are all arrays indexed by gl_ViewportIndex, and the
|
||||||
|
// spec floor for MAX_VIEWPORTS is 16. MobileGL advertises exactly 16 on both backends, so
|
||||||
|
// this is also what GL_MAX_VIEWPORTS reports (see the backend loaders' caps.MaxViewports).
|
||||||
|
static constexpr Uint MAX_VIEWPORTS = 16;
|
||||||
|
|
||||||
|
// Rasterization
|
||||||
|
// The viewport rectangle is FLOAT state as of GL 4.1 - ViewportIndexedf writes fractional
|
||||||
|
// values and GetFloati_v(GL_VIEWPORT) must hand them back bit-exact
|
||||||
|
// (KHR-GL43.viewport_array.viewport_api compares with ==, no tolerance). glViewport's
|
||||||
|
// integers are simply one way to write it. Index 0 is what a program that never assigns
|
||||||
|
// gl_ViewportIndex rasterizes against, and what the classic glViewport /
|
||||||
|
// glGetIntegerv(GL_VIEWPORT) pair addresses. Both backends rasterize the rectangle
|
||||||
|
// rounded back to integers; the STATE stays exact, which is the half the conformance
|
||||||
|
// suite checks (see the KNOWN INFIDELITY note in AdvertisedLimitsScenario.cpp).
|
||||||
|
Array<FloatVec4, MAX_VIEWPORTS> Viewports{}; // x, y, width, height
|
||||||
|
Float LineWidth = 1.0f;
|
||||||
|
Float PointSize = 1.0f;
|
||||||
|
// GL_PATCH_VERTICES: how many vertices one tessellation patch consumes.
|
||||||
|
Uint PatchVertices = 3;
|
||||||
|
// GL_PATCH_DEFAULT_OUTER_LEVEL / GL_PATCH_DEFAULT_INNER_LEVEL (glPatchParameterfv). The
|
||||||
|
// tessellation levels used when a program has an evaluation stage and NO control stage -
|
||||||
|
// GL's fixed-function pass-through (4.6 core 11.2.2). Both backends have to synthesize
|
||||||
|
// that stage, and they bake these numbers into it, so a change here makes an already-built
|
||||||
|
// one stale exactly as PATCH_VERTICES does. Default 1.0, per table 23.44.
|
||||||
|
FloatVec4 PatchDefaultOuterLevel = FloatVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
FloatVec2 PatchDefaultInnerLevel = FloatVec2(1.0f, 1.0f);
|
||||||
|
Float PolygonOffsetFactor = 0.0f;
|
||||||
|
Float PolygonOffsetUnits = 0.0f;
|
||||||
|
// GL_POLYGON_OFFSET_CLAMP (GL 4.6 core 14.6.5 / GL_EXT_polygon_offset_clamp): the maximum
|
||||||
|
// magnitude of the offset glPolygonOffsetClamp's third argument allows. Zero - the default
|
||||||
|
// - means "no clamp", which is exactly the behaviour glPolygonOffset leaves behind.
|
||||||
|
Float PolygonOffsetClamp = 0.0f;
|
||||||
|
|
||||||
|
// glClipControl (GL 4.5 core 13.5). Defaults per table 23.7 are the pre-4.5 fixed
|
||||||
|
// behaviour: origin at the lower left, depth mapped from -1..1.
|
||||||
|
GLenum ClipOrigin = GL_LOWER_LEFT;
|
||||||
|
GLenum ClipDepthMode = GL_NEGATIVE_ONE_TO_ONE;
|
||||||
|
|
||||||
|
// Blending
|
||||||
|
Array<PerBufferBlendState, kMGMaxDrawBuffers> BlendStates;
|
||||||
|
LogicOperation LogicOp = LogicOperation::Copy;
|
||||||
|
|
||||||
|
// Depth
|
||||||
|
Bool DepthTestEnabled = false;
|
||||||
|
DepthTestFunc DepthFunc = DepthTestFunc::Less;
|
||||||
|
Bool DepthMask = true;
|
||||||
|
|
||||||
|
// Color Mask. Per-draw-buffer state (glColorMaski); glColorMask broadcasts to all buffers.
|
||||||
|
// Every entry is initialized to all-true in RenderState's constructor.
|
||||||
|
Array<BoolVec4, kMGMaxDrawBuffers> ColorMasks;
|
||||||
|
|
||||||
|
// Clear State
|
||||||
|
FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
Float ClearDepth = 1.0f;
|
||||||
|
Uint32 ClearStencil = 0;
|
||||||
|
FloatVec4 BlendColor = FloatVec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
// Per-viewport depth range (glDepthRangeIndexed / glDepthRangeArrayv). Every entry is
|
||||||
|
// initialized to (0, 1) in RenderState's constructor - a default member initializer would
|
||||||
|
// not survive the Array<> aggregate. Kept float rather than double: DepthRangeArrayv takes
|
||||||
|
// GLdouble, but the value reaches the hardware as VkViewport::minDepth/maxDepth (float) on
|
||||||
|
// Magma and glDepthRangef on Espryt, so a double store would only widen the readback and
|
||||||
|
// then lose it again at the same place.
|
||||||
|
Array<FloatVec2, MAX_VIEWPORTS> DepthRanges{};
|
||||||
|
Float SampleCoverageValue = 1.0f;
|
||||||
|
Bool SampleCoverageInvert = false;
|
||||||
|
Uint32 SampleMaskValue = 0xffffffffu;
|
||||||
|
// glMinSampleShading (ARB_sample_shading / GL 4.0 core 14.3.1). The fraction of samples
|
||||||
|
// that get their own independent shading when GL_SAMPLE_SHADING is enabled; the initial
|
||||||
|
// value is 0, and the value is clamped to [0, 1] on the way in.
|
||||||
|
Float MinSampleShadingValue = 0.0f;
|
||||||
|
Array<StencilFaceState, 2> StencilStates{};
|
||||||
|
|
||||||
|
// Cull Face
|
||||||
|
Bool CullFaceEnabled = false;
|
||||||
|
CullFaceMode CullFaceModeSetting = CullFaceMode::Back;
|
||||||
|
FrontFaceMode FrontFaceModeSetting = FrontFaceMode::CounterClockwise;
|
||||||
|
ProvokingVertexMode ProvokingVertexModeSetting = ProvokingVertexMode::LastVertex;
|
||||||
|
|
||||||
|
// Hints (glHint). All GL 3.3 core hint targets default to GL_DONT_CARE.
|
||||||
|
GLenum LineSmoothHint = GL_DONT_CARE;
|
||||||
|
GLenum PolygonSmoothHint = GL_DONT_CARE;
|
||||||
|
GLenum TextureCompressionHint = GL_DONT_CARE;
|
||||||
|
GLenum FragmentShaderDerivativeHint = GL_DONT_CARE;
|
||||||
|
|
||||||
|
// Point parameters (glPointParameter). Only the two GL 3.3 core pnames.
|
||||||
|
Float PointFadeThresholdSize = 1.0f;
|
||||||
|
GLenum PointSpriteCoordOrigin = GL_UPPER_LEFT;
|
||||||
|
|
||||||
|
// Color clamping (glClampColor). Core profile exposes only GL_CLAMP_READ_COLOR.
|
||||||
|
GLenum ClampReadColor = GL_FIXED_ONLY;
|
||||||
|
|
||||||
|
// Polygon rasterization mode (glPolygonMode). Core profile sets front and back together,
|
||||||
|
// but GL_POLYGON_MODE still reports both slots, so keep them separate for a faithful query.
|
||||||
|
GLenum PolygonModeFront = GL_FILL;
|
||||||
|
GLenum PolygonModeBack = GL_FILL;
|
||||||
|
|
||||||
|
// Primitive restart index (glPrimitiveRestartIndex); consumed when GL_PRIMITIVE_RESTART is
|
||||||
|
// enabled during an indexed draw. Default 0.
|
||||||
|
Uint32 PrimitiveRestartIndex = 0;
|
||||||
|
|
||||||
|
// Scissor
|
||||||
|
Bool ColorLogicOpEnabled = false;
|
||||||
|
Bool DebugOutputEnabled = false;
|
||||||
|
Bool DebugOutputSynchronousEnabled = false;
|
||||||
|
Bool DitherEnabled = true;
|
||||||
|
Bool LineSmoothEnabled = false;
|
||||||
|
Bool MultisampleEnabled = true;
|
||||||
|
Bool PolygonOffsetFillEnabled = false;
|
||||||
|
Bool PolygonOffsetLineEnabled = false;
|
||||||
|
Bool PolygonOffsetPointEnabled = false;
|
||||||
|
Bool PolygonSmoothEnabled = false;
|
||||||
|
Bool PrimitiveRestartEnabled = false;
|
||||||
|
Bool PrimitiveRestartFixedIndexEnabled = false;
|
||||||
|
Bool RasterizerDiscardEnabled = false;
|
||||||
|
Bool SampleAlphaToCoverageEnabled = false;
|
||||||
|
Bool SampleAlphaToOneEnabled = false;
|
||||||
|
Bool SampleCoverageEnabled = false;
|
||||||
|
Bool SampleMaskEnabled = false;
|
||||||
|
Bool SampleShadingEnabled = false;
|
||||||
|
Bool StencilTestEnabled = false;
|
||||||
|
Bool ProgramPointSizeEnabled = false;
|
||||||
|
// glEnable(GL_SCISSOR_TEST) enables the test for EVERY viewport, glEnablei for one
|
||||||
|
// (GL 4.6 core 17.3.2), so this is 16 bits and not a bool. Bit 0 is what the classic
|
||||||
|
// glIsEnabled(GL_SCISSOR_TEST) reports and what both backends currently consume. Unlike
|
||||||
|
// ClipDistanceEnabledMask below it DOES bump the pipeline version, because DirectGLES
|
||||||
|
// turns it into a real glEnable/glDisable.
|
||||||
|
Uint32 ScissorTestEnabledMask = 0;
|
||||||
|
Array<IntVec4, MAX_VIEWPORTS> ScissorBoxes{}; // x, y, width, height
|
||||||
|
// One bit per viewport, set the first time the application writes that index's scissor
|
||||||
|
// rectangle - glScissor broadcasts and sets all 16, glScissorIndexed/glScissorArrayv set
|
||||||
|
// the indices they name. It exists because the RECTANGLE cannot answer "has the
|
||||||
|
// application spoken?": ScissorBoxes starts all-zero (its spec initial value is the size
|
||||||
|
// of a window the frontend does not know yet, see the RenderState constructor), and
|
||||||
|
// glScissor(0, 0, 0, 0) is a legal GL state meaning "the scissor test rejects every
|
||||||
|
// fragment". A backend that reads an empty rectangle as the never-written sentinel
|
||||||
|
// therefore INVERTS that request into "accept every fragment"; DirectGLES did exactly
|
||||||
|
// that and KHR-GL43.viewport_array.scissor_zero_dimension caught it. Deliberately beside
|
||||||
|
// ScissorBoxes so it shares their tail span (after LogicOp) and DirectGLES' span memcmp
|
||||||
|
// picks a transition up like any other state.
|
||||||
|
Uint32 ScissorBoxWrittenMask = 0;
|
||||||
|
// glEnable(GL_CLIP_DISTANCE0 + i) for i in [0, 8), one bit each. A bitmask rather than
|
||||||
|
// eight bools because every consumer wants the set, not an individual flag, and because
|
||||||
|
// the SYNC_CAPABILITY/SET_CAPABILITY macros key off a "<Name>Enabled" field name that
|
||||||
|
// eight numbered capabilities cannot share. Lives in the tail span (after LogicOp), so
|
||||||
|
// DirectGLES' span memcmp picks a change up like any other capability.
|
||||||
|
Uint32 ClipDistanceEnabledMask = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SamplerFilterMode {
|
||||||
|
Nearest,
|
||||||
|
Linear,
|
||||||
|
SamplerFilterCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SamplerMipmapMode {
|
||||||
|
None,
|
||||||
|
Nearest,
|
||||||
|
Linear,
|
||||||
|
SamplerMipmapModeCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SamplerWrapMode {
|
||||||
|
ClampToEdge,
|
||||||
|
MirroredRepeat,
|
||||||
|
Repeat,
|
||||||
|
ClampToBorder,
|
||||||
|
MirrorClampToEdge,
|
||||||
|
SamplerWrapModeCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SamplerCompareMode {
|
||||||
|
None,
|
||||||
|
CompareToTexture,
|
||||||
|
SamplerCompareModeCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SamplerCompareFunc {
|
||||||
|
Never,
|
||||||
|
Less,
|
||||||
|
Equal,
|
||||||
|
LessEqual,
|
||||||
|
Greater,
|
||||||
|
NotEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
Always,
|
||||||
|
SamplerCompareFuncCount,
|
||||||
|
Unknown = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Which of the three GL_TEXTURE_BORDER_COLOR entry-point families last wrote the border colour,
|
||||||
|
// and therefore which of the three stored representations is AUTHORITATIVE. GL 4.6 core 8.10:
|
||||||
|
// TexParameterIiv/Iuiv store an integer border colour "unmodified, with an internal data type of
|
||||||
|
// integer", TexParameterfv stores a floating-point one, and the derived forms are only a
|
||||||
|
// convenience for a getter of the other spelling. A backend cannot pick the right driver entry
|
||||||
|
// point (glSamplerParameterIiv vs fv) or the right VkBorderColor family without this: numerically
|
||||||
|
// the three representations are always populated, so the value alone says nothing about the form.
|
||||||
|
enum class BorderColorForm : Uint8 {
|
||||||
|
Float,
|
||||||
|
Int,
|
||||||
|
Uint
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SamplerParameters {
|
||||||
|
SamplerWrapMode wrapS = SamplerWrapMode::Repeat;
|
||||||
|
SamplerWrapMode wrapT = SamplerWrapMode::Repeat;
|
||||||
|
SamplerWrapMode wrapR = SamplerWrapMode::Repeat;
|
||||||
|
SamplerFilterMode minFilter = SamplerFilterMode::Nearest;
|
||||||
|
SamplerFilterMode magFilter = SamplerFilterMode::Linear;
|
||||||
|
SamplerMipmapMode mipmapMode = SamplerMipmapMode::Linear;
|
||||||
|
Float minLod = -1000.0f;
|
||||||
|
Float maxLod = 1000.0f;
|
||||||
|
Float lodBias = 0.0f;
|
||||||
|
Float maxAnisotropy = 1.0f;
|
||||||
|
// GL 4.6 core table 23.18 / GLES 3.2 table 21.16: TEXTURE_COMPARE_FUNC starts at LEQUAL,
|
||||||
|
// for both sampler objects and the sampler state a texture object carries.
|
||||||
|
SamplerCompareFunc compareFunc = SamplerCompareFunc::LessEqual;
|
||||||
|
SamplerCompareMode compareMode = SamplerCompareMode::None;
|
||||||
|
// TEXTURE_BORDER_COLOR is sampler state (GL 4.6 core table 23.18), so it belongs here and
|
||||||
|
// not on the texture - a texture object reaches it through the sampler object it owns. The
|
||||||
|
// three representations are the float, integer and unsigned-integer forms glSamplerParameterfv,
|
||||||
|
// glSamplerParameterIiv and glSamplerParameterIuiv set; whichever is written last defines
|
||||||
|
// the colour and the other two follow it, so a getter always has an answer.
|
||||||
|
FloatVec4 borderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
IntVec4 borderColorI = {0, 0, 0, 0};
|
||||||
|
UintVec4 borderColorUI = {0, 0, 0, 0};
|
||||||
|
BorderColorForm borderColorForm = BorderColorForm::Float;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace MG_State::GLState {
|
||||||
|
class BufferObject;
|
||||||
|
|
||||||
|
struct VertexAttribute {
|
||||||
|
Bool Enabled = false;
|
||||||
|
int Size = 4;
|
||||||
|
DataType Type = DataType::Float32;
|
||||||
|
Bool Normalized = false;
|
||||||
|
// The RESOLVED byte distance between consecutive elements, never the raw
|
||||||
|
// glVertexAttrib*Pointer argument: a pointer call's stride 0 means "tightly
|
||||||
|
// packed" and is resolved to the element size here, so a zero that survives
|
||||||
|
// into this field can only have come from the binding model, where a zero
|
||||||
|
// VERTEX_BINDING_STRIDE means the opposite - every vertex reads the SAME
|
||||||
|
// element and the fetch address never advances (GL 4.6 core 10.3.1). Backends
|
||||||
|
// consume this verbatim; collapsing 0 back into the element size is what made
|
||||||
|
// KHR-GL43.vertex_attrib_binding.basic-input-case7/8 read past the buffer.
|
||||||
|
int Stride = 0;
|
||||||
|
SizeT Offset = 0;
|
||||||
|
Bool IsInteger = false;
|
||||||
|
// GL_BGRA vertex size: four components in reversed (B,G,R,A) memory order. Size stays 4.
|
||||||
|
// Set only by the long (L) format entry points. It is NOT implied by
|
||||||
|
// Type == Float64: VertexAttribFormat(GL_DOUBLE) also reads doubles from memory but
|
||||||
|
// asks for them *converted to float*, while VertexAttribLFormat keeps all 64 bits
|
||||||
|
// (GL 4.6 core 10.3.2). Backends have to tell the two apart, and it is what
|
||||||
|
// GL_VERTEX_ATTRIB_ARRAY_LONG reports.
|
||||||
|
Bool IsLong = false;
|
||||||
|
Bool IsBgra = false;
|
||||||
|
Uint Divisor = 0;
|
||||||
|
SharedPtr<BufferObject> Buffer;
|
||||||
|
|
||||||
|
// GL 4.6 core table 23.3: VERTEX_ATTRIB_ARRAY_STRIDE and _POINTER are the
|
||||||
|
// arguments of the last glVertexAttrib*Pointer call on this attribute,
|
||||||
|
// reported verbatim, and NOTHING else writes them - not glVertexAttribFormat,
|
||||||
|
// not glBindVertexBuffer. Stride/Offset above are the *resolved* draw inputs
|
||||||
|
// and the binding model does overwrite those, so the two views have to be
|
||||||
|
// stored apart or the binding-model sequence reports a legacy state it never
|
||||||
|
// set (KHR-GL4x.vertex_attrib_binding.basic-state3).
|
||||||
|
int LegacyStride = 0;
|
||||||
|
SizeT LegacyPointer = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ARB_vertex_attrib_binding separate binding point. Attributes configured through the
|
||||||
|
// binding-point API are resolved eagerly into the flat VertexAttribute view above, so
|
||||||
|
// backends keep consuming resolved attributes and never see binding points.
|
||||||
|
struct VertexBufferBindingPoint {
|
||||||
|
SharedPtr<BufferObject> Buffer;
|
||||||
|
SizeT Offset = 0;
|
||||||
|
// GL 4.6 core table 23.4: the initial VERTEX_BINDING_STRIDE is 16, not 0.
|
||||||
|
int Stride = 16;
|
||||||
|
Uint Divisor = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexAttributeVersion {
|
||||||
|
Uint16 FormatVersion = 0;
|
||||||
|
Uint16 BufferVersion = 0;
|
||||||
|
Uint16 SwitchVersion = 0;
|
||||||
|
};
|
||||||
|
} // namespace MG_State::GLState
|
||||||
|
|
||||||
|
// ---- trip wires (P0.5). Sizes are what every ABI MobileGL ships on produces: every
|
||||||
|
// member is a fixed-width scalar, an enum of one, or an array of those - no pointer, no
|
||||||
|
// SizeT - except the vertex types, which carry SharedPtr<BufferObject> by design and are
|
||||||
|
// therefore not trivially copyable (MGPipeTypes.h carries them as a blob).
|
||||||
|
static_assert(std::is_trivially_copyable_v<PixelStoreParameters> && sizeof(PixelStoreParameters) == 28);
|
||||||
|
static_assert(std::is_trivially_copyable_v<PerBufferBlendState> && sizeof(PerBufferBlendState) == 28);
|
||||||
|
static_assert(std::is_trivially_copyable_v<StencilFaceState> && sizeof(StencilFaceState) == 28);
|
||||||
|
static_assert(std::is_trivially_copyable_v<RenderStateParameters>);
|
||||||
|
static_assert(std::is_standard_layout_v<RenderStateParameters>); // offsetof legality
|
||||||
|
static_assert(sizeof(RenderStateParameters) == 1168,
|
||||||
|
"RenderStateParameters changed size; MGL_RESIDUAL_BLOCK_SIZE and the Espryt spans depend on it");
|
||||||
|
static_assert(offsetof(RenderStateParameters, BlendStates) < offsetof(RenderStateParameters, LogicOp));
|
||||||
|
static_assert(std::tuple_size_v<decltype(RenderStateParameters::BlendStates)> == kMGMaxDrawBuffers);
|
||||||
|
static_assert(std::is_trivially_copyable_v<SamplerParameters> && sizeof(SamplerParameters) == 100);
|
||||||
|
static_assert(std::is_trivially_copyable_v<MG_State::GLState::VertexAttributeVersion> &&
|
||||||
|
sizeof(MG_State::GLState::VertexAttributeVersion) == 6);
|
||||||
|
} // namespace MobileGL
|
||||||
|
#endif // MOBILEGL_MG_PIPE_VALUE_TYPES_H
|
||||||
@@ -230,11 +230,11 @@ inline Bool MGPipeFieldEqual(const T& a, const T& b) {
|
|||||||
} else if constexpr (requires(const T& x, const T& y) { x == y; }) {
|
} else if constexpr (requires(const T& x, const T& y) { x == y; }) {
|
||||||
return a == b;
|
return a == b;
|
||||||
} else {
|
} else {
|
||||||
// MEMCMP FALLBACK. Only reached by the payload members that are still MG_State /
|
// MEMCMP FALLBACK. Only reached by the payload members that are still value structs
|
||||||
// MG_Backend value structs (RenderStateParameters, PixelStoreParameters,
|
// without a field list (RenderStateParameters, PixelStoreParameters,
|
||||||
// DynamicBackendParameters) and by MGHostSpan. Those are exactly the types P0.5
|
// DynamicBackendParameters) and by MGHostSpan. P0.5 moved the first two into
|
||||||
// moves into MGPipeValueTypes.h, at which point they get field lists of their own
|
// MGPipeValueTypes.h; P1 gives them field lists of their own, at which point this
|
||||||
// and this branch stops being reachable from any payload.
|
// branch stops being reachable from any payload.
|
||||||
return std::memcmp(&a, &b, sizeof(T)) == 0;
|
return std::memcmp(&a, &b, sizeof(T)) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||||
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
|
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
|
||||||
|
#include <MG_Pipe/MGPipeValueTypes.h>
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
enum class FramebufferTarget {
|
enum class FramebufferTarget {
|
||||||
@@ -103,7 +104,7 @@ namespace MobileGL {
|
|||||||
|
|
||||||
class FramebufferObject {
|
class FramebufferObject {
|
||||||
public:
|
public:
|
||||||
static constexpr Uint MAX_DRAW_BUFFERS = 8;
|
static constexpr Uint MAX_DRAW_BUFFERS = MobileGL::kMGMaxDrawBuffers;
|
||||||
|
|
||||||
using TargetEnum = FramebufferTarget;
|
using TargetEnum = FramebufferTarget;
|
||||||
using FramebufferAttachmentObjectArray =
|
using FramebufferAttachmentObjectArray =
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "RenderState.h"
|
#include "RenderState.h"
|
||||||
|
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||||
#include "MG_Util/Debug/Log.h"
|
#include "MG_Util/Debug/Log.h"
|
||||||
#include "MG_Util/Types.h"
|
#include "MG_Util/Types.h"
|
||||||
|
|
||||||
|
|||||||
@@ -8,367 +8,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_Util/Math/VectorTypes.h>
|
#include <MG_Pipe/MGPipeValueTypes.h>
|
||||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
enum class BlendFactor {
|
|
||||||
Zero,
|
|
||||||
One,
|
|
||||||
SrcColor,
|
|
||||||
OneMinusSrcColor,
|
|
||||||
DstColor,
|
|
||||||
OneMinusDstColor,
|
|
||||||
SrcAlpha,
|
|
||||||
OneMinusSrcAlpha,
|
|
||||||
DstAlpha,
|
|
||||||
OneMinusDstAlpha,
|
|
||||||
ConstantColor,
|
|
||||||
OneMinusConstantColor,
|
|
||||||
ConstantAlpha,
|
|
||||||
OneMinusConstantAlpha,
|
|
||||||
// Dual-source blend factors (GL_SRC1_*, glBindFragDataLocationIndexed); require the
|
|
||||||
// dualSrcBlend device feature.
|
|
||||||
Src1Color,
|
|
||||||
OneMinusSrc1Color,
|
|
||||||
Src1Alpha,
|
|
||||||
OneMinusSrc1Alpha,
|
|
||||||
BlendFactorCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class BlendEquation {
|
|
||||||
Add,
|
|
||||||
Subtract,
|
|
||||||
ReverseSubtract,
|
|
||||||
Min,
|
|
||||||
Max,
|
|
||||||
BlendEquationCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class LogicOperation {
|
|
||||||
Clear,
|
|
||||||
And,
|
|
||||||
AndReverse,
|
|
||||||
Copy,
|
|
||||||
AndInverted,
|
|
||||||
Noop,
|
|
||||||
Xor,
|
|
||||||
Or,
|
|
||||||
Nor,
|
|
||||||
Equiv,
|
|
||||||
Invert,
|
|
||||||
OrReverse,
|
|
||||||
CopyInverted,
|
|
||||||
OrInverted,
|
|
||||||
Nand,
|
|
||||||
Set,
|
|
||||||
LogicOperationCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class DepthTestFunc {
|
|
||||||
Never,
|
|
||||||
Less,
|
|
||||||
Equal,
|
|
||||||
LessEqual,
|
|
||||||
Greater,
|
|
||||||
NotEqual,
|
|
||||||
GreaterEqual,
|
|
||||||
Always,
|
|
||||||
DepthTestFuncCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class StencilOperation {
|
|
||||||
Keep,
|
|
||||||
Zero,
|
|
||||||
Replace,
|
|
||||||
IncrementClamp,
|
|
||||||
DecrementClamp,
|
|
||||||
Invert,
|
|
||||||
IncrementWrap,
|
|
||||||
DecrementWrap,
|
|
||||||
StencilOperationCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class StencilFace {
|
|
||||||
Front,
|
|
||||||
Back,
|
|
||||||
StencilFaceCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PixelStoreParam {
|
|
||||||
// Pack Parameters
|
|
||||||
PackAlignment,
|
|
||||||
PackRowLength,
|
|
||||||
PackImageHeight,
|
|
||||||
PackSkipRows,
|
|
||||||
PackSkipPixels,
|
|
||||||
PackSkipImages,
|
|
||||||
PackSwapBytes,
|
|
||||||
PackLSBFirst,
|
|
||||||
|
|
||||||
// Unpack Parameters
|
|
||||||
UnpackAlignment,
|
|
||||||
UnpackRowLength,
|
|
||||||
UnpackImageHeight,
|
|
||||||
UnpackSkipRows,
|
|
||||||
UnpackSkipPixels,
|
|
||||||
UnpackSkipImages,
|
|
||||||
UnpackSwapBytes,
|
|
||||||
UnpackLSBFirst,
|
|
||||||
|
|
||||||
PixelStoreParamCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class CullFaceMode {
|
|
||||||
Front,
|
|
||||||
Back,
|
|
||||||
FrontAndBack,
|
|
||||||
CullFaceModeCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FrontFaceMode {
|
|
||||||
CounterClockwise,
|
|
||||||
Clockwise,
|
|
||||||
FrontFaceModeCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ProvokingVertexMode {
|
|
||||||
FirstVertex,
|
|
||||||
LastVertex,
|
|
||||||
ProvokingVertexModeCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class CapabilityInput {
|
|
||||||
Blend,
|
|
||||||
ClipDistance0,
|
|
||||||
ClipDistance1,
|
|
||||||
ClipDistance2,
|
|
||||||
ClipDistance3,
|
|
||||||
ClipDistance4,
|
|
||||||
ClipDistance5,
|
|
||||||
ClipDistance6,
|
|
||||||
ClipDistance7,
|
|
||||||
ColorLogicOp,
|
|
||||||
CullFace,
|
|
||||||
DebugOutput,
|
|
||||||
DebugOutputSynchronous,
|
|
||||||
DepthClamp,
|
|
||||||
DepthTest,
|
|
||||||
Dither,
|
|
||||||
FramebufferSrgb,
|
|
||||||
LineSmooth,
|
|
||||||
Multisample,
|
|
||||||
PolygonOffsetFill,
|
|
||||||
PolygonOffsetLine,
|
|
||||||
PolygonOffsetPoint,
|
|
||||||
PolygonSmooth,
|
|
||||||
PrimitiveRestart,
|
|
||||||
PrimitiveRestartFixedIndex,
|
|
||||||
RasterizerDiscard,
|
|
||||||
SampleAlphaToCoverage,
|
|
||||||
SampleAlphaToOne,
|
|
||||||
SampleCoverage,
|
|
||||||
SampleShading,
|
|
||||||
SampleMask,
|
|
||||||
ScissorTest,
|
|
||||||
StencilTest,
|
|
||||||
TextureCubeMapSeamless,
|
|
||||||
ProgramPointSize,
|
|
||||||
CapabilityInputCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PixelStoreParameters {
|
|
||||||
Bool SwapBytes = false;
|
|
||||||
Bool LSBFirst = false;
|
|
||||||
Int RowLength = 0;
|
|
||||||
Int ImageHeight = 0;
|
|
||||||
Int SkipPixels = 0;
|
|
||||||
Int SkipRows = 0;
|
|
||||||
Int SkipImages = 0;
|
|
||||||
Int Alignment = 4;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PerBufferBlendState {
|
|
||||||
Bool Enabled = false;
|
|
||||||
BlendFactor SrcFactorRGB = BlendFactor::One;
|
|
||||||
BlendFactor DstFactorRGB = BlendFactor::Zero;
|
|
||||||
BlendFactor SrcFactorAlpha = BlendFactor::One;
|
|
||||||
BlendFactor DstFactorAlpha = BlendFactor::Zero;
|
|
||||||
BlendEquation ColorEquation = BlendEquation::Add;
|
|
||||||
BlendEquation AlphaEquation = BlendEquation::Add;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StencilFaceState {
|
|
||||||
DepthTestFunc Func = DepthTestFunc::Always;
|
|
||||||
Int Ref = 0;
|
|
||||||
Uint32 ValueMask = 0xffffffffu;
|
|
||||||
Uint32 WriteMask = 0xffffffffu;
|
|
||||||
StencilOperation FailOp = StencilOperation::Keep;
|
|
||||||
StencilOperation PassDepthFailOp = StencilOperation::Keep;
|
|
||||||
StencilOperation PassDepthPassOp = StencilOperation::Keep;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RenderStateParameters {
|
|
||||||
// ARB_viewport_array / GL 4.6 core 13.6.1: the viewport, the scissor rectangle, the depth
|
|
||||||
// range and the scissor-test enable are all arrays indexed by gl_ViewportIndex, and the
|
|
||||||
// spec floor for MAX_VIEWPORTS is 16. MobileGL advertises exactly 16 on both backends, so
|
|
||||||
// this is also what GL_MAX_VIEWPORTS reports (see the backend loaders' caps.MaxViewports).
|
|
||||||
static constexpr Uint MAX_VIEWPORTS = 16;
|
|
||||||
|
|
||||||
// Rasterization
|
|
||||||
// The viewport rectangle is FLOAT state as of GL 4.1 - ViewportIndexedf writes fractional
|
|
||||||
// values and GetFloati_v(GL_VIEWPORT) must hand them back bit-exact
|
|
||||||
// (KHR-GL43.viewport_array.viewport_api compares with ==, no tolerance). glViewport's
|
|
||||||
// integers are simply one way to write it. Index 0 is what a program that never assigns
|
|
||||||
// gl_ViewportIndex rasterizes against, and what the classic glViewport /
|
|
||||||
// glGetIntegerv(GL_VIEWPORT) pair addresses. Both backends rasterize the rectangle
|
|
||||||
// rounded back to integers; the STATE stays exact, which is the half the conformance
|
|
||||||
// suite checks (see the KNOWN INFIDELITY note in AdvertisedLimitsScenario.cpp).
|
|
||||||
Array<FloatVec4, MAX_VIEWPORTS> Viewports{}; // x, y, width, height
|
|
||||||
Float LineWidth = 1.0f;
|
|
||||||
Float PointSize = 1.0f;
|
|
||||||
// GL_PATCH_VERTICES: how many vertices one tessellation patch consumes.
|
|
||||||
Uint PatchVertices = 3;
|
|
||||||
// GL_PATCH_DEFAULT_OUTER_LEVEL / GL_PATCH_DEFAULT_INNER_LEVEL (glPatchParameterfv). The
|
|
||||||
// tessellation levels used when a program has an evaluation stage and NO control stage -
|
|
||||||
// GL's fixed-function pass-through (4.6 core 11.2.2). Both backends have to synthesize
|
|
||||||
// that stage, and they bake these numbers into it, so a change here makes an already-built
|
|
||||||
// one stale exactly as PATCH_VERTICES does. Default 1.0, per table 23.44.
|
|
||||||
FloatVec4 PatchDefaultOuterLevel = FloatVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
FloatVec2 PatchDefaultInnerLevel = FloatVec2(1.0f, 1.0f);
|
|
||||||
Float PolygonOffsetFactor = 0.0f;
|
|
||||||
Float PolygonOffsetUnits = 0.0f;
|
|
||||||
// GL_POLYGON_OFFSET_CLAMP (GL 4.6 core 14.6.5 / GL_EXT_polygon_offset_clamp): the maximum
|
|
||||||
// magnitude of the offset glPolygonOffsetClamp's third argument allows. Zero - the default
|
|
||||||
// - means "no clamp", which is exactly the behaviour glPolygonOffset leaves behind.
|
|
||||||
Float PolygonOffsetClamp = 0.0f;
|
|
||||||
|
|
||||||
// glClipControl (GL 4.5 core 13.5). Defaults per table 23.7 are the pre-4.5 fixed
|
|
||||||
// behaviour: origin at the lower left, depth mapped from -1..1.
|
|
||||||
GLenum ClipOrigin = GL_LOWER_LEFT;
|
|
||||||
GLenum ClipDepthMode = GL_NEGATIVE_ONE_TO_ONE;
|
|
||||||
|
|
||||||
// Blending
|
|
||||||
Array<PerBufferBlendState, MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS> BlendStates;
|
|
||||||
LogicOperation LogicOp = LogicOperation::Copy;
|
|
||||||
|
|
||||||
// Depth
|
|
||||||
Bool DepthTestEnabled = false;
|
|
||||||
DepthTestFunc DepthFunc = DepthTestFunc::Less;
|
|
||||||
Bool DepthMask = true;
|
|
||||||
|
|
||||||
// Color Mask. Per-draw-buffer state (glColorMaski); glColorMask broadcasts to all buffers.
|
|
||||||
// Every entry is initialized to all-true in RenderState's constructor.
|
|
||||||
Array<BoolVec4, MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS> ColorMasks;
|
|
||||||
|
|
||||||
// Clear State
|
|
||||||
FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
Float ClearDepth = 1.0f;
|
|
||||||
Uint32 ClearStencil = 0;
|
|
||||||
FloatVec4 BlendColor = FloatVec4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
||||||
// Per-viewport depth range (glDepthRangeIndexed / glDepthRangeArrayv). Every entry is
|
|
||||||
// initialized to (0, 1) in RenderState's constructor - a default member initializer would
|
|
||||||
// not survive the Array<> aggregate. Kept float rather than double: DepthRangeArrayv takes
|
|
||||||
// GLdouble, but the value reaches the hardware as VkViewport::minDepth/maxDepth (float) on
|
|
||||||
// Magma and glDepthRangef on Espryt, so a double store would only widen the readback and
|
|
||||||
// then lose it again at the same place.
|
|
||||||
Array<FloatVec2, MAX_VIEWPORTS> DepthRanges{};
|
|
||||||
Float SampleCoverageValue = 1.0f;
|
|
||||||
Bool SampleCoverageInvert = false;
|
|
||||||
Uint32 SampleMaskValue = 0xffffffffu;
|
|
||||||
// glMinSampleShading (ARB_sample_shading / GL 4.0 core 14.3.1). The fraction of samples
|
|
||||||
// that get their own independent shading when GL_SAMPLE_SHADING is enabled; the initial
|
|
||||||
// value is 0, and the value is clamped to [0, 1] on the way in.
|
|
||||||
Float MinSampleShadingValue = 0.0f;
|
|
||||||
Array<StencilFaceState, 2> StencilStates{};
|
|
||||||
|
|
||||||
// Cull Face
|
|
||||||
Bool CullFaceEnabled = false;
|
|
||||||
CullFaceMode CullFaceModeSetting = CullFaceMode::Back;
|
|
||||||
FrontFaceMode FrontFaceModeSetting = FrontFaceMode::CounterClockwise;
|
|
||||||
ProvokingVertexMode ProvokingVertexModeSetting = ProvokingVertexMode::LastVertex;
|
|
||||||
|
|
||||||
// Hints (glHint). All GL 3.3 core hint targets default to GL_DONT_CARE.
|
|
||||||
GLenum LineSmoothHint = GL_DONT_CARE;
|
|
||||||
GLenum PolygonSmoothHint = GL_DONT_CARE;
|
|
||||||
GLenum TextureCompressionHint = GL_DONT_CARE;
|
|
||||||
GLenum FragmentShaderDerivativeHint = GL_DONT_CARE;
|
|
||||||
|
|
||||||
// Point parameters (glPointParameter). Only the two GL 3.3 core pnames.
|
|
||||||
Float PointFadeThresholdSize = 1.0f;
|
|
||||||
GLenum PointSpriteCoordOrigin = GL_UPPER_LEFT;
|
|
||||||
|
|
||||||
// Color clamping (glClampColor). Core profile exposes only GL_CLAMP_READ_COLOR.
|
|
||||||
GLenum ClampReadColor = GL_FIXED_ONLY;
|
|
||||||
|
|
||||||
// Polygon rasterization mode (glPolygonMode). Core profile sets front and back together,
|
|
||||||
// but GL_POLYGON_MODE still reports both slots, so keep them separate for a faithful query.
|
|
||||||
GLenum PolygonModeFront = GL_FILL;
|
|
||||||
GLenum PolygonModeBack = GL_FILL;
|
|
||||||
|
|
||||||
// Primitive restart index (glPrimitiveRestartIndex); consumed when GL_PRIMITIVE_RESTART is
|
|
||||||
// enabled during an indexed draw. Default 0.
|
|
||||||
Uint32 PrimitiveRestartIndex = 0;
|
|
||||||
|
|
||||||
// Scissor
|
|
||||||
Bool ColorLogicOpEnabled = false;
|
|
||||||
Bool DebugOutputEnabled = false;
|
|
||||||
Bool DebugOutputSynchronousEnabled = false;
|
|
||||||
Bool DitherEnabled = true;
|
|
||||||
Bool LineSmoothEnabled = false;
|
|
||||||
Bool MultisampleEnabled = true;
|
|
||||||
Bool PolygonOffsetFillEnabled = false;
|
|
||||||
Bool PolygonOffsetLineEnabled = false;
|
|
||||||
Bool PolygonOffsetPointEnabled = false;
|
|
||||||
Bool PolygonSmoothEnabled = false;
|
|
||||||
Bool PrimitiveRestartEnabled = false;
|
|
||||||
Bool PrimitiveRestartFixedIndexEnabled = false;
|
|
||||||
Bool RasterizerDiscardEnabled = false;
|
|
||||||
Bool SampleAlphaToCoverageEnabled = false;
|
|
||||||
Bool SampleAlphaToOneEnabled = false;
|
|
||||||
Bool SampleCoverageEnabled = false;
|
|
||||||
Bool SampleMaskEnabled = false;
|
|
||||||
Bool SampleShadingEnabled = false;
|
|
||||||
Bool StencilTestEnabled = false;
|
|
||||||
Bool ProgramPointSizeEnabled = false;
|
|
||||||
// glEnable(GL_SCISSOR_TEST) enables the test for EVERY viewport, glEnablei for one
|
|
||||||
// (GL 4.6 core 17.3.2), so this is 16 bits and not a bool. Bit 0 is what the classic
|
|
||||||
// glIsEnabled(GL_SCISSOR_TEST) reports and what both backends currently consume. Unlike
|
|
||||||
// ClipDistanceEnabledMask below it DOES bump the pipeline version, because DirectGLES
|
|
||||||
// turns it into a real glEnable/glDisable.
|
|
||||||
Uint32 ScissorTestEnabledMask = 0;
|
|
||||||
Array<IntVec4, MAX_VIEWPORTS> ScissorBoxes{}; // x, y, width, height
|
|
||||||
// One bit per viewport, set the first time the application writes that index's scissor
|
|
||||||
// rectangle - glScissor broadcasts and sets all 16, glScissorIndexed/glScissorArrayv set
|
|
||||||
// the indices they name. It exists because the RECTANGLE cannot answer "has the
|
|
||||||
// application spoken?": ScissorBoxes starts all-zero (its spec initial value is the size
|
|
||||||
// of a window the frontend does not know yet, see the RenderState constructor), and
|
|
||||||
// glScissor(0, 0, 0, 0) is a legal GL state meaning "the scissor test rejects every
|
|
||||||
// fragment". A backend that reads an empty rectangle as the never-written sentinel
|
|
||||||
// therefore INVERTS that request into "accept every fragment"; DirectGLES did exactly
|
|
||||||
// that and KHR-GL43.viewport_array.scissor_zero_dimension caught it. Deliberately beside
|
|
||||||
// ScissorBoxes so it shares their tail span (after LogicOp) and DirectGLES' span memcmp
|
|
||||||
// picks a transition up like any other state.
|
|
||||||
Uint32 ScissorBoxWrittenMask = 0;
|
|
||||||
// glEnable(GL_CLIP_DISTANCE0 + i) for i in [0, 8), one bit each. A bitmask rather than
|
|
||||||
// eight bools because every consumer wants the set, not an individual flag, and because
|
|
||||||
// the SYNC_CAPABILITY/SET_CAPABILITY macros key off a "<Name>Enabled" field name that
|
|
||||||
// eight numbered capabilities cannot share. Lives in the tail span (after LogicOp), so
|
|
||||||
// DirectGLES' span memcmp picks a change up like any other capability.
|
|
||||||
Uint32 ClipDistanceEnabledMask = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace MG_State {
|
namespace MG_State {
|
||||||
namespace GLState {
|
namespace GLState {
|
||||||
class RenderState {
|
class RenderState {
|
||||||
|
|||||||
@@ -8,93 +8,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_Util/Math/VectorTypes.h>
|
#include <MG_Pipe/MGPipeValueTypes.h>
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
enum class SamplerFilterMode {
|
|
||||||
Nearest,
|
|
||||||
Linear,
|
|
||||||
SamplerFilterCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SamplerMipmapMode {
|
|
||||||
None,
|
|
||||||
Nearest,
|
|
||||||
Linear,
|
|
||||||
SamplerMipmapModeCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SamplerWrapMode {
|
|
||||||
ClampToEdge,
|
|
||||||
MirroredRepeat,
|
|
||||||
Repeat,
|
|
||||||
ClampToBorder,
|
|
||||||
MirrorClampToEdge,
|
|
||||||
SamplerWrapModeCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SamplerCompareMode {
|
|
||||||
None,
|
|
||||||
CompareToTexture,
|
|
||||||
SamplerCompareModeCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SamplerCompareFunc {
|
|
||||||
Never,
|
|
||||||
Less,
|
|
||||||
Equal,
|
|
||||||
LessEqual,
|
|
||||||
Greater,
|
|
||||||
NotEqual,
|
|
||||||
GreaterEqual,
|
|
||||||
Always,
|
|
||||||
SamplerCompareFuncCount,
|
|
||||||
Unknown = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
// Which of the three GL_TEXTURE_BORDER_COLOR entry-point families last wrote the border colour,
|
|
||||||
// and therefore which of the three stored representations is AUTHORITATIVE. GL 4.6 core 8.10:
|
|
||||||
// TexParameterIiv/Iuiv store an integer border colour "unmodified, with an internal data type of
|
|
||||||
// integer", TexParameterfv stores a floating-point one, and the derived forms are only a
|
|
||||||
// convenience for a getter of the other spelling. A backend cannot pick the right driver entry
|
|
||||||
// point (glSamplerParameterIiv vs fv) or the right VkBorderColor family without this: numerically
|
|
||||||
// the three representations are always populated, so the value alone says nothing about the form.
|
|
||||||
enum class BorderColorForm : Uint8 {
|
|
||||||
Float,
|
|
||||||
Int,
|
|
||||||
Uint
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SamplerParameters {
|
|
||||||
SamplerWrapMode wrapS = SamplerWrapMode::Repeat;
|
|
||||||
SamplerWrapMode wrapT = SamplerWrapMode::Repeat;
|
|
||||||
SamplerWrapMode wrapR = SamplerWrapMode::Repeat;
|
|
||||||
SamplerFilterMode minFilter = SamplerFilterMode::Nearest;
|
|
||||||
SamplerFilterMode magFilter = SamplerFilterMode::Linear;
|
|
||||||
SamplerMipmapMode mipmapMode = SamplerMipmapMode::Linear;
|
|
||||||
Float minLod = -1000.0f;
|
|
||||||
Float maxLod = 1000.0f;
|
|
||||||
Float lodBias = 0.0f;
|
|
||||||
Float maxAnisotropy = 1.0f;
|
|
||||||
// GL 4.6 core table 23.18 / GLES 3.2 table 21.16: TEXTURE_COMPARE_FUNC starts at LEQUAL,
|
|
||||||
// for both sampler objects and the sampler state a texture object carries.
|
|
||||||
SamplerCompareFunc compareFunc = SamplerCompareFunc::LessEqual;
|
|
||||||
SamplerCompareMode compareMode = SamplerCompareMode::None;
|
|
||||||
// TEXTURE_BORDER_COLOR is sampler state (GL 4.6 core table 23.18), so it belongs here and
|
|
||||||
// not on the texture - a texture object reaches it through the sampler object it owns. The
|
|
||||||
// three representations are the float, integer and unsigned-integer forms glSamplerParameterfv,
|
|
||||||
// glSamplerParameterIiv and glSamplerParameterIuiv set; whichever is written last defines
|
|
||||||
// the colour and the other two follow it, so a getter always has an answer.
|
|
||||||
FloatVec4 borderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
IntVec4 borderColorI = {0, 0, 0, 0};
|
|
||||||
UintVec4 borderColorUI = {0, 0, 0, 0};
|
|
||||||
BorderColorForm borderColorForm = BorderColorForm::Float;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace MG_State {
|
namespace MG_State {
|
||||||
namespace GLState {
|
namespace GLState {
|
||||||
class SamplerObject {
|
class SamplerObject {
|
||||||
|
|||||||
@@ -10,65 +10,11 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include "../BufferState/BufferObject.h"
|
#include "../BufferState/BufferObject.h"
|
||||||
#include "MG_Util/Types.h"
|
#include "MG_Util/Types.h"
|
||||||
|
#include <MG_Pipe/MGPipeValueTypes.h>
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
namespace MG_State {
|
namespace MG_State {
|
||||||
namespace GLState {
|
namespace GLState {
|
||||||
struct VertexAttribute {
|
|
||||||
Bool Enabled = false;
|
|
||||||
int Size = 4;
|
|
||||||
DataType Type = DataType::Float32;
|
|
||||||
Bool Normalized = false;
|
|
||||||
// The RESOLVED byte distance between consecutive elements, never the raw
|
|
||||||
// glVertexAttrib*Pointer argument: a pointer call's stride 0 means "tightly
|
|
||||||
// packed" and is resolved to the element size here, so a zero that survives
|
|
||||||
// into this field can only have come from the binding model, where a zero
|
|
||||||
// VERTEX_BINDING_STRIDE means the opposite - every vertex reads the SAME
|
|
||||||
// element and the fetch address never advances (GL 4.6 core 10.3.1). Backends
|
|
||||||
// consume this verbatim; collapsing 0 back into the element size is what made
|
|
||||||
// KHR-GL43.vertex_attrib_binding.basic-input-case7/8 read past the buffer.
|
|
||||||
int Stride = 0;
|
|
||||||
SizeT Offset = 0;
|
|
||||||
Bool IsInteger = false;
|
|
||||||
// GL_BGRA vertex size: four components in reversed (B,G,R,A) memory order. Size stays 4.
|
|
||||||
// Set only by the long (L) format entry points. It is NOT implied by
|
|
||||||
// Type == Float64: VertexAttribFormat(GL_DOUBLE) also reads doubles from memory but
|
|
||||||
// asks for them *converted to float*, while VertexAttribLFormat keeps all 64 bits
|
|
||||||
// (GL 4.6 core 10.3.2). Backends have to tell the two apart, and it is what
|
|
||||||
// GL_VERTEX_ATTRIB_ARRAY_LONG reports.
|
|
||||||
Bool IsLong = false;
|
|
||||||
Bool IsBgra = false;
|
|
||||||
Uint Divisor = 0;
|
|
||||||
SharedPtr<BufferObject> Buffer;
|
|
||||||
|
|
||||||
// GL 4.6 core table 23.3: VERTEX_ATTRIB_ARRAY_STRIDE and _POINTER are the
|
|
||||||
// arguments of the last glVertexAttrib*Pointer call on this attribute,
|
|
||||||
// reported verbatim, and NOTHING else writes them - not glVertexAttribFormat,
|
|
||||||
// not glBindVertexBuffer. Stride/Offset above are the *resolved* draw inputs
|
|
||||||
// and the binding model does overwrite those, so the two views have to be
|
|
||||||
// stored apart or the binding-model sequence reports a legacy state it never
|
|
||||||
// set (KHR-GL4x.vertex_attrib_binding.basic-state3).
|
|
||||||
int LegacyStride = 0;
|
|
||||||
SizeT LegacyPointer = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ARB_vertex_attrib_binding separate binding point. Attributes configured through the
|
|
||||||
// binding-point API are resolved eagerly into the flat VertexAttribute view above, so
|
|
||||||
// backends keep consuming resolved attributes and never see binding points.
|
|
||||||
struct VertexBufferBindingPoint {
|
|
||||||
SharedPtr<BufferObject> Buffer;
|
|
||||||
SizeT Offset = 0;
|
|
||||||
// GL 4.6 core table 23.4: the initial VERTEX_BINDING_STRIDE is 16, not 0.
|
|
||||||
int Stride = 16;
|
|
||||||
Uint Divisor = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VertexAttributeVersion {
|
|
||||||
Uint16 FormatVersion = 0;
|
|
||||||
Uint16 BufferVersion = 0;
|
|
||||||
Uint16 SwitchVersion = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VertexArrayObject {
|
class VertexArrayObject {
|
||||||
public:
|
public:
|
||||||
// Storage capacity, not the GL-visible limit. GL_MAX_VERTEX_ATTRIBS is reported as
|
// Storage capacity, not the GL-visible limit. GL_MAX_VERTEX_ATTRIBS is reported as
|
||||||
|
|||||||
@@ -113,6 +113,39 @@ TEST(PipeCatalogue, ResidualBlockSizeIsPinned) {
|
|||||||
EXPECT_GE(sizeof(ResidualValueBlock), sizeof(RenderStateParameters) + sizeof(PixelStoreParameters));
|
EXPECT_GE(sizeof(ResidualValueBlock), sizeof(RenderStateParameters) + sizeof(PixelStoreParameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// P0.5 moved the value structs into MG_Pipe/MGPipeValueTypes.h. These are the runtime twins
|
||||||
|
// of that header's static assertions, so the numbers show up in ctest output on every
|
||||||
|
// platform - including one where a static assertion is skipped. Every number here is also
|
||||||
|
// what MGL_RESIDUAL_BLOCK_SIZE (MGPipeTypes.h) and the Espryt offsetof spans depend on.
|
||||||
|
TEST(PipeCatalogue, ValueTypeLayoutsArePinned) {
|
||||||
|
EXPECT_EQ(sizeof(PixelStoreParameters), 28u);
|
||||||
|
EXPECT_EQ(sizeof(PerBufferBlendState), 28u);
|
||||||
|
EXPECT_EQ(sizeof(StencilFaceState), 28u);
|
||||||
|
EXPECT_EQ(sizeof(RenderStateParameters), 1168u);
|
||||||
|
EXPECT_EQ(sizeof(SamplerParameters), 100u);
|
||||||
|
EXPECT_EQ(sizeof(MG_State::GLState::VertexAttributeVersion), 6u);
|
||||||
|
EXPECT_TRUE(std::is_trivially_copyable_v<PixelStoreParameters>);
|
||||||
|
EXPECT_TRUE(std::is_trivially_copyable_v<PerBufferBlendState>);
|
||||||
|
EXPECT_TRUE(std::is_trivially_copyable_v<StencilFaceState>);
|
||||||
|
EXPECT_TRUE(std::is_trivially_copyable_v<RenderStateParameters>);
|
||||||
|
EXPECT_TRUE(std::is_standard_layout_v<RenderStateParameters>);
|
||||||
|
EXPECT_TRUE(std::is_trivially_copyable_v<SamplerParameters>);
|
||||||
|
EXPECT_TRUE(std::is_trivially_copyable_v<MG_State::GLState::VertexAttributeVersion>);
|
||||||
|
EXPECT_LT(offsetof(RenderStateParameters, BlendStates), offsetof(RenderStateParameters, LogicOp));
|
||||||
|
EXPECT_EQ(std::tuple_size_v<decltype(RenderStateParameters::BlendStates)>, static_cast<SizeT>(kMGMaxDrawBuffers));
|
||||||
|
EXPECT_EQ(std::tuple_size_v<decltype(RenderStateParameters::ColorMasks)>, static_cast<SizeT>(kMGMaxDrawBuffers));
|
||||||
|
EXPECT_EQ(kMGMaxDrawBuffers, 8u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The move did not alter the carrier: the residual block is still the render-state struct,
|
||||||
|
// then the pack struct, then the 8-aligned capability word, at the offsets it had before.
|
||||||
|
TEST(PipeCatalogue, ResidualBlockIsExactlyItsTwoValueStructsPlusPatchTail) {
|
||||||
|
EXPECT_EQ(offsetof(ResidualValueBlock, RenderState), 0u);
|
||||||
|
EXPECT_EQ(offsetof(ResidualValueBlock, Pack), sizeof(RenderStateParameters));
|
||||||
|
EXPECT_EQ(offsetof(ResidualValueBlock, CapabilityBits), 1200u);
|
||||||
|
EXPECT_EQ(offsetof(ResidualValueBlock, PatchVertices), 1208u);
|
||||||
|
}
|
||||||
|
|
||||||
// G3's opcode numbering is the wire protocol. Position in PipeCalls.def, 1-based, no holes.
|
// G3's opcode numbering is the wire protocol. Position in PipeCalls.def, 1-based, no holes.
|
||||||
TEST(PipeCatalogue, WireOpcodesAreThePositionsInTheCatalogue) {
|
TEST(PipeCatalogue, WireOpcodesAreThePositionsInTheCatalogue) {
|
||||||
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::GetCaps), 1);
|
EXPECT_EQ(static_cast<Uint16>(MGPWireOp::GetCaps), 1);
|
||||||
|
|||||||
+8
-7
@@ -161,8 +161,9 @@ def parse_calls():
|
|||||||
|
|
||||||
|
|
||||||
# The member types the G4 comparator falls back to memcmp for (see gen_verify): the
|
# The member types the G4 comparator falls back to memcmp for (see gen_verify): the
|
||||||
# MG_State / MG_Backend value structs and MGHostSpan. They are not call payloads and get
|
# MG_Pipe / MG_Backend value structs and MGHostSpan. They are not call payloads and get
|
||||||
# field lists of their own in P0.5. Nothing else may be missing from PipeFields.def.
|
# field lists of their own in P1 (P0.5 moved the types). Nothing else may be missing from
|
||||||
|
# PipeFields.def.
|
||||||
MEMCMP_FALLBACK_TYPES = {
|
MEMCMP_FALLBACK_TYPES = {
|
||||||
"RenderStateParameters",
|
"RenderStateParameters",
|
||||||
"PixelStoreParameters",
|
"PixelStoreParameters",
|
||||||
@@ -407,11 +408,11 @@ inline Bool MGPipeFieldEqual(const T& a, const T& b) {
|
|||||||
} else if constexpr (requires(const T& x, const T& y) { x == y; }) {
|
} else if constexpr (requires(const T& x, const T& y) { x == y; }) {
|
||||||
return a == b;
|
return a == b;
|
||||||
} else {
|
} else {
|
||||||
// MEMCMP FALLBACK. Only reached by the payload members that are still MG_State /
|
// MEMCMP FALLBACK. Only reached by the payload members that are still value structs
|
||||||
// MG_Backend value structs (RenderStateParameters, PixelStoreParameters,
|
// without a field list (RenderStateParameters, PixelStoreParameters,
|
||||||
// DynamicBackendParameters) and by MGHostSpan. Those are exactly the types P0.5
|
// DynamicBackendParameters) and by MGHostSpan. P0.5 moved the first two into
|
||||||
// moves into MGPipeValueTypes.h, at which point they get field lists of their own
|
// MGPipeValueTypes.h; P1 gives them field lists of their own, at which point this
|
||||||
// and this branch stops being reachable from any payload.
|
// branch stops being reachable from any payload.
|
||||||
return std::memcmp(&a, &b, sizeof(T)) == 0;
|
return std::memcmp(&a, &b, sizeof(T)) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user