mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-18 00:58:30 +09:00
[Fix] (DirectGLES): verify generated mip storage from pushed descriptors
This commit is contained in:
@@ -8078,6 +8078,38 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
static Bool EnsureGenerateMipmapStorageAllocated(const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
// The frontend has already defined the generated chain before emitting this verb.
|
||||
// Its resource_respecify carries that shape, so the server only verifies the
|
||||
// descriptor; it must not allocate or dirty the client's level shadows again.
|
||||
// Identity resolution is the same existing registry lookup used by texture sync.
|
||||
const auto handle = TextureImpl::g_backendTextureObjects.HandleOf(texture.get());
|
||||
const auto* record = PipeTextureRecordForHandle(handle);
|
||||
if (record == nullptr || record->Desc.Width == 0 || record->Desc.Levels == 0) {
|
||||
MG_Pipe::MGPipeUnmigratedEmulation("generate-mipmap-storage");
|
||||
}
|
||||
const auto& desc = record->Desc;
|
||||
Uint maxDimension = desc.Width;
|
||||
const auto target = static_cast<MG_Pipe::MGPipeResourceTarget>(desc.Target);
|
||||
if (target != MG_Pipe::MGPipeResourceTarget::Tex1D &&
|
||||
target != MG_Pipe::MGPipeResourceTarget::Tex1DArray) {
|
||||
maxDimension = std::max(maxDimension, desc.Height);
|
||||
}
|
||||
if (target == MG_Pipe::MGPipeResourceTarget::Tex3D) {
|
||||
maxDimension = std::max(maxDimension, desc.Depth);
|
||||
}
|
||||
Uint requiredLevels = 1;
|
||||
while (maxDimension > 1) {
|
||||
maxDimension /= 2;
|
||||
++requiredLevels;
|
||||
}
|
||||
if (desc.Levels < requiredLevels) {
|
||||
MG_Pipe::MGPipeUnmigratedEmulation("generate-mipmap-storage");
|
||||
}
|
||||
return false; // No server-side shadow allocation was necessary.
|
||||
}
|
||||
#endif
|
||||
auto* mipmapTexture = dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(texture.get());
|
||||
MOBILEGL_ASSERT(mipmapTexture != nullptr, "GenerateMipmap requires mipmap texture storage.");
|
||||
Bool allocatedStorage = false;
|
||||
|
||||
@@ -2159,7 +2159,7 @@ endif()
|
||||
# f1: split-only source keeps the monolith registry unchanged.
|
||||
if (MOBILEGL_BUILD_DISAGGREGATED)
|
||||
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/F1WireScenario.cpp)
|
||||
foreach(f1Slot ClearBufferfi ClearBufferfv ClearBufferiv ClearBufferuiv ClearNamedFramebufferfi ClearNamedFramebufferfv ClearNamedFramebufferiv ClearNamedFramebufferuiv CopyTexImage2D CopyTexSubImage2D GenerateMipmap)
|
||||
foreach(f1Slot ClearBufferfi ClearBufferfv ClearBufferiv ClearBufferuiv ClearNamedFramebufferfi ClearNamedFramebufferfv ClearNamedFramebufferiv ClearNamedFramebufferuiv CopyTexImage2D CopyTexSubImage2D GenerateMipmap GenerateMipmapPackedFloat GenerateMipmapDepth)
|
||||
gtest_discover_tests(MobileGLIntegrationTest
|
||||
TEST_PREFIX "DirectGLES.Split.F1."
|
||||
TEST_FILTER "F1WireScenario.${f1Slot}Pixels"
|
||||
|
||||
@@ -219,6 +219,46 @@ TEST_F(F1WireScenario, GenerateMipmapPixels) {
|
||||
const int expected[4] = {64, 128, 191, 255};
|
||||
for (int i = 0; i < 4; ++i) EXPECT_NEAR(pixel[i], expected[i], 1) << "F1.GenerateMipmap.pixels";
|
||||
}
|
||||
TEST_F(F1WireScenario, GenerateMipmapPackedFloatPixels) {
|
||||
if (!Ready()) return;
|
||||
// Only level zero exists initially. Generating the special-format chain must use the
|
||||
// shape published by the client, and level two must contain the generated GPU pixels.
|
||||
std::array<GLfloat, 8 * 8 * 3> source{};
|
||||
for (size_t i = 0; i < source.size(); i += 3) {
|
||||
source[i] = 0.25f; source[i + 1] = 0.5f; source[i + 2] = 0.75f;
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R11F_G11F_B10F, 8, 8, 0, GL_RGB, GL_FLOAT, source.data());
|
||||
const auto before = PeekSplitRuntime().emitSeq;
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
ASSERT_GT(PeekSplitRuntime().emitSeq, before);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 2);
|
||||
ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum(GL_FRAMEBUFFER_COMPLETE));
|
||||
GLfloat pixel[4]{};
|
||||
glReadPixels(1, 1, 1, 1, GL_RGBA, GL_FLOAT, pixel);
|
||||
ASSERT_EQ(FirstGLError(), GLenum(GL_NO_ERROR));
|
||||
const GLfloat expected[4] = {0.25f, 0.5f, 0.75f, 1.0f};
|
||||
for (int i = 0; i < 4; ++i) EXPECT_NEAR(pixel[i], expected[i], 0.01f);
|
||||
}
|
||||
|
||||
TEST_F(F1WireScenario, GenerateMipmapDepthPixels) {
|
||||
if (!Ready()) return;
|
||||
std::array<GLfloat, 8 * 8> source{};
|
||||
source.fill(0.375f);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, 8, 8, 0,
|
||||
GL_DEPTH_COMPONENT, GL_FLOAT, source.data());
|
||||
const auto before = PeekSplitRuntime().emitSeq;
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
ASSERT_GT(PeekSplitRuntime().emitSeq, before);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture, 2);
|
||||
glDrawBuffer(GL_NONE);
|
||||
glReadBuffer(GL_NONE);
|
||||
ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum(GL_FRAMEBUFFER_COMPLETE));
|
||||
GLfloat pixel = 0;
|
||||
glReadPixels(1, 1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pixel);
|
||||
ASSERT_EQ(FirstGLError(), GLenum(GL_NO_ERROR));
|
||||
EXPECT_NEAR(pixel, 0.375f, 0.00001f);
|
||||
}
|
||||
|
||||
TEST_F(F1WireScenario, NamedBlitPreservesBindingsAndRestoresNextVerbsPixels) {
|
||||
if (!Ready()) return;
|
||||
Attach(GL_RGBA8);
|
||||
|
||||
Reference in New Issue
Block a user