mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38:30 +09:00
[Fix, Test] (DirectVulkan, GLImpl): size a 1D-array texture's mip chain and layered attachment by the axis that carries its layers
This commit is contained in:
@@ -86,9 +86,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return ToStorageArrayLayer(texture, face);
|
||||
}
|
||||
|
||||
// The attachment's size is GL geometry, and GL_TEXTURE_1D_ARRAY keeps its layer count in the
|
||||
// state-side HEIGHT rather than in z (see ToVulkanLevelExtent, which exists for exactly this
|
||||
// remap). Reading z directly gave every layered 1D-array attachment layerCount = 1, so a
|
||||
// geometry shader writing gl_Layer = 1..n had its output silently dropped and the parent's
|
||||
// upper layers were never written at all.
|
||||
static Uint32 ResolveAttachmentLayerCount(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
if (attachment.IsLayered()) {
|
||||
return static_cast<Uint32>(std::max(attachment.GetSize().z(), 1));
|
||||
const auto& texture = attachment.GetTexture();
|
||||
const TextureTarget target = texture != nullptr ? texture->GetTarget() : TextureTarget::Unknown;
|
||||
return static_cast<Uint32>(std::max(ToVulkanLevelExtent(target, attachment.GetSize()).z(), 1));
|
||||
}
|
||||
return 1u;
|
||||
}
|
||||
@@ -1060,8 +1067,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
.key = VkClearManager::MakePendingClearKey(att)
|
||||
});
|
||||
}
|
||||
const IntVec2 attachmentExtent =
|
||||
ResolveRenderPassFramebufferExtent(isDefaultFbo, att.GetSize(), swapchainExtent);
|
||||
// Same remap as ResolveAttachmentLayerCount, for the same reason: a
|
||||
// 1D-array attachment's GL height is its layer count, and using it as the
|
||||
// framebuffer height asks for a framebuffer taller than the VK_IMAGE_TYPE_1D
|
||||
// image it is built over.
|
||||
const IntVec2 attachmentExtent = ResolveRenderPassFramebufferExtent(
|
||||
isDefaultFbo, ToVulkanLevelExtent(texture->GetTarget(), att.GetSize()), swapchainExtent);
|
||||
if (width == 0)
|
||||
width = attachmentExtent.x();
|
||||
if (height == 0)
|
||||
@@ -1211,9 +1222,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
depthAttachmentDescription.format = depthTextureResource->format;
|
||||
depthAttachmentSampleCount = depthTextureResource->sampleCount;
|
||||
depthAttachmentId = static_cast<Int>(texture.GetExternalIndex());
|
||||
attachmentExtent =
|
||||
ResolveRenderPassFramebufferExtent(isDefaultFbo, selectedDepthStencilAttachment->GetSize(),
|
||||
swapchainExtent);
|
||||
attachmentExtent = ResolveRenderPassFramebufferExtent(
|
||||
isDefaultFbo,
|
||||
ToVulkanLevelExtent(texture.GetTarget(), selectedDepthStencilAttachment->GetSize()),
|
||||
swapchainExtent);
|
||||
} else {
|
||||
const auto& renderbuffer = selectedDepthStencilAttachment->GetRenderbuffer();
|
||||
depthRenderbufferResource = GetOrCreateRenderbufferResource(renderbuffer);
|
||||
|
||||
@@ -4911,7 +4911,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
for (const auto uploadTarget : textureObject->GetUploadTargets()) {
|
||||
for (GLsizei level = 0; level < levels; ++level) {
|
||||
const GLsizei levelWidth = std::max<GLsizei>(1, width >> level);
|
||||
const GLsizei levelHeight = std::max<GLsizei>(1, height >> level);
|
||||
// GL 4.6 core 8.19: for GL_TEXTURE_1D_ARRAY the state-side HEIGHT is the LAYER
|
||||
// COUNT, and layers do not halve down the mip chain - level i is
|
||||
// (max(1, width >> i), height). Shrinking it made every mipmapped 1D array
|
||||
// level report fewer layers than it has.
|
||||
const Bool heightIsLayerCount = textureObject->GetTarget() == TextureTarget::Texture1DArray;
|
||||
const GLsizei levelHeight =
|
||||
heightIsLayerCount ? height : std::max<GLsizei>(1, height >> level);
|
||||
const SizeT byteSize =
|
||||
static_cast<SizeT>(levelWidth) * static_cast<SizeT>(levelHeight) * bytesPerPixel;
|
||||
textureMipmapObject->AllocateStorage(uploadTarget, level, {{levelWidth, levelHeight, 1}, byteSize});
|
||||
|
||||
@@ -1642,6 +1642,38 @@ TEST_F(TextureTest, TexStorage2DTrimsALongerPreExistingMipChain) {
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
// GL 4.6 core 8.19: for GL_TEXTURE_1D_ARRAY the `height` argument of glTexStorage2D is the LAYER
|
||||
// COUNT, and an array texture's layer count "stays put all the way down the chain" (8.14.3) - only
|
||||
// the image's own axes halve. Shrinking it made level i report height >> i layers, which is also
|
||||
// what ComputeMipmapCompleteForFilter reads (it holds component 1 constant for this target), so
|
||||
// every mipmapped 1D array texture judged itself incomplete.
|
||||
TEST_F(TextureTest, TexStorage2DKeepsA1DArrayLayerCountConstantDownTheMipChain) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_1D_ARRAY, texture);
|
||||
|
||||
constexpr GLsizei kLevels = 3;
|
||||
constexpr GLsizei kWidth = 4;
|
||||
constexpr GLsizei kLayers = 4;
|
||||
MG_Impl::GLImpl::TexStorage2D(GL_TEXTURE_1D_ARRAY, kLevels, GL_RGBA8, kWidth, kLayers);
|
||||
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
|
||||
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
auto* mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
ASSERT_NE(mipmapObject, nullptr);
|
||||
ASSERT_EQ(mipmapObject->GetMipmapLevelCount(), static_cast<Uint>(kLevels));
|
||||
|
||||
for (GLsizei level = 0; level < kLevels; ++level) {
|
||||
const IntVec3 size =
|
||||
mipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture1DArray, static_cast<Uint>(level));
|
||||
EXPECT_EQ(size.x(), std::max<GLsizei>(1, kWidth >> level)) << "level " << level << " width";
|
||||
EXPECT_EQ(size.y(), kLayers) << "level " << level << " must keep every layer";
|
||||
}
|
||||
|
||||
// The completeness walk is the reason this matters beyond the reported extent.
|
||||
EXPECT_TRUE(textureObject->IsComplete());
|
||||
}
|
||||
|
||||
// glTexImage2D used to reject every GL_COMPRESSED_* internal format with GL_INVALID_ENUM, because
|
||||
// none of them mapped to a TextureInternalFormat and the "unknown format" gate fired. They now
|
||||
// resolve to the uncompressed storage that backs them - what GL prescribes for the generic formats,
|
||||
|
||||
Reference in New Issue
Block a user