[Fix] (DirectVulkan): answer a texture-image query from the CPU shadow when the texture has no VkImage

This commit is contained in:
2026-08-27 08:35:02 -04:00
parent 88ee75be0e
commit 8e072bc793
2 changed files with 25 additions and 1 deletions
@@ -19,6 +19,7 @@
#include "MG_State/GLState/SamplerState/SamplerObject.h"
#include "MG_State/GLState/TextureState/TextureObject.h"
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
#include "MG_Impl/GLImpl/Texture/GL_Texture.h"
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
// Only reached from an MGLOG_W, which the shipping INFO log level compiles out - so the
// missing include never broke a default build and did break every WARN/DEBUG-level one.
@@ -10412,8 +10413,23 @@ void main() {
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*textureObject);
if (resource == nullptr || resource->image == VK_NULL_HANDLE) {
MGLOG_E_ONCE("DirectVulkan::GetTexImage skipped: failed to sync textureId=%u",
// No VkImage exists for this texture, so by construction nothing GPU-side has ever
// written it and the CPU shadow IS its content - answer from there instead of leaving
// the caller's buffer untouched. Gated on "no image at all", never on "the image exists
// but syncing it was inconvenient": a blanket shadow answer would silently return stale
// bytes for every render-to-texture result.
//
// The live shape that lands here is a mutable texture whose GL level 0 was never defined
// - glTexImage2D(GL_TEXTURE_2D, 5, ...) and nothing else, which is exactly what the
// clear_tex_image conformance cases build. VkTextureManager refuses to back such a
// texture (CheckMipmapCompleteness takes storage mip 0 as the image extent), so it is
// invisible to sampling and rendering as well; this fallback fixes the readback only.
MGLOG_D("DirectVulkan::GetTexImage: textureId=%u has no VkImage (GL level 0 undefined?); "
"answering from the CPU shadow",
textureObject->GetExternalIndex());
MG_Impl::GLImpl::CopyTextureImageToClientOrPBO_State(textureObject, textureUploadTarget, level, format,
type, bufSize, pixels,
"DirectVulkan::GetTextureImage");
return;
}
@@ -8,9 +8,17 @@
#pragma once
#include <Includes.h>
#include <MG_State/GLState/TextureState/TextureObject.h>
namespace MobileGL::MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
// Answers a texture-image query straight out of the CPU shadow, honouring the pack state and a
// bound PIXEL_PACK_BUFFER. This is the whole of glGetTexImage on a build with no backend
// readback, and it is also the sound fallback for a backend that has no GPU image to read: with
// no image, nothing GPU-side can ever have written the texture, so the shadow IS its content.
void CopyTextureImageToClientOrPBO_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
TextureUploadTarget textureUploadTarget, GLint level, GLenum format,
GLenum type, GLsizei bufSize, void* pixels, const char* caller);
// The sized internal formats a buffer texture accepts (GL 4.6 core table 8.16). The buffer
// clears take the same list, so it is shared rather than written out twice.
Bool IsBufferTextureInternalFormat(GLenum internalformat);