[Fix] (MG_Impl/GLImpl, MG_Backend/DirectVulkan): allow color renderbuffer framebuffers [skip ci]

This commit is contained in:
2026-07-02 19:59:48 +08:00
parent ba330cd70a
commit 1c84422f8e
3 changed files with 31 additions and 32 deletions
@@ -12,6 +12,8 @@
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include "MG_State/GLState/ErrorState/ErrorInfo.h" #include "MG_State/GLState/ErrorState/ErrorInfo.h"
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h" #include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
#include "MG_Util/Metrics/TextureMetrics.h"
#include "MG_Util/Miscellany/IndexGenerator.h" #include "MG_Util/Miscellany/IndexGenerator.h"
#include <cstring> #include <cstring>
#include <spirv_reflect.h> #include <spirv_reflect.h>
@@ -58,6 +60,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
UnorderedMap<GLuint, ProgramResourceCache> g_programResourceCaches; UnorderedMap<GLuint, ProgramResourceCache> g_programResourceCaches;
void ClearReadPixelsOutput(GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
if (!pixels || width <= 0 || height <= 0) {
return;
}
const auto inputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
const auto inputType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
const SizeT size = MG_Util::CalculateInputTextureImageSize(inputFormat, inputType,
IntVec3(width, height, 1));
if (size > 0) {
std::memset(pixels, 0, size);
}
}
String NormalizeDescriptorName(const SpvReflectDescriptorBinding& binding) { String NormalizeDescriptorName(const SpvReflectDescriptorBinding& binding) {
const char* rawName = binding.name; const char* rawName = binding.name;
if (binding.type_description != nullptr && binding.type_description->type_name != nullptr) { if (binding.type_description != nullptr && binding.type_description->type_name != nullptr) {
@@ -1145,8 +1160,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
cache.storageBlocks[storageBlockIndex].binding = storageBlockBinding; cache.storageBlocks[storageBlockIndex].binding = storageBlockBinding;
} }
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ReadPixels called with null VulkanRenderer"); if (!pVulkanRenderer || !MG_State::pGLContext) {
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ReadPixels called with null GL context"); // TODO: Route early/default-FBO readbacks through a real DirectVulkan read path instead of returning zeros.
ClearReadPixelsOutput(width, height, format, type, pixels);
return;
}
pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels); pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels);
} }
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) { void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
@@ -1162,8 +1180,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void Clear(GLbitfield mask) { void Clear(GLbitfield mask) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer"); if (!pVulkanRenderer || !MG_State::pGLContext) {
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context"); // TODO: Preserve pending clears issued before the Vulkan renderer/context is fully attached.
return;
}
pVulkanRenderer->Clear(mask); pVulkanRenderer->Clear(mask);
} }
@@ -1277,8 +1297,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter) { GLint dstY1, GLbitfield mask, GLenum filter) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer"); if (!pVulkanRenderer || !MG_State::pGLContext) {
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context"); // TODO: Support pre-renderer/default-FBO blits instead of dropping them at the DirectVulkan boundary.
return;
}
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
} }
@@ -908,17 +908,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
const auto& attachments = framebufferObject.GetAllAttachmentObjects();
for (SizeT i = 0; i < attachments.size(); ++i) {
const auto attachmentType = static_cast<FramebufferAttachmentType>(i);
const auto& attachment = attachments[i];
if (attachment.IsRenderbuffer() && attachment.IsComplete()) {
if (IsColorAttachment(attachmentType)) {
return true;
}
}
}
const auto& depthAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Depth); const auto& depthAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Depth);
const auto& stencilAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Stencil); const auto& stencilAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Stencil);
if (!depthAttachment.IsComplete() || !stencilAttachment.IsComplete()) { if (!depthAttachment.IsComplete() || !stencilAttachment.IsComplete()) {
@@ -936,6 +925,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
static Bool IsUnsupportedFramebufferForDirectVulkan( static Bool IsUnsupportedFramebufferForDirectVulkan(
const MG_State::GLState::FramebufferObject& framebufferObject) { const MG_State::GLState::FramebufferObject& framebufferObject) {
// TODO: Revisit this gate when DirectVulkan has full color renderbuffer render/blit/readback support.
return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject) || return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject) ||
HasUnsupportedCompleteRenderbufferAttachment(framebufferObject); HasUnsupportedCompleteRenderbufferAttachment(framebufferObject);
} }
@@ -45,23 +45,10 @@ namespace MobileGL::MG_Impl::GLImpl {
depthAttachment.GetTextureLevel() != stencilAttachment.GetTextureLevel(); depthAttachment.GetTextureLevel() != stencilAttachment.GetTextureLevel();
} }
Bool HasCompleteRenderbufferAttachment(const MG_State::GLState::FramebufferObject& framebufferObject) {
if (framebufferObject.GetExternalIndex() == 0) {
return false;
}
for (const auto& attachment : framebufferObject.GetAllAttachmentObjects()) {
if (attachment.IsRenderbuffer() && attachment.IsComplete()) {
return true;
}
}
return false;
}
Bool IsUnsupportedFramebufferForDirectVulkan( Bool IsUnsupportedFramebufferForDirectVulkan(
const MG_State::GLState::FramebufferObject& framebufferObject) { const MG_State::GLState::FramebufferObject& framebufferObject) {
return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject) || // TODO: Keep this in sync with DirectVulkan renderbuffer support as color renderbuffer rendering lands.
HasCompleteRenderbufferAttachment(framebufferObject); return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject);
} }
Bool HasDefinedAttachment(const MG_State::GLState::FramebufferObject& framebufferObject) { Bool HasDefinedAttachment(const MG_State::GLState::FramebufferObject& framebufferObject) {