mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Fix] (GL): keep TEXTURE_BASE_LEVEL/MAX_LEVEL as set on immutable textures and clamp only the effective range
This commit is contained in:
@@ -1536,10 +1536,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = static_cast<GLint>(textureObject->GetSamplerObject()->GetMaxLod());
|
||||
break;
|
||||
case GL_TEXTURE_BASE_LEVEL:
|
||||
*params = static_cast<GLint>(textureObject->GetLevelRange().x());
|
||||
*params = static_cast<GLint>(textureObject->GetSpecifiedLevelRange().x());
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LEVEL:
|
||||
*params = static_cast<GLint>(textureObject->GetLevelRange().y());
|
||||
*params = static_cast<GLint>(textureObject->GetSpecifiedLevelRange().y());
|
||||
break;
|
||||
case GL_TEXTURE_IMMUTABLE_FORMAT:
|
||||
*params = textureObject->IsImmutable() ? GL_TRUE : GL_FALSE;
|
||||
@@ -3211,12 +3211,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
break;
|
||||
case GL_TEXTURE_BASE_LEVEL:
|
||||
if (params) {
|
||||
*params = static_cast<GLint>(textureObject->GetLevelRange().x());
|
||||
*params = static_cast<GLint>(textureObject->GetSpecifiedLevelRange().x());
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LEVEL:
|
||||
if (params) {
|
||||
*params = static_cast<GLint>(textureObject->GetLevelRange().y());
|
||||
*params = static_cast<GLint>(textureObject->GetSpecifiedLevelRange().y());
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_IMMUTABLE_FORMAT:
|
||||
@@ -3398,12 +3398,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
break;
|
||||
case GL_TEXTURE_BASE_LEVEL:
|
||||
if (params) {
|
||||
*params = static_cast<GLfloat>(textureObject->GetLevelRange().x());
|
||||
*params = static_cast<GLfloat>(textureObject->GetSpecifiedLevelRange().x());
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LEVEL:
|
||||
if (params) {
|
||||
*params = static_cast<GLfloat>(textureObject->GetLevelRange().y());
|
||||
*params = static_cast<GLfloat>(textureObject->GetSpecifiedLevelRange().y());
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_IMMUTABLE_FORMAT:
|
||||
|
||||
@@ -344,16 +344,29 @@ namespace MobileGL {
|
||||
return m_levelRange;
|
||||
}
|
||||
|
||||
void TextureObjectBase::SetBaseLevel(Uint baseLevel) {
|
||||
if (IsImmutable() && m_immutableLevels > 0) {
|
||||
baseLevel = std::min(baseLevel, m_immutableLevels - 1);
|
||||
}
|
||||
if (baseLevel == m_levelRange.x()) return;
|
||||
const UintVec2& TextureObjectBase::GetSpecifiedLevelRange() const {
|
||||
return m_specifiedLevelRange;
|
||||
}
|
||||
|
||||
m_levelRange.x() = baseLevel;
|
||||
if (IsImmutable() && m_levelRange.y() < m_levelRange.x()) {
|
||||
m_levelRange.y() = m_levelRange.x();
|
||||
// GL 4.6 core 8.17: an immutable texture's level_base is clamped to [0, levels - 1]
|
||||
// and its level_max to [level_base, levels - 1] - when they are USED. The parameters
|
||||
// themselves keep what was set (glGetTexParameter(GL_TEXTURE_MAX_LEVEL) still reads
|
||||
// 1000 after a two-level glTexStorage), so the clamp lives in this derived copy.
|
||||
Bool TextureObjectBase::UpdateEffectiveLevelRange() {
|
||||
UintVec2 effective = m_specifiedLevelRange;
|
||||
if (IsImmutable()) {
|
||||
effective.x() = std::min(effective.x(), m_immutableLevels - 1);
|
||||
effective.y() = std::min(std::max(effective.y(), effective.x()), m_immutableLevels - 1);
|
||||
}
|
||||
if (effective == m_levelRange) return false;
|
||||
m_levelRange = effective;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureObjectBase::SetBaseLevel(Uint baseLevel) {
|
||||
m_specifiedLevelRange.x() = baseLevel;
|
||||
if (!UpdateEffectiveLevelRange()) return;
|
||||
|
||||
++m_textureParamsVersion;
|
||||
MGP_NOTE_AGGREGATE(TextureParams);
|
||||
BumpShapeVersion();
|
||||
@@ -364,12 +377,9 @@ namespace MobileGL {
|
||||
}
|
||||
|
||||
void TextureObjectBase::SetMaxLevel(Uint maxLevel) {
|
||||
if (IsImmutable() && m_immutableLevels > 0) {
|
||||
maxLevel = std::min(std::max(maxLevel, m_levelRange.x()), m_immutableLevels - 1);
|
||||
}
|
||||
if (maxLevel == m_levelRange.y()) return;
|
||||
m_specifiedLevelRange.y() = maxLevel;
|
||||
if (!UpdateEffectiveLevelRange()) return;
|
||||
|
||||
m_levelRange.y() = maxLevel;
|
||||
++m_textureParamsVersion;
|
||||
MGP_NOTE_AGGREGATE(TextureParams);
|
||||
BumpShapeVersion();
|
||||
@@ -388,10 +398,7 @@ namespace MobileGL {
|
||||
if (m_immutableLevels == levels) return;
|
||||
|
||||
m_immutableLevels = levels;
|
||||
if (m_immutableLevels > 0) {
|
||||
m_levelRange.x() = std::min(m_levelRange.x(), m_immutableLevels - 1);
|
||||
m_levelRange.y() = std::min(std::max(m_levelRange.y(), m_levelRange.x()), m_immutableLevels - 1);
|
||||
}
|
||||
UpdateEffectiveLevelRange();
|
||||
++m_textureParamsVersion;
|
||||
MGP_NOTE_AGGREGATE(TextureParams);
|
||||
// Immutable is a descriptor fact the backend reads - and NOT a request for an
|
||||
|
||||
@@ -47,7 +47,12 @@ namespace MobileGL::MG_State::GLState {
|
||||
virtual void SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) = 0;
|
||||
virtual void SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) = 0;
|
||||
virtual const Vec4<TextureSwizzleParam>& GetAllSwizzleParams() const = 0;
|
||||
// The EFFECTIVE [base, max] level range every consumer of the level range samples,
|
||||
// allocates and completes against: on an immutable texture both ends are clamped into
|
||||
// the stored levels (GL 4.6 core 8.17). GetSpecifiedLevelRange() is what the
|
||||
// application set, which is what glGetTexParameter reports.
|
||||
virtual const UintVec2& GetLevelRange() const = 0;
|
||||
virtual const UintVec2& GetSpecifiedLevelRange() const = 0;
|
||||
virtual void SetBaseLevel(Uint baseLevel) = 0;
|
||||
virtual void SetMaxLevel(Uint maxLevel) = 0;
|
||||
virtual Bool IsImmutable() const = 0;
|
||||
@@ -146,6 +151,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
void SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) override;
|
||||
void SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) override;
|
||||
const UintVec2& GetLevelRange() const override;
|
||||
const UintVec2& GetSpecifiedLevelRange() const override;
|
||||
void SetBaseLevel(Uint baseLevel) override;
|
||||
void SetMaxLevel(Uint maxLevel) override;
|
||||
Bool IsImmutable() const override;
|
||||
@@ -225,6 +231,8 @@ namespace MobileGL::MG_State::GLState {
|
||||
// this form on the built descriptor, so an over-call costs one 88-byte compare and
|
||||
// never an extra record.
|
||||
void PipePublishDescriptor();
|
||||
// Re-derives m_levelRange from the specified range; true when the effective range moved.
|
||||
Bool UpdateEffectiveLevelRange();
|
||||
// The PER-LEVEL and the CHAIN-CUT forms of the same call (P4a final review C-1). The
|
||||
// applier keeps a pending-upload set per (uploadTarget, level) and drops the entries
|
||||
// against the storage a respecify REPLACES - and the descriptor cannot tell it which:
|
||||
@@ -252,6 +260,9 @@ namespace MobileGL::MG_State::GLState {
|
||||
SharedPtr<SamplerObject> m_sampler = nullptr;
|
||||
Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
|
||||
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
|
||||
// m_specifiedLevelRange is stored as set; m_levelRange is derived from it and the
|
||||
// immutable level count by UpdateEffectiveLevelRange().
|
||||
UintVec2 m_specifiedLevelRange = {0, 1000};
|
||||
UintVec2 m_levelRange = {0, 1000};
|
||||
Uint m_immutableLevels = 0;
|
||||
Uint16 m_textureParamsVersion = 0;
|
||||
|
||||
@@ -1134,6 +1134,46 @@ TEST_F(TextureTest, ScalarDsaTextureParameterAppliesTheSameTargetRuleAsItsVector
|
||||
DrainPendingGlErrors();
|
||||
}
|
||||
|
||||
// GL 4.6 core 8.17 clamps an immutable texture's base/max level when they are USED; the parameters
|
||||
// keep what was set. A two-level glTexStorage must still read MAX_LEVEL 1000 back, while the
|
||||
// effective range the backends consume is [0, 1] - and a later out-of-range BASE_LEVEL is likewise
|
||||
// reported as set and clamped only in the effective range.
|
||||
TEST_F(TextureTest, ImmutableStorageClampsOnlyTheEffectiveLevelRange) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
ASSERT_NE(texture, 0u);
|
||||
MG_Impl::GLImpl::TextureStorage2D(texture, 2, GL_RGBA8, 4, 4);
|
||||
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
|
||||
GLint queried = -1;
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(texture, GL_TEXTURE_MAX_LEVEL, &queried);
|
||||
EXPECT_EQ(queried, 1000);
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(texture, GL_TEXTURE_BASE_LEVEL, &queried);
|
||||
EXPECT_EQ(queried, 0);
|
||||
|
||||
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
ASSERT_NE(textureObject, nullptr);
|
||||
EXPECT_EQ(textureObject->GetLevelRange(), UintVec2(0, 1));
|
||||
|
||||
MG_Impl::GLImpl::TextureParameteri(texture, GL_TEXTURE_BASE_LEVEL, 5);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
MG_Impl::GLImpl::GetTextureParameteriv(texture, GL_TEXTURE_BASE_LEVEL, &queried);
|
||||
EXPECT_EQ(queried, 5);
|
||||
GLfloat queriedFloat = -1.0f;
|
||||
MG_Impl::GLImpl::GetTextureParameterfv(texture, GL_TEXTURE_MAX_LEVEL, &queriedFloat);
|
||||
EXPECT_EQ(queriedFloat, 1000.0f);
|
||||
EXPECT_EQ(textureObject->GetLevelRange(), UintVec2(1, 1));
|
||||
|
||||
// Back in range: the effective range follows the specified one again.
|
||||
MG_Impl::GLImpl::TextureParameteri(texture, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
MG_Impl::GLImpl::TextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
EXPECT_EQ(textureObject->GetLevelRange(), UintVec2(0, 0));
|
||||
|
||||
MG_Impl::GLImpl::DeleteTextures(1, &texture);
|
||||
DrainPendingGlErrors();
|
||||
}
|
||||
|
||||
// GL 4.6 core 8.10 and 8.11 enumerate exactly ten targets and no proxy. The spec's own asymmetry is
|
||||
// the proof: GetTexLevelParameter needs an explicit clause adding the proxies to ITS list, and these
|
||||
// two entry points carry no such clause - so the proxies must be rejected here and still accepted
|
||||
|
||||
Reference in New Issue
Block a user