mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18: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,8 +613,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
MG_State::GLState::ITextureObject* texture = ResolveSamplerTextureRaw(program, programObj, binding);
|
MG_State::GLState::ITextureObject* texture = ResolveSamplerTextureRaw(program, programObj, binding);
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
texture = GetFallbackTexture(preferredTarget).get();
|
||||||
|
}
|
||||||
|
|
||||||
auto found = std::find(outTextures.begin(), outTextures.end(), texture);
|
auto found = std::find(outTextures.begin(), outTextures.end(), texture);
|
||||||
if (found == outTextures.end()) {
|
if (found == outTextures.end()) {
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ namespace MobileGL {
|
|||||||
// texture is bound at a unit; lets a backend skip re-resolving an unchanged
|
// texture is bound at a unit; lets a backend skip re-resolving an unchanged
|
||||||
// per-draw sampled-texture set.
|
// per-draw sampled-texture set.
|
||||||
Uint64 GetTextureBindGeneration() const { return m_textureState.GetTextureBindGeneration(); }
|
Uint64 GetTextureBindGeneration() const { return m_textureState.GetTextureBindGeneration(); }
|
||||||
|
void BumpTextureBindGeneration() { m_textureState.BumpTextureBindGeneration(); }
|
||||||
Bool ValidateTextureName(Uint index) const;
|
Bool ValidateTextureName(Uint index) const;
|
||||||
Bool ValidateTextureObject(Uint index) const;
|
Bool ValidateTextureObject(Uint index) const;
|
||||||
Int GetActiveTextureUnit() const;
|
Int GetActiveTextureUnit() const;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "TextureObject.h"
|
#include "TextureObject.h"
|
||||||
|
#include "MG_State/GLState/Core.h"
|
||||||
#include "MG_Util/Types.h"
|
#include "MG_Util/Types.h"
|
||||||
#include <MG_Util/Metrics/TextureMetrics.h>
|
#include <MG_Util/Metrics/TextureMetrics.h>
|
||||||
|
|
||||||
@@ -52,6 +53,20 @@ namespace MobileGL {
|
|||||||
void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) {
|
void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) {
|
||||||
if (format == m_internalFormat) return;
|
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_internalFormat = format;
|
||||||
++m_textureParamsVersion;
|
++m_textureParamsVersion;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <MG_State/EGLState/Core.h>
|
#include <MG_State/EGLState/Core.h>
|
||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
#include <MG_State/GLState/TextureState/TextureObject.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/GLToMG/TextureEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||||
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
||||||
@@ -1840,6 +1841,46 @@ TEST_F(TextureTest, DefaultTextureIsBoundInitiallyAndIsPerTarget) {
|
|||||||
default2D);
|
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) {
|
TEST_F(TextureTest, DefaultTextureAcceptsImageAndParameterCalls) {
|
||||||
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, 0);
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, 0);
|
||||||
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
|||||||
Reference in New Issue
Block a user