[Fix] (MG_State/GLState, MG_Backend): track layered framebuffer textures

This commit is contained in:
2026-07-03 10:38:51 +08:00
parent 6418561d3c
commit 940ab5fd8e
10 changed files with 155 additions and 39 deletions
+16 -6
View File
@@ -1793,12 +1793,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
const GLuint backendFBOId = backendFBO->GetBackendFramebufferId();
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backendFBOId);
g_GLESFuncs.glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, backendAttachment, textureTarget, 0, 0);
if (attachmentObject.IsLayered()) {
g_GLESFuncs.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, backendAttachment, 0, 0);
} else {
g_GLESFuncs.glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, backendAttachment, textureTarget, 0, 0);
}
ClearGLErrors();
m_detachedAttachments.push_back(
{backendFBOId, backendAttachment, textureTarget, backendTextureId,
static_cast<GLint>(attachmentObject.GetTextureLevel())});
static_cast<GLint>(attachmentObject.GetTextureLevel()), attachmentObject.IsLayered()});
}
}
}
@@ -1806,9 +1810,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
~ScopedDetachedTextureFramebufferAttachments() {
for (const auto& attachment : m_detachedAttachments) {
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, attachment.framebuffer);
g_GLESFuncs.glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, attachment.attachment, attachment.textureTarget,
attachment.texture, attachment.level);
if (attachment.layered) {
g_GLESFuncs.glFramebufferTexture(
GL_DRAW_FRAMEBUFFER, attachment.attachment, attachment.texture, attachment.level);
} else {
g_GLESFuncs.glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, attachment.attachment, attachment.textureTarget,
attachment.texture, attachment.level);
}
}
g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, m_prevReadFBO);
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_prevDrawFBO);
@@ -1821,6 +1830,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLenum textureTarget = GL_TEXTURE_2D;
GLuint texture = 0;
GLint level = 0;
Bool layered = false;
};
GLuint m_prevReadFBO = 0;
+14 -8
View File
@@ -1283,15 +1283,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
return false;
}
backendTextureObject->SyncMipmapsToBackend(textureObject);
auto glTextureTarget =
MG_Util::ConvertTextureUploadTargetToGLEnum(attachmentObject.GetTextureUploadTarget());
if (glTextureTarget == GL_UNKNOWN_MGL) {
glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
if (attachmentObject.IsLayered()) {
g_GLESFuncs.glFramebufferTexture(glFBOTarget, glBackendAttachment,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachmentObject.GetTextureLevel()));
} else {
auto glTextureTarget =
MG_Util::ConvertTextureUploadTargetToGLEnum(attachmentObject.GetTextureUploadTarget());
if (glTextureTarget == GL_UNKNOWN_MGL) {
glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
}
backendTextureObject->Bind(glTextureTarget);
g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachmentObject.GetTextureLevel()));
}
backendTextureObject->Bind(glTextureTarget);
g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
static_cast<GLint>(attachmentObject.GetTextureLevel()));
} else if (attachmentObject.IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
const auto& backendRenderbufferIt =
@@ -28,6 +28,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return static_cast<Uint32>(target) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
}
static Uint32 ResolveAttachmentBaseArrayLayer(
const MG_State::GLState::FramebufferAttachmentObject& attachment) {
if (attachment.IsLayered()) {
return 0;
}
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
if (!IsCubeMapFaceUploadTarget(uploadTarget)) {
return static_cast<Uint32>(std::max(attachment.GetTextureLayer(), 0));
}
return ResolveAttachmentBaseArrayLayer(uploadTarget);
}
static Uint32 ResolveAttachmentLayerCount(
const MG_State::GLState::FramebufferAttachmentObject& attachment) {
if (attachment.IsLayered()) {
return static_cast<Uint32>(std::max(attachment.GetSize().z(), 1));
}
return 1u;
}
static const MG_State::GLState::FramebufferAttachmentObject* GetClearableAttachment(
const MG_State::GLState::FramebufferObject& drawFbo, FramebufferAttachmentType attachmentType) {
if (attachmentType == FramebufferAttachmentType::None) {
@@ -60,9 +80,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
auto* texture = attachment.GetTexture().get();
MOBILEGL_ASSERT(texture != nullptr, "MakePendingClearKey: texture attachment resolved to null");
const Uint32 mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(uploadTarget);
const Uint32 layerCount = IsCubeMapFaceUploadTarget(uploadTarget) ? 1u : 1u;
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(attachment);
const Uint32 layerCount = ResolveAttachmentLayerCount(attachment);
return MakePendingClearKey(texture, mipLevel, baseArrayLayer, layerCount);
}
@@ -73,22 +73,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
static Uint32 ResolveAttachmentBaseArrayLayer(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
if (attachment.IsLayered()) {
return 0;
}
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
if (!IsCubeMapFaceUploadTarget(uploadTarget)) {
return 0;
return static_cast<Uint32>(std::max(attachment.GetTextureLayer(), 0));
}
return static_cast<Uint32>(uploadTarget) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
}
static Uint32 ResolveAttachmentLayerCount(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
static_cast<void>(attachment);
if (attachment.IsLayered()) {
return static_cast<Uint32>(std::max(attachment.GetSize().z(), 1));
}
return 1u;
}
static VkImageViewType ResolveAttachmentViewType(
const MG_State::GLState::FramebufferAttachmentObject& attachment,
const VkTextureManager::TextureResource& resource) {
return IsCubeMapFaceUploadTarget(attachment.GetTextureUploadTarget()) ?
return !attachment.IsLayered() && IsCubeMapFaceUploadTarget(attachment.GetTextureUploadTarget()) ?
VK_IMAGE_VIEW_TYPE_2D :
resource.viewType;
}
@@ -438,6 +443,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel)));
const TextureUploadTarget textureUploadTarget = att.GetTextureUploadTarget();
XXHASH_VERIFY(XXH64_update(m_hashState, &textureUploadTarget, sizeof(textureUploadTarget)));
const Int textureLayer = att.GetTextureLayer();
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLayer, sizeof(textureLayer)));
const Bool textureLayered = att.IsLayered();
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLayered, sizeof(textureLayered)));
Uint64 imageIdentity = 0;
auto* texture = att.GetTexture().get();
@@ -621,6 +630,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
attachmentViews.reserve(colorAttachmentSlotCount + 1);
VkSampleCountFlagBits renderPassSampleCount = VK_SAMPLE_COUNT_1_BIT;
Bool hasRenderPassSampleCount = false;
Uint32 framebufferLayers = 1;
const auto adoptRenderPassSampleCount = [&](VkSampleCountFlagBits sampleCount,
const char* attachmentKind,
Int attachmentId) {
@@ -713,6 +723,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
});
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(att);
const Uint32 layerCount = ResolveAttachmentLayerCount(att);
framebufferLayers = std::max(framebufferLayers, layerCount);
const VkImageViewType attachmentViewType = ResolveAttachmentViewType(att, *textureResource);
attachmentViews.emplace_back(
m_textureManager.GetOrCreateAttachmentViewAtMipLevel(
@@ -877,6 +888,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
textureResources.emplace_back(depthTextureResource);
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(*selectedDepthStencilAttachment);
const Uint32 layerCount = ResolveAttachmentLayerCount(*selectedDepthStencilAttachment);
framebufferLayers = std::max(framebufferLayers, layerCount);
const VkImageViewType attachmentViewType =
ResolveAttachmentViewType(*selectedDepthStencilAttachment, *depthTextureResource);
attachmentViews.emplace_back(
@@ -953,7 +965,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
framebufferCreateInfo.pAttachments = attachmentViews.data();
framebufferCreateInfo.width = width;
framebufferCreateInfo.height = height;
framebufferCreateInfo.layers = 1;
framebufferCreateInfo.layers = framebufferLayers;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
IntVec2 extent = {width, height};
@@ -969,7 +981,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
hasDepthStencilAttachment,
renderPassSampleCount,
extent,
1 };
static_cast<Int>(framebufferLayers) };
MGLOG_D("VkRenderPassManager::GetOrCreateRenderPass: hash=0x%llx compatibilityHash=0x%llx attachmentCount=%u colorAttachmentCount=%u samples=%d extent=%dx%d",
static_cast<unsigned long long>(hash),
static_cast<unsigned long long>(compatibilityHash),
@@ -522,6 +522,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
case TextureUploadTarget::ProxyTexture2DMultisample:
outShape = {};
return true;
case TextureUploadTarget::Texture2DArray:
case TextureUploadTarget::ProxyTexture2DArray:
MOBILEGL_ASSERT(texelSize.z() > 0,
"TryResolveTextureShapeInfo: invalid 2D array depth=%d for textureId=%d",
texelSize.z(), texture.GetExternalIndex());
outShape.imageType = VK_IMAGE_TYPE_2D;
outShape.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
outShape.depth = 1;
outShape.arrayLayers = static_cast<Uint32>(texelSize.z());
return true;
case TextureUploadTarget::Texture2DMultisampleArray:
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
MOBILEGL_ASSERT(texelSize.z() > 0,
@@ -923,11 +923,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false;
}
static Bool HasLayeredTextureAttachment(const MG_State::GLState::FramebufferObject& framebufferObject) {
if (framebufferObject.GetExternalIndex() == 0) {
return false;
}
for (const auto& attachment : framebufferObject.GetAllAttachmentObjects()) {
if (attachment.IsTexture() && attachment.IsLayered()) {
return true;
}
}
return false;
}
static Bool IsUnsupportedFramebufferForDirectVulkan(
const MG_State::GLState::FramebufferObject& framebufferObject) {
// TODO: Revisit this gate when DirectVulkan has full color renderbuffer render/blit/readback support.
// TODO: Implement DirectVulkan layered framebuffer rendering instead of rejecting layered draw targets.
return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject) ||
HasUnsupportedCompleteRenderbufferAttachment(framebufferObject);
HasUnsupportedCompleteRenderbufferAttachment(framebufferObject) ||
HasLayeredTextureAttachment(framebufferObject);
}
static void RecordUnsupportedFramebufferError(const char* func) {
@@ -67,7 +67,9 @@ namespace MobileGL::MG_Impl::GLImpl {
}
Bool ResolveRepresentableFramebufferTextureUploadTarget(const MG_State::GLState::ITextureObject& textureObject,
TextureUploadTarget& outUploadTarget) {
TextureUploadTarget& outUploadTarget,
Bool& outLayered) {
outLayered = false;
switch (textureObject.GetTarget()) {
case TextureTarget::Texture1D:
outUploadTarget = TextureUploadTarget::Texture1D;
@@ -81,7 +83,12 @@ namespace MobileGL::MG_Impl::GLImpl {
case TextureTarget::Texture2DMultisample:
outUploadTarget = TextureUploadTarget::Texture2DMultisample;
return true;
case TextureTarget::Texture2DArray:
outUploadTarget = TextureUploadTarget::Texture2DArray;
outLayered = true;
return true;
default:
// TODO: Extend layered framebuffer attachment support to 3D, cube, 1D array, and multisample array textures.
outUploadTarget = TextureUploadTarget::Unknown;
return false;
}
@@ -89,7 +96,7 @@ namespace MobileGL::MG_Impl::GLImpl {
void AttachFramebufferTextureWithUploadTarget(const char* functionName, GLenum target, GLenum attachment,
GLuint texture, GLint level,
TextureUploadTarget textureUploadTarget) {
TextureUploadTarget textureUploadTarget, Bool layered = false) {
if (target == GL_FRAMEBUFFER) {
target = GL_DRAW_FRAMEBUFFER;
}
@@ -145,7 +152,7 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level);
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level, 0, layered);
}
} // namespace
@@ -406,7 +413,15 @@ namespace MobileGL::MG_Impl::GLImpl {
}
break;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
*params = 0;
*params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid())
? static_cast<GLint>(attachmentObject->GetTextureLayer())
: 0;
break;
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
*params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid() &&
attachmentObject->IsLayered())
? GL_TRUE
: GL_FALSE;
break;
default:
MG_State::pGLContext->RecordError(
@@ -661,14 +676,16 @@ namespace MobileGL::MG_Impl::GLImpl {
}
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
if (!ResolveRepresentableFramebufferTextureUploadTarget(*textureObject, textureUploadTarget)) {
Bool layered = false;
if (!ResolveRepresentableFramebufferTextureUploadTarget(*textureObject, textureUploadTarget, layered)) {
RecordUnsupportedFramebufferTextureAttachmentError(
__func__,
"Layered or multi-image framebuffer texture targets are not fully represented by the current framebuffer attachment model.");
return;
}
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget);
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget,
layered);
}
void NamedFramebufferTexture_State(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) {
@@ -700,14 +717,15 @@ namespace MobileGL::MG_Impl::GLImpl {
}
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
if (!ResolveRepresentableFramebufferTextureUploadTarget(*textureObject, textureUploadTarget)) {
Bool layered = false;
if (!ResolveRepresentableFramebufferTextureUploadTarget(*textureObject, textureUploadTarget, layered)) {
RecordUnsupportedFramebufferTextureAttachmentError(
"NamedFramebufferTexture_State",
"Layered or multi-image framebuffer texture targets are not fully represented by the current framebuffer attachment model.");
return;
}
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level);
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level, 0, layered);
}
void NamedFramebufferTextureWithUploadTarget_State(const char* functionName, GLuint framebuffer, GLenum attachment,
@@ -1322,9 +1340,19 @@ namespace MobileGL::MG_Impl::GLImpl {
: 0;
break;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
*params = 0;
break;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
*params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid())
? static_cast<GLint>(attachmentObject->GetTextureLayer())
: 0;
break;
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
*params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid() &&
attachmentObject->IsLayered())
? GL_TRUE
: GL_FALSE;
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
@@ -12,8 +12,10 @@
namespace MobileGL::MG_State::GLState {
// FramebufferAttachmentObject
FramebufferAttachmentObject::FramebufferAttachmentObject(
const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget textureUploadTarget, Int level)
: m_texture(texture), m_textureUploadTarget(textureUploadTarget), m_textureLevel(level) {}
const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget textureUploadTarget, Int level,
Int layer, Bool layered)
: m_texture(texture), m_textureUploadTarget(textureUploadTarget), m_textureLevel(level),
m_textureLayer(layer), m_layered(layered) {}
FramebufferAttachmentObject::FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer)
: m_renderbuffer(renderbuffer) {}
FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid)
@@ -45,6 +47,14 @@ namespace MobileGL::MG_State::GLState {
return m_textureLevel;
}
Int FramebufferAttachmentObject::GetTextureLayer() const {
return m_textureLayer;
}
Bool FramebufferAttachmentObject::IsLayered() const {
return m_layered;
}
TextureUploadTarget FramebufferAttachmentObject::GetTextureUploadTarget() const {
return m_textureUploadTarget;
}
@@ -98,8 +108,9 @@ namespace MobileGL::MG_State::GLState {
}
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture,
TextureUploadTarget textureUploadTarget, int level) {
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(texture, textureUploadTarget, level);
TextureUploadTarget textureUploadTarget, int level, int layer, Bool layered) {
m_attachmentObjects[static_cast<SizeT>(type)] =
FramebufferAttachmentObject(texture, textureUploadTarget, level, layer, layered);
BumpAttachmentVersion(type);
}
@@ -74,7 +74,7 @@ namespace MobileGL {
public:
explicit FramebufferAttachmentObject(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
TextureUploadTarget textureUploadTarget,
Int level = 0);
Int level = 0, Int layer = 0, Bool layered = false);
explicit FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer);
explicit FramebufferAttachmentObject(Bool IsValid = true);
@@ -84,6 +84,8 @@ namespace MobileGL {
const SharedPtr<MG_State::GLState::ITextureObject>& GetTexture() const;
const SharedPtr<RenderbufferObject>& GetRenderbuffer() const;
Int GetTextureLevel() const;
Int GetTextureLayer() const;
Bool IsLayered() const;
TextureUploadTarget GetTextureUploadTarget() const;
Bool IsComplete() const;
IntVec3 GetSize() const;
@@ -94,6 +96,8 @@ namespace MobileGL {
SharedPtr<RenderbufferObject> m_renderbuffer = nullptr;
TextureUploadTarget m_textureUploadTarget = TextureUploadTarget::Unknown;
Int m_textureLevel = 0;
Int m_textureLayer = 0;
Bool m_layered = false;
Bool m_isValid = true;
};
@@ -112,7 +116,8 @@ namespace MobileGL {
FramebufferObject(Uint externalIndex);
void AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture,
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown, int level = 0);
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown, int level = 0,
int layer = 0, Bool layered = false);
void AttachRenderbuffer(FramebufferAttachmentType type, const SharedPtr<RenderbufferObject>& renderbuffer);
void Detach(FramebufferAttachmentType type);
const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
@@ -45,7 +45,7 @@ namespace MobileGL {
{TextureUploadTarget::Texture1DArray});
STUB_TEXTURE_OBJECT_CLASS_DEFINITION(TextureObject2DArray, TextureTarget::Texture2DArray,
{TextureUploadTarget::Texture2D});
{TextureUploadTarget::Texture2DArray});
STUB_TEXTURE_OBJECT_CLASS_DEFINITION(TextureObjectCubeMapArray, TextureTarget::TextureCubeMapArray,
{TextureUploadTarget::CubeMapArray});