mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
GL_PATCH_VERTICES decides how many vertices one tessellation patch consumes, and glPatchParameteri was a stub - so the value stayed at the driver's default of 3 no matter what the application asked for. KHR-GL40.texture_gather.gather-tesselation-shader sets it to 1 and then draws a single patch: with the request dropped the draw had too few vertices for one patch, produced nothing at all, and the case read back the clear colour. The value is context state on both sides and ES 3.2 spells the entry point exactly the same way, so it is stored in the render state (where glGetIntegerv(GL_PATCH_VERTICES) now finds it) and forwarded. Validation needs the real bound, so GL_MAX_PATCH_VERTICES and GL_MAX_TESS_GEN_LEVEL are probed off the host driver alongside the other limits and answered from there too; the defaults are the GL 4.0 core minimums. KHR-GL40.texture_gather is now 75/75.
685 lines
29 KiB
C++
685 lines
29 KiB
C++
// MobileGL - MobileGL/MG_State/GLState/RenderState/RenderState.cpp
|
|
// 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
|
|
|
|
#include "RenderState.h"
|
|
#include "MG_Util/Types.h"
|
|
|
|
namespace MobileGL {
|
|
namespace MG_State {
|
|
namespace GLState {
|
|
namespace {
|
|
SizeT GetStencilFaceIndex(StencilFace face) {
|
|
switch (face) {
|
|
case StencilFace::Front:
|
|
return 0;
|
|
case StencilFace::Back:
|
|
return 1;
|
|
default:
|
|
MOBILEGL_ASSERT(false, "Invalid stencil face enum: %d", static_cast<int>(face));
|
|
return 0;
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
RenderState::RenderState() {
|
|
// The color writemask defaults to all-true for every draw buffer.
|
|
for (auto& mask : m_parameters.ColorMasks) {
|
|
mask = BoolVec4(true, true, true, true);
|
|
}
|
|
}
|
|
|
|
Uint RenderState::GetVersion() const {
|
|
return m_version;
|
|
}
|
|
|
|
const RenderStateParameters& RenderState::GetAllParameters() const {
|
|
return m_parameters;
|
|
}
|
|
|
|
// -------------------- Rasterization --------------------
|
|
void RenderState::SetViewport(IntVec4 viewport) {
|
|
if (m_parameters.Viewport == viewport) return;
|
|
|
|
m_parameters.Viewport = viewport;
|
|
++m_version;
|
|
}
|
|
|
|
const IntVec4& RenderState::GetViewport() const {
|
|
return m_parameters.Viewport;
|
|
}
|
|
|
|
void RenderState::SetLineWidth(Float width) {
|
|
if (m_parameters.LineWidth == width) return;
|
|
|
|
m_parameters.LineWidth = width;
|
|
++m_version;
|
|
}
|
|
|
|
Float RenderState::GetLineWidth() const {
|
|
return m_parameters.LineWidth;
|
|
}
|
|
|
|
void RenderState::SetHint(GLenum target, GLenum mode) {
|
|
GLenum* slot = nullptr;
|
|
switch (target) {
|
|
case GL_LINE_SMOOTH_HINT: slot = &m_parameters.LineSmoothHint; break;
|
|
case GL_POLYGON_SMOOTH_HINT: slot = &m_parameters.PolygonSmoothHint; break;
|
|
case GL_TEXTURE_COMPRESSION_HINT: slot = &m_parameters.TextureCompressionHint; break;
|
|
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: slot = &m_parameters.FragmentShaderDerivativeHint; break;
|
|
default: return;
|
|
}
|
|
if (*slot == mode) return;
|
|
*slot = mode;
|
|
++m_version;
|
|
}
|
|
|
|
GLenum RenderState::GetHint(GLenum target) const {
|
|
switch (target) {
|
|
case GL_LINE_SMOOTH_HINT: return m_parameters.LineSmoothHint;
|
|
case GL_POLYGON_SMOOTH_HINT: return m_parameters.PolygonSmoothHint;
|
|
case GL_TEXTURE_COMPRESSION_HINT: return m_parameters.TextureCompressionHint;
|
|
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: return m_parameters.FragmentShaderDerivativeHint;
|
|
default: return GL_DONT_CARE;
|
|
}
|
|
}
|
|
|
|
void RenderState::SetPointFadeThresholdSize(Float size) {
|
|
if (m_parameters.PointFadeThresholdSize == size) return;
|
|
m_parameters.PointFadeThresholdSize = size;
|
|
++m_version;
|
|
}
|
|
|
|
Float RenderState::GetPointFadeThresholdSize() const {
|
|
return m_parameters.PointFadeThresholdSize;
|
|
}
|
|
|
|
void RenderState::SetPointSpriteCoordOrigin(GLenum origin) {
|
|
if (m_parameters.PointSpriteCoordOrigin == origin) return;
|
|
m_parameters.PointSpriteCoordOrigin = origin;
|
|
++m_version;
|
|
}
|
|
|
|
GLenum RenderState::GetPointSpriteCoordOrigin() const {
|
|
return m_parameters.PointSpriteCoordOrigin;
|
|
}
|
|
|
|
void RenderState::SetClampReadColor(GLenum clamp) {
|
|
if (m_parameters.ClampReadColor == clamp) return;
|
|
m_parameters.ClampReadColor = clamp;
|
|
++m_version;
|
|
}
|
|
|
|
GLenum RenderState::GetClampReadColor() const {
|
|
return m_parameters.ClampReadColor;
|
|
}
|
|
|
|
void RenderState::SetPolygonMode(GLenum front, GLenum back) {
|
|
if (m_parameters.PolygonModeFront == front && m_parameters.PolygonModeBack == back) return;
|
|
m_parameters.PolygonModeFront = front;
|
|
m_parameters.PolygonModeBack = back;
|
|
++m_version;
|
|
}
|
|
|
|
GLenum RenderState::GetPolygonModeFront() const {
|
|
return m_parameters.PolygonModeFront;
|
|
}
|
|
|
|
GLenum RenderState::GetPolygonModeBack() const {
|
|
return m_parameters.PolygonModeBack;
|
|
}
|
|
|
|
void RenderState::SetPrimitiveRestartIndex(Uint32 index) {
|
|
if (m_parameters.PrimitiveRestartIndex == index) return;
|
|
m_parameters.PrimitiveRestartIndex = index;
|
|
++m_version;
|
|
}
|
|
|
|
Uint32 RenderState::GetPrimitiveRestartIndex() const {
|
|
return m_parameters.PrimitiveRestartIndex;
|
|
}
|
|
|
|
void RenderState::SetPointSize(Float size) {
|
|
if (m_parameters.PointSize == size) return;
|
|
|
|
m_parameters.PointSize = size;
|
|
++m_version;
|
|
}
|
|
|
|
Float RenderState::GetPointSize() const {
|
|
return m_parameters.PointSize;
|
|
}
|
|
|
|
void RenderState::SetPatchVertices(Uint vertices) {
|
|
if (m_parameters.PatchVertices == vertices) return;
|
|
|
|
m_parameters.PatchVertices = vertices;
|
|
++m_version;
|
|
}
|
|
|
|
Uint RenderState::GetPatchVertices() const {
|
|
return m_parameters.PatchVertices;
|
|
}
|
|
|
|
void RenderState::SetPolygonOffset(Float factor, Float units) {
|
|
if (m_parameters.PolygonOffsetFactor == factor && m_parameters.PolygonOffsetUnits == units) return;
|
|
|
|
m_parameters.PolygonOffsetFactor = factor;
|
|
m_parameters.PolygonOffsetUnits = units;
|
|
++m_version;
|
|
}
|
|
|
|
Float RenderState::GetPolygonOffsetFactor() const {
|
|
return m_parameters.PolygonOffsetFactor;
|
|
}
|
|
|
|
Float RenderState::GetPolygonOffsetUnits() const {
|
|
return m_parameters.PolygonOffsetUnits;
|
|
}
|
|
|
|
// -------------------- Capabilities --------------------
|
|
void RenderState::SetCapability(CapabilityInput cap, Bool enabled) {
|
|
#define SET_CAPABILITY(capability, flag) \
|
|
case CapabilityInput::capability: \
|
|
if (m_parameters.capability##Enabled == (flag)) break; \
|
|
m_parameters.capability##Enabled = (flag); \
|
|
++m_version; \
|
|
break;
|
|
|
|
switch (cap) {
|
|
SET_CAPABILITY(ColorLogicOp, enabled);
|
|
SET_CAPABILITY(DebugOutput, enabled);
|
|
SET_CAPABILITY(DebugOutputSynchronous, enabled);
|
|
SET_CAPABILITY(DepthTest, enabled);
|
|
SET_CAPABILITY(CullFace, enabled);
|
|
SET_CAPABILITY(Dither, enabled);
|
|
SET_CAPABILITY(LineSmooth, enabled);
|
|
SET_CAPABILITY(Multisample, enabled);
|
|
SET_CAPABILITY(PolygonOffsetFill, enabled);
|
|
SET_CAPABILITY(PolygonOffsetLine, enabled);
|
|
SET_CAPABILITY(PolygonOffsetPoint, enabled);
|
|
SET_CAPABILITY(PolygonSmooth, enabled);
|
|
SET_CAPABILITY(PrimitiveRestart, enabled);
|
|
SET_CAPABILITY(PrimitiveRestartFixedIndex, enabled);
|
|
SET_CAPABILITY(RasterizerDiscard, enabled);
|
|
SET_CAPABILITY(SampleAlphaToCoverage, enabled);
|
|
SET_CAPABILITY(SampleAlphaToOne, enabled);
|
|
SET_CAPABILITY(SampleCoverage, enabled);
|
|
SET_CAPABILITY(SampleMask, enabled);
|
|
SET_CAPABILITY(ScissorTest, enabled);
|
|
SET_CAPABILITY(StencilTest, enabled);
|
|
SET_CAPABILITY(ProgramPointSize, enabled);
|
|
case CapabilityInput::Blend: {
|
|
Bool stateChanged = false;
|
|
for (auto& blendState : m_parameters.BlendStates) {
|
|
if (blendState.Enabled == enabled) continue;
|
|
blendState.Enabled = enabled;
|
|
stateChanged = true;
|
|
}
|
|
if (stateChanged) ++m_version;
|
|
break;
|
|
}
|
|
default: // not supported currently
|
|
break;
|
|
}
|
|
#undef SET_CAPABILITY
|
|
}
|
|
|
|
Bool RenderState::IsCapabilityEnabled(CapabilityInput cap) const {
|
|
#define RETURN_CAPABILITY(capability) \
|
|
case CapabilityInput::capability: \
|
|
return m_parameters.capability##Enabled;
|
|
switch (cap) {
|
|
RETURN_CAPABILITY(ColorLogicOp);
|
|
RETURN_CAPABILITY(DebugOutput);
|
|
RETURN_CAPABILITY(DebugOutputSynchronous);
|
|
RETURN_CAPABILITY(DepthTest);
|
|
RETURN_CAPABILITY(CullFace);
|
|
RETURN_CAPABILITY(Dither);
|
|
RETURN_CAPABILITY(LineSmooth);
|
|
RETURN_CAPABILITY(Multisample);
|
|
RETURN_CAPABILITY(PolygonOffsetFill);
|
|
RETURN_CAPABILITY(PolygonOffsetLine);
|
|
RETURN_CAPABILITY(PolygonOffsetPoint);
|
|
RETURN_CAPABILITY(PolygonSmooth);
|
|
RETURN_CAPABILITY(PrimitiveRestart);
|
|
RETURN_CAPABILITY(PrimitiveRestartFixedIndex);
|
|
RETURN_CAPABILITY(RasterizerDiscard);
|
|
RETURN_CAPABILITY(SampleAlphaToCoverage);
|
|
RETURN_CAPABILITY(SampleAlphaToOne);
|
|
RETURN_CAPABILITY(SampleCoverage);
|
|
RETURN_CAPABILITY(SampleMask);
|
|
RETURN_CAPABILITY(ScissorTest);
|
|
RETURN_CAPABILITY(StencilTest);
|
|
RETURN_CAPABILITY(ProgramPointSize);
|
|
case CapabilityInput::Blend:
|
|
return m_parameters.BlendStates[0].Enabled;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void RenderState::SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled) {
|
|
// Only for BlendState currently
|
|
if (cap != CapabilityInput::Blend) {
|
|
THROW_UNIMPL_EXCEPTION;
|
|
return;
|
|
}
|
|
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
|
MOBILEGL_ASSERT(false, "Blend capability index out of range: %d", index);
|
|
return;
|
|
}
|
|
if (m_parameters.BlendStates[index].Enabled == enabled) return;
|
|
|
|
m_parameters.BlendStates[index].Enabled = enabled;
|
|
++m_version;
|
|
}
|
|
|
|
Bool RenderState::IsCapabilityEnabledIndexed(CapabilityInput cap, Uint index) const {
|
|
// Only for BlendState currently
|
|
if (cap != CapabilityInput::Blend) {
|
|
THROW_UNIMPL_EXCEPTION;
|
|
return false;
|
|
}
|
|
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
|
MOBILEGL_ASSERT(false, "Blend capability index out of range: %d", index);
|
|
return false;
|
|
}
|
|
return m_parameters.BlendStates[index].Enabled;
|
|
}
|
|
|
|
// -------------------- Blending --------------------
|
|
void RenderState::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
|
|
BlendFactor dstAlpha) {
|
|
Bool stateChanged = false;
|
|
for (auto& blendState : m_parameters.BlendStates) {
|
|
if (blendState.SrcFactorRGB == srcRGB && blendState.DstFactorRGB == dstRGB &&
|
|
blendState.SrcFactorAlpha == srcAlpha && blendState.DstFactorAlpha == dstAlpha) {
|
|
continue;
|
|
}
|
|
blendState.SrcFactorRGB = srcRGB;
|
|
blendState.DstFactorRGB = dstRGB;
|
|
blendState.SrcFactorAlpha = srcAlpha;
|
|
blendState.DstFactorAlpha = dstAlpha;
|
|
stateChanged = true;
|
|
}
|
|
if (!stateChanged) return;
|
|
++m_version;
|
|
}
|
|
|
|
void RenderState::GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
|
|
BlendFactor& dstAlpha) const {
|
|
srcRGB = m_parameters.BlendStates[0].SrcFactorRGB;
|
|
dstRGB = m_parameters.BlendStates[0].DstFactorRGB;
|
|
srcAlpha = m_parameters.BlendStates[0].SrcFactorAlpha;
|
|
dstAlpha = m_parameters.BlendStates[0].DstFactorAlpha;
|
|
}
|
|
|
|
void RenderState::SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB,
|
|
BlendFactor srcAlpha, BlendFactor dstAlpha) {
|
|
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
|
MOBILEGL_ASSERT(false, "Blend function index out of range: %d", index);
|
|
return;
|
|
}
|
|
PerBufferBlendState& blendState = m_parameters.BlendStates[index];
|
|
if (blendState.SrcFactorRGB == srcRGB && blendState.DstFactorRGB == dstRGB &&
|
|
blendState.SrcFactorAlpha == srcAlpha && blendState.DstFactorAlpha == dstAlpha) {
|
|
return;
|
|
}
|
|
blendState.SrcFactorRGB = srcRGB;
|
|
blendState.DstFactorRGB = dstRGB;
|
|
blendState.SrcFactorAlpha = srcAlpha;
|
|
blendState.DstFactorAlpha = dstAlpha;
|
|
++m_version;
|
|
}
|
|
|
|
void RenderState::GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB,
|
|
BlendFactor& srcAlpha, BlendFactor& dstAlpha) const {
|
|
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
|
MOBILEGL_ASSERT(false, "Blend function index out of range: %d", index);
|
|
return;
|
|
}
|
|
srcRGB = m_parameters.BlendStates[index].SrcFactorRGB;
|
|
dstRGB = m_parameters.BlendStates[index].DstFactorRGB;
|
|
srcAlpha = m_parameters.BlendStates[index].SrcFactorAlpha;
|
|
dstAlpha = m_parameters.BlendStates[index].DstFactorAlpha;
|
|
}
|
|
|
|
void RenderState::SetBlendEquation(BlendEquation color, BlendEquation alpha) {
|
|
Bool stateChanged = false;
|
|
for (auto& blendState : m_parameters.BlendStates) {
|
|
if (blendState.ColorEquation == color && blendState.AlphaEquation == alpha) {
|
|
continue;
|
|
}
|
|
blendState.ColorEquation = color;
|
|
blendState.AlphaEquation = alpha;
|
|
stateChanged = true;
|
|
}
|
|
if (!stateChanged) return;
|
|
++m_version;
|
|
}
|
|
|
|
void RenderState::GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const {
|
|
color = m_parameters.BlendStates[0].ColorEquation;
|
|
alpha = m_parameters.BlendStates[0].AlphaEquation;
|
|
}
|
|
|
|
void RenderState::SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha) {
|
|
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
|
MOBILEGL_ASSERT(false, "Blend equation index out of range: %d", index);
|
|
return;
|
|
}
|
|
PerBufferBlendState& blendState = m_parameters.BlendStates[index];
|
|
if (blendState.ColorEquation == color && blendState.AlphaEquation == alpha) {
|
|
return;
|
|
}
|
|
blendState.ColorEquation = color;
|
|
blendState.AlphaEquation = alpha;
|
|
++m_version;
|
|
}
|
|
|
|
void RenderState::GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const {
|
|
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
|
MOBILEGL_ASSERT(false, "Blend equation index out of range: %d", index);
|
|
return;
|
|
}
|
|
color = m_parameters.BlendStates[index].ColorEquation;
|
|
alpha = m_parameters.BlendStates[index].AlphaEquation;
|
|
}
|
|
|
|
void RenderState::SetLogicOp(LogicOperation logicOp) {
|
|
if (m_parameters.LogicOp == logicOp) return;
|
|
|
|
m_parameters.LogicOp = logicOp;
|
|
++m_version;
|
|
}
|
|
|
|
LogicOperation RenderState::GetLogicOp() const {
|
|
return m_parameters.LogicOp;
|
|
}
|
|
|
|
// -------------------- Depth --------------------
|
|
void RenderState::SetDepthFunc(DepthTestFunc func) {
|
|
if (m_parameters.DepthFunc == func) return;
|
|
|
|
m_parameters.DepthFunc = func;
|
|
++m_version;
|
|
}
|
|
|
|
DepthTestFunc RenderState::GetDepthFunc() const {
|
|
return m_parameters.DepthFunc;
|
|
}
|
|
|
|
void RenderState::SetDepthMask(Bool flag) {
|
|
if (m_parameters.DepthMask == flag) return;
|
|
|
|
m_parameters.DepthMask = flag;
|
|
++m_version;
|
|
}
|
|
|
|
Bool RenderState::GetDepthMask() const {
|
|
return m_parameters.DepthMask;
|
|
}
|
|
|
|
void RenderState::SetStencilFunc(StencilFace face, DepthTestFunc func, Int ref, Uint32 mask) {
|
|
StencilFaceState& state = m_parameters.StencilStates[GetStencilFaceIndex(face)];
|
|
if (state.Func == func && state.Ref == ref && state.ValueMask == mask) return;
|
|
|
|
state.Func = func;
|
|
state.Ref = ref;
|
|
state.ValueMask = mask;
|
|
++m_version;
|
|
}
|
|
|
|
void RenderState::SetStencilMask(StencilFace face, Uint32 mask) {
|
|
StencilFaceState& state = m_parameters.StencilStates[GetStencilFaceIndex(face)];
|
|
if (state.WriteMask == mask) return;
|
|
|
|
state.WriteMask = mask;
|
|
++m_version;
|
|
}
|
|
|
|
void RenderState::SetStencilOp(StencilFace face, StencilOperation fail, StencilOperation depthFail,
|
|
StencilOperation depthPass) {
|
|
StencilFaceState& state = m_parameters.StencilStates[GetStencilFaceIndex(face)];
|
|
if (state.FailOp == fail && state.PassDepthFailOp == depthFail &&
|
|
state.PassDepthPassOp == depthPass) {
|
|
return;
|
|
}
|
|
|
|
state.FailOp = fail;
|
|
state.PassDepthFailOp = depthFail;
|
|
state.PassDepthPassOp = depthPass;
|
|
++m_version;
|
|
}
|
|
|
|
const StencilFaceState& RenderState::GetStencilState(StencilFace face) const {
|
|
return m_parameters.StencilStates[GetStencilFaceIndex(face)];
|
|
}
|
|
|
|
// -------------------- Color Mask --------------------
|
|
void RenderState::SetColorMask(BoolVec4 mask) {
|
|
// glColorMask broadcasts the same mask to every draw buffer.
|
|
Bool changed = false;
|
|
for (auto& slot : m_parameters.ColorMasks) {
|
|
if (!(slot == mask)) {
|
|
slot = mask;
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed) ++m_version;
|
|
}
|
|
|
|
BoolVec4 RenderState::GetColorMask() const {
|
|
// Non-indexed query reports draw buffer 0.
|
|
return m_parameters.ColorMasks[0];
|
|
}
|
|
|
|
void RenderState::SetColorMaskIndexed(Uint index, BoolVec4 mask) {
|
|
if (m_parameters.ColorMasks[index] == mask) return;
|
|
m_parameters.ColorMasks[index] = mask;
|
|
++m_version;
|
|
}
|
|
|
|
BoolVec4 RenderState::GetColorMaskIndexed(Uint index) const {
|
|
return m_parameters.ColorMasks[index];
|
|
}
|
|
|
|
// -------------------- Clear State --------------------
|
|
void RenderState::SetClearColor(FloatVec4 color) {
|
|
if (m_parameters.ClearColor == color) return;
|
|
|
|
m_parameters.ClearColor = color;
|
|
++m_version;
|
|
}
|
|
|
|
const FloatVec4& RenderState::GetClearColor() const {
|
|
return m_parameters.ClearColor;
|
|
}
|
|
|
|
void RenderState::SetClearDepth(Float depth) {
|
|
if (m_parameters.ClearDepth == depth) return;
|
|
|
|
m_parameters.ClearDepth = depth;
|
|
++m_version;
|
|
}
|
|
|
|
Float RenderState::GetClearDepth() const {
|
|
return m_parameters.ClearDepth;
|
|
}
|
|
|
|
void RenderState::SetClearStencil(Int stencil) {
|
|
if (m_parameters.ClearStencil == stencil) return;
|
|
|
|
m_parameters.ClearStencil = stencil;
|
|
++m_version;
|
|
}
|
|
|
|
Uint32 RenderState::GetClearStencil() const {
|
|
return m_parameters.ClearStencil;
|
|
}
|
|
|
|
void RenderState::SetBlendColor(FloatVec4 color) {
|
|
if (m_parameters.BlendColor == color) return;
|
|
|
|
m_parameters.BlendColor = color;
|
|
++m_version;
|
|
}
|
|
|
|
const FloatVec4& RenderState::GetBlendColor() const {
|
|
return m_parameters.BlendColor;
|
|
}
|
|
|
|
void RenderState::SetDepthRange(FloatVec2 range) {
|
|
if (m_parameters.DepthRange == range) return;
|
|
|
|
m_parameters.DepthRange = range;
|
|
++m_version;
|
|
}
|
|
|
|
const FloatVec2& RenderState::GetDepthRange() const {
|
|
return m_parameters.DepthRange;
|
|
}
|
|
|
|
void RenderState::SetSampleCoverage(Float value, Bool invert) {
|
|
if (m_parameters.SampleCoverageValue == value && m_parameters.SampleCoverageInvert == invert) return;
|
|
|
|
m_parameters.SampleCoverageValue = value;
|
|
m_parameters.SampleCoverageInvert = invert;
|
|
++m_version;
|
|
}
|
|
|
|
Float RenderState::GetSampleCoverageValue() const {
|
|
return m_parameters.SampleCoverageValue;
|
|
}
|
|
|
|
Bool RenderState::GetSampleCoverageInvert() const {
|
|
return m_parameters.SampleCoverageInvert;
|
|
}
|
|
|
|
void RenderState::SetSampleMaskValue(Uint32 mask) {
|
|
if (m_parameters.SampleMaskValue == mask) return;
|
|
|
|
m_parameters.SampleMaskValue = mask;
|
|
++m_version;
|
|
}
|
|
|
|
Uint32 RenderState::GetSampleMaskValue() const {
|
|
return m_parameters.SampleMaskValue;
|
|
}
|
|
|
|
// -------------------- Pixel Store --------------------
|
|
void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) {
|
|
#define SET_PIXEL_STORE_PARAM(paramNameHead, paramNameTail, val) \
|
|
case PixelStoreParam::paramNameHead##paramNameTail: \
|
|
if (m_pixelStore##paramNameHead##Parameters.paramNameTail == (val)) break; \
|
|
m_pixelStore##paramNameHead##Parameters.paramNameTail = (val); \
|
|
break;
|
|
|
|
switch (param) {
|
|
SET_PIXEL_STORE_PARAM(Pack, Alignment, value);
|
|
SET_PIXEL_STORE_PARAM(Pack, RowLength, value);
|
|
SET_PIXEL_STORE_PARAM(Pack, ImageHeight, value);
|
|
SET_PIXEL_STORE_PARAM(Pack, SkipPixels, value);
|
|
SET_PIXEL_STORE_PARAM(Pack, SkipRows, value);
|
|
SET_PIXEL_STORE_PARAM(Pack, SkipImages, value);
|
|
SET_PIXEL_STORE_PARAM(Pack, SwapBytes, value != 0);
|
|
SET_PIXEL_STORE_PARAM(Pack, LSBFirst, value != 0);
|
|
SET_PIXEL_STORE_PARAM(Unpack, Alignment, value);
|
|
SET_PIXEL_STORE_PARAM(Unpack, RowLength, value);
|
|
SET_PIXEL_STORE_PARAM(Unpack, ImageHeight, value);
|
|
SET_PIXEL_STORE_PARAM(Unpack, SkipPixels, value);
|
|
SET_PIXEL_STORE_PARAM(Unpack, SkipRows, value);
|
|
SET_PIXEL_STORE_PARAM(Unpack, SkipImages, value);
|
|
SET_PIXEL_STORE_PARAM(Unpack, SwapBytes, value != 0);
|
|
SET_PIXEL_STORE_PARAM(Unpack, LSBFirst, value != 0);
|
|
default:
|
|
MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param));
|
|
return;
|
|
}
|
|
}
|
|
|
|
Int RenderState::GetPixelStoreParam(PixelStoreParam param) const {
|
|
#define RETURN_PIXEL_STORE_PARAM(paramNameHead, paramNameTail) \
|
|
case PixelStoreParam::paramNameHead##paramNameTail: \
|
|
return m_pixelStore##paramNameHead##Parameters.paramNameTail;
|
|
switch (param) {
|
|
RETURN_PIXEL_STORE_PARAM(Pack, Alignment);
|
|
RETURN_PIXEL_STORE_PARAM(Pack, RowLength);
|
|
RETURN_PIXEL_STORE_PARAM(Pack, ImageHeight);
|
|
RETURN_PIXEL_STORE_PARAM(Pack, SkipPixels);
|
|
RETURN_PIXEL_STORE_PARAM(Pack, SkipRows);
|
|
RETURN_PIXEL_STORE_PARAM(Pack, SkipImages);
|
|
RETURN_PIXEL_STORE_PARAM(Pack, SwapBytes);
|
|
RETURN_PIXEL_STORE_PARAM(Pack, LSBFirst);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, Alignment);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, RowLength);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, ImageHeight);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, SkipPixels);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, SkipRows);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, SkipImages);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, SwapBytes);
|
|
RETURN_PIXEL_STORE_PARAM(Unpack, LSBFirst);
|
|
default:
|
|
MOBILEGL_ASSERT(false, "Invalid PixelStoreParam enum: %d", static_cast<int>(param));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
PixelStoreParameters RenderState::GetPixelStoreParameters(Bool isUnpack) const {
|
|
return isUnpack ? m_pixelStoreUnpackParameters : m_pixelStorePackParameters;
|
|
}
|
|
|
|
// -------------------- Cull Face --------------------
|
|
void RenderState::SetCullFaceMode(CullFaceMode mode) {
|
|
if (m_parameters.CullFaceModeSetting == mode) return;
|
|
|
|
m_parameters.CullFaceModeSetting = mode;
|
|
++m_version;
|
|
}
|
|
|
|
CullFaceMode RenderState::GetCullFaceMode() const {
|
|
return m_parameters.CullFaceModeSetting;
|
|
}
|
|
|
|
void RenderState::SetFrontFaceMode(FrontFaceMode mode) {
|
|
if (m_parameters.FrontFaceModeSetting == mode) return;
|
|
|
|
m_parameters.FrontFaceModeSetting = mode;
|
|
++m_version;
|
|
}
|
|
|
|
FrontFaceMode RenderState::GetFrontFaceMode() const {
|
|
return m_parameters.FrontFaceModeSetting;
|
|
}
|
|
|
|
void RenderState::SetProvokingVertexMode(ProvokingVertexMode mode) {
|
|
if (m_parameters.ProvokingVertexModeSetting == mode) return;
|
|
|
|
m_parameters.ProvokingVertexModeSetting = mode;
|
|
++m_version;
|
|
}
|
|
|
|
ProvokingVertexMode RenderState::GetProvokingVertexMode() const {
|
|
return m_parameters.ProvokingVertexModeSetting;
|
|
}
|
|
|
|
// --------------------- Scissor ---------------------
|
|
void RenderState::SetScissorBox(IntVec4 box) {
|
|
if (m_parameters.ScissorBox == box) return;
|
|
|
|
m_parameters.ScissorBox = box;
|
|
++m_version;
|
|
}
|
|
|
|
const IntVec4& RenderState::GetScissorBox() const {
|
|
return m_parameters.ScissorBox;
|
|
}
|
|
} // namespace GLState
|
|
} // namespace MG_State
|
|
} // namespace MobileGL
|