mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20:58:31 +09:00
[Fix] (MG_State, MG_Backend/DirectVulkan): bump the texture bind generation when a context default texture crosses the undefined<->defined boundary so cached sampled sets re-resolve, and collect the fallback texture into the sampled set so its first use transitions outside the render pass
This commit is contained in:
@@ -613,7 +613,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
MG_State::GLState::ITextureObject* texture = ResolveSamplerTextureRaw(program, programObj, binding);
|
||||
if (!texture) {
|
||||
continue;
|
||||
// ResolveSamplerDescriptor will substitute the fallback texture for this binding;
|
||||
// include it in the sampled set so the pre-render-pass sync/transition pass covers
|
||||
// its first use instead of leaving that work to happen inside an active pass.
|
||||
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
|
||||
if (preferredTarget != TextureTarget::Texture2D &&
|
||||
preferredTarget != TextureTarget::TextureRectangle) {
|
||||
continue;
|
||||
}
|
||||
texture = GetFallbackTexture(preferredTarget).get();
|
||||
}
|
||||
|
||||
auto found = std::find(outTextures.begin(), outTextures.end(), texture);
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace MobileGL {
|
||||
// texture is bound at a unit; lets a backend skip re-resolving an unchanged
|
||||
// per-draw sampled-texture set.
|
||||
Uint64 GetTextureBindGeneration() const { return m_textureState.GetTextureBindGeneration(); }
|
||||
void BumpTextureBindGeneration() { m_textureState.BumpTextureBindGeneration(); }
|
||||
Bool ValidateTextureName(Uint index) const;
|
||||
Bool ValidateTextureObject(Uint index) const;
|
||||
Int GetActiveTextureUnit() const;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "TextureObject.h"
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_Util/Types.h"
|
||||
#include <MG_Util/Metrics/TextureMetrics.h>
|
||||
|
||||
@@ -52,6 +53,20 @@ namespace MobileGL {
|
||||
void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) {
|
||||
if (format == m_internalFormat) return;
|
||||
|
||||
// A default texture (name 0) changes IsUndefinedDefaultTexture on the
|
||||
// Unknown<->defined transition, which changes per-draw sampled-set membership
|
||||
// without any bind happening; bump the bind generation so cached sampled sets
|
||||
// re-resolve instead of replaying the stale membership. The identity check
|
||||
// excludes the other externalIndex-0 objects (proxy textures, default-FBO
|
||||
// attachments) whose definedness never feeds sampled-set membership, so e.g.
|
||||
// proxy probes cannot churn the cache.
|
||||
if (m_externalIndex == 0 && pGLContext &&
|
||||
(m_internalFormat == TextureInternalFormat::Unknown) !=
|
||||
(format == TextureInternalFormat::Unknown) &&
|
||||
pGLContext->GetDefaultTextureObject(GetTarget()).get() == this) {
|
||||
pGLContext->BumpTextureBindGeneration();
|
||||
}
|
||||
|
||||
m_internalFormat = format;
|
||||
++m_textureParamsVersion;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <MG_State/EGLState/Core.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject2D.h>
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
||||
@@ -1840,6 +1841,46 @@ TEST_F(TextureTest, DefaultTextureIsBoundInitiallyAndIsPerTarget) {
|
||||
default2D);
|
||||
}
|
||||
|
||||
// Backend sampled-set membership keys off IsUndefinedDefaultTexture, so a default texture
|
||||
// crossing the Unknown<->defined boundary must move the bind generation even though no bind
|
||||
// happened - a cached sampled set (DirectVulkan walk-skip) would otherwise replay stale
|
||||
// membership and never sync/transition the now-image-bearing default. Positioned while the 2D
|
||||
// default is still undefined in a single-process run (later tests define it and definedness is
|
||||
// irreversible through the GL API); the reverse transition at the end restores that state.
|
||||
TEST_F(TextureTest, DefiningImageOnBoundDefaultTextureBumpsBindGeneration) {
|
||||
MG_Impl::GLImpl::ActiveTexture(GL_TEXTURE0);
|
||||
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, 0);
|
||||
const auto& defaultTexture =
|
||||
MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
|
||||
ASSERT_TRUE(MG_State::GLState::IsUndefinedDefaultTexture(defaultTexture.get()))
|
||||
<< "an earlier test defined the 2D default texture; move this test before it";
|
||||
|
||||
// glTexImage2D on the BOUND name-0 texture (no rebind anywhere) moves the generation
|
||||
// exactly once: the next draw re-collects the sampled set and references the default's
|
||||
// image instead of the fallback.
|
||||
const Uint64 base = MG_State::pGLContext->GetTextureBindGeneration();
|
||||
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureBindGeneration(), base + 1);
|
||||
|
||||
// Re-specifying an already-defined default keeps the cache hot.
|
||||
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureBindGeneration(), base + 1);
|
||||
|
||||
// Other externalIndex-0 objects (proxy textures, default-FBO attachments) are not the
|
||||
// context's default texture; their (re)specification must not churn the cache.
|
||||
auto proxyLike = MakeShared<MG_State::GLState::TextureObject2D>(0u);
|
||||
proxyLike->SetInternalFormat(TextureInternalFormat::RGBA8);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureBindGeneration(), base + 1);
|
||||
|
||||
// The reverse transition (no GL entry point produces it today) is symmetric, and restores
|
||||
// the undefined 2D default the rest of the suite expects.
|
||||
defaultTexture->SetInternalFormat(TextureInternalFormat::Unknown);
|
||||
EXPECT_EQ(MG_State::pGLContext->GetTextureBindGeneration(), base + 2);
|
||||
EXPECT_TRUE(MG_State::GLState::IsUndefinedDefaultTexture(defaultTexture.get()));
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, DefaultTextureAcceptsImageAndParameterCalls) {
|
||||
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, 0);
|
||||
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
|
||||
Reference in New Issue
Block a user