mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Feat] (MG_State, MG_Impl, MG_Backend, MG_Util): make the border colour real sampler state
glGetSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR) raised INVALID_ENUM,
because MobileGL kept the border colour on the texture object and
GetSamplerParam_State had no case for it at all. That is the first thing
direct_state_access.samplers_defaults asks, so the case threw before reaching
any of the defaults it was written to check.
GL 4.6 core table 23.18 lists TEXTURE_BORDER_COLOR as sampler state, so it moves
to SamplerParameters and TextureObjectBase reaches it through the SamplerObject
it already owns - one source of truth, and a sampler object bound over a texture
now supplies its own border colour, which is what GL says should happen. The
texture params version still moves on a write, because the DirectGLES texture
sync memoises on it. glSamplerParameter{fv,Iiv,Iuiv} and their getters read and
write all four components in whichever representation the caller used, and the
three representations are kept in step so any getter has an answer. The bogus
[0,1] and [0,255] range checks are gone: GL clamps a border colour when a
fixed-point format is sampled, it does not reject it.
DirectVulkan's ResolveVkBorderColor now reads the sampler rather than the
texture. DirectGLES gained a glSamplerParameterfv in its sampler sync, and both
that and the pre-existing glTexParameterfv are gated on a new
SupportsTextureBorderClamp capability - ES 3.2 core, or EXT/OES_texture_border_clamp
before it - since without the extension every such call is INVALID_ENUM on the
driver. DriverPost gains the matching row per the POST rule, saying what a user
actually loses when it is missing.
Takes direct_state_access.samplers_defaults from failing to passing on both
backends.
This commit is contained in:
@@ -139,6 +139,61 @@ namespace MobileGL {
|
||||
return m_samplerParameters.maxAnisotropy;
|
||||
}
|
||||
|
||||
// The three border-colour representations are kept in step so a getter of any form has
|
||||
// an answer whichever form was written. Integer <-> float uses the plain value, matching
|
||||
// what glTexParameterIiv/Iuiv mean: those forms are for integer texture formats, whose
|
||||
// border components are the raw integers rather than a normalized fraction.
|
||||
void SamplerObject::SetBorderColor(const FloatVec4& color) {
|
||||
if (color == m_samplerParameters.borderColor) return;
|
||||
|
||||
m_samplerParameters.borderColor = color;
|
||||
m_samplerParameters.borderColorI =
|
||||
IntVec4(static_cast<Int32>(color.x()), static_cast<Int32>(color.y()),
|
||||
static_cast<Int32>(color.z()), static_cast<Int32>(color.w()));
|
||||
m_samplerParameters.borderColorUI =
|
||||
UintVec4(static_cast<Uint32>(color.x()), static_cast<Uint32>(color.y()),
|
||||
static_cast<Uint32>(color.z()), static_cast<Uint32>(color.w()));
|
||||
++m_version;
|
||||
}
|
||||
|
||||
void SamplerObject::SetBorderColorI(const IntVec4& color) {
|
||||
if (color == m_samplerParameters.borderColorI) return;
|
||||
|
||||
m_samplerParameters.borderColorI = color;
|
||||
m_samplerParameters.borderColorUI =
|
||||
UintVec4(static_cast<Uint32>(color.x()), static_cast<Uint32>(color.y()),
|
||||
static_cast<Uint32>(color.z()), static_cast<Uint32>(color.w()));
|
||||
m_samplerParameters.borderColor =
|
||||
FloatVec4(static_cast<Float>(color.x()), static_cast<Float>(color.y()),
|
||||
static_cast<Float>(color.z()), static_cast<Float>(color.w()));
|
||||
++m_version;
|
||||
}
|
||||
|
||||
void SamplerObject::SetBorderColorUI(const UintVec4& color) {
|
||||
if (color == m_samplerParameters.borderColorUI) return;
|
||||
|
||||
m_samplerParameters.borderColorUI = color;
|
||||
m_samplerParameters.borderColorI =
|
||||
IntVec4(static_cast<Int32>(color.x()), static_cast<Int32>(color.y()),
|
||||
static_cast<Int32>(color.z()), static_cast<Int32>(color.w()));
|
||||
m_samplerParameters.borderColor =
|
||||
FloatVec4(static_cast<Float>(color.x()), static_cast<Float>(color.y()),
|
||||
static_cast<Float>(color.z()), static_cast<Float>(color.w()));
|
||||
++m_version;
|
||||
}
|
||||
|
||||
const FloatVec4& SamplerObject::GetBorderColor() const {
|
||||
return m_samplerParameters.borderColor;
|
||||
}
|
||||
|
||||
const IntVec4& SamplerObject::GetBorderColorI() const {
|
||||
return m_samplerParameters.borderColorI;
|
||||
}
|
||||
|
||||
const UintVec4& SamplerObject::GetBorderColorUI() const {
|
||||
return m_samplerParameters.borderColorUI;
|
||||
}
|
||||
|
||||
SamplerCompareMode SamplerObject::GetCompareMode() const {
|
||||
return m_samplerParameters.compareMode;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include <MG_Util/Math/VectorTypes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
enum class SamplerFilterMode {
|
||||
@@ -70,6 +71,14 @@ namespace MobileGL {
|
||||
// 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};
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
@@ -89,6 +98,9 @@ namespace MobileGL {
|
||||
void SetMaxAnisotropy(Float maxAnisotropy);
|
||||
void SetSamplerCompareFunc(SamplerCompareFunc func);
|
||||
void SetCompareMode(SamplerCompareMode mode);
|
||||
void SetBorderColor(const FloatVec4& color);
|
||||
void SetBorderColorI(const IntVec4& color);
|
||||
void SetBorderColorUI(const UintVec4& color);
|
||||
|
||||
SamplerWrapMode GetWrapS() const;
|
||||
SamplerWrapMode GetWrapT() const;
|
||||
@@ -102,6 +114,9 @@ namespace MobileGL {
|
||||
Float GetMaxAnisotropy() const;
|
||||
SamplerCompareMode GetCompareMode() const;
|
||||
SamplerCompareFunc GetSamplerCompareFunc() const;
|
||||
const FloatVec4& GetBorderColor() const;
|
||||
const IntVec4& GetBorderColorI() const;
|
||||
const UintVec4& GetBorderColorUI() const;
|
||||
Uint GetExternalIndex() const;
|
||||
Uint16 GetVersion() const;
|
||||
// Globally-unique, never-reused id for this sampler object's lifetime. Lets a
|
||||
|
||||
@@ -88,48 +88,40 @@ namespace MobileGL {
|
||||
return m_externalIndex;
|
||||
}
|
||||
|
||||
// TEXTURE_BORDER_COLOR is sampler state, so it lives on the SamplerObject this texture
|
||||
// owns rather than being duplicated here - a sampler object bound over the texture then
|
||||
// supplies its own, exactly as GL says it should. The texture params version still moves
|
||||
// on a write, because the DirectGLES texture sync memoises on it.
|
||||
const FloatVec4& TextureObjectBase::GetBorderColor() const {
|
||||
return m_borderColor;
|
||||
return m_sampler->GetBorderColor();
|
||||
}
|
||||
|
||||
void TextureObjectBase::SetBorderColor(const FloatVec4& color) {
|
||||
if (color == m_borderColor) return;
|
||||
if (color == m_sampler->GetBorderColor()) return;
|
||||
|
||||
m_borderColor = color;
|
||||
m_borderColorI = IntVec4(static_cast<Int32>(color.x()), static_cast<Int32>(color.y()),
|
||||
static_cast<Int32>(color.z()), static_cast<Int32>(color.w()));
|
||||
m_borderColorUI = UintVec4(static_cast<Uint32>(color.x()), static_cast<Uint32>(color.y()),
|
||||
static_cast<Uint32>(color.z()), static_cast<Uint32>(color.w()));
|
||||
m_sampler->SetBorderColor(color);
|
||||
++m_textureParamsVersion;
|
||||
}
|
||||
|
||||
const IntVec4& TextureObjectBase::GetBorderColorI() const {
|
||||
return m_borderColorI;
|
||||
return m_sampler->GetBorderColorI();
|
||||
}
|
||||
|
||||
void TextureObjectBase::SetBorderColorI(const IntVec4& color) {
|
||||
if (color == m_borderColorI) return;
|
||||
if (color == m_sampler->GetBorderColorI()) return;
|
||||
|
||||
m_borderColorI = color;
|
||||
m_borderColorUI = UintVec4(static_cast<Uint32>(color.x()), static_cast<Uint32>(color.y()),
|
||||
static_cast<Uint32>(color.z()), static_cast<Uint32>(color.w()));
|
||||
m_borderColor = FloatVec4(static_cast<Float>(color.x()), static_cast<Float>(color.y()),
|
||||
static_cast<Float>(color.z()), static_cast<Float>(color.w()));
|
||||
m_sampler->SetBorderColorI(color);
|
||||
++m_textureParamsVersion;
|
||||
}
|
||||
|
||||
const UintVec4& TextureObjectBase::GetBorderColorUI() const {
|
||||
return m_borderColorUI;
|
||||
return m_sampler->GetBorderColorUI();
|
||||
}
|
||||
|
||||
void TextureObjectBase::SetBorderColorUI(const UintVec4& color) {
|
||||
if (color == m_borderColorUI) return;
|
||||
if (color == m_sampler->GetBorderColorUI()) return;
|
||||
|
||||
m_borderColorUI = color;
|
||||
m_borderColorI = IntVec4(static_cast<Int32>(color.x()), static_cast<Int32>(color.y()),
|
||||
static_cast<Int32>(color.z()), static_cast<Int32>(color.w()));
|
||||
m_borderColor = FloatVec4(static_cast<Float>(color.x()), static_cast<Float>(color.y()),
|
||||
static_cast<Float>(color.z()), static_cast<Float>(color.w()));
|
||||
m_sampler->SetBorderColorUI(color);
|
||||
++m_textureParamsVersion;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,9 +119,6 @@ namespace MobileGL::MG_State::GLState {
|
||||
const TextureTarget m_target = TextureTarget::Unknown;
|
||||
TextureInternalFormat m_internalFormat = TextureInternalFormat::Unknown;
|
||||
SharedPtr<SamplerObject> m_sampler = nullptr;
|
||||
FloatVec4 m_borderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
IntVec4 m_borderColorI = {0, 0, 0, 0};
|
||||
UintVec4 m_borderColorUI = {0, 0, 0, 0};
|
||||
Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
|
||||
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
|
||||
UintVec2 m_levelRange = {0, 1000};
|
||||
|
||||
Reference in New Issue
Block a user