[Fix] (MG_Backend/DirectVulkan): support Voxy rendering

Implemented:

- Advertise Voxy-required DirectVulkan extensions without raising the reported OpenGL version.

- Add DirectVulkan compute, indirect draw count, DSA, readback, and buffer state paths needed by Voxy.

Fixed:

- Enable Vulkan shaderInt64 and drawIndirectFirstInstance so Voxy baseInstance-driven LOD draws address the correct section data.

- Fix DirectVulkan synchronization, framebuffer, texture readback, and shader interface handling used by Voxy and Minecraft screenshots.

Tests:

- Add MG_Test coverage for DirectVulkan extension advertising, DSA buffer/texture/framebuffer/vertex-array behavior, persistent mapped readback, and shader/program paths.
This commit is contained in:
2026-06-09 00:37:37 +08:00
parent ab9db43599
commit cf165c0db5
65 changed files with 3724 additions and 239 deletions
+109 -4
View File
@@ -14,6 +14,13 @@
#include <string>
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
#include <MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h>
#include <MG_Backend/BackendObjects.h>
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
#include <MG_Impl/GLImpl/RenderState/GL_RenderState.h>
#include <MG_State/GLState/Core.h>
#include <MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h>
#include <MG_Backend/DirectVulkan/Renderer/VkTextureManager.h>
#include <MG_Util/Debug/Log.h>
namespace {
@@ -48,6 +55,102 @@ TEST(DirectGLESSanity, AdvertisesDepthTextureForGlmarkShadowScenes) {
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_depth_texture), extensions.end());
}
TEST(DirectVulkanSanity, AdvertisesTextureStorageForDirectStateAccess) {
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
const auto& extensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_direct_state_access),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage), extensions.end());
}
TEST(DirectVulkanSanity, AdvertisesVoxyRequiredRenderingExtensionsWithoutRaisingGLVersion) {
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
const auto& rendererInfo = backend.GetRendererInfo().RendererGLInfo;
const auto& extensions = rendererInfo.Extensions;
EXPECT_EQ(rendererInfo.TargetGLVersion.Major, 3);
EXPECT_EQ(rendererInfo.TargetGLVersion.Minor, 3);
EXPECT_EQ(rendererInfo.TargetGLVersion.Patch, 0);
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_compute_shader),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_storage_buffer_object),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_multi_draw_indirect),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_indirect_parameters),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_draw_parameters),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_gpu_shader_int64),
extensions.end());
}
TEST(DirectVulkanSanity, UndefinedDepthStencilLayoutUsesDontCareForUnclearedAspects) {
using namespace MobileGL;
using namespace MobileGL::MG_Backend::DirectVulkan;
auto noClear = ResolveDepthStencilAttachmentLoadInfo(VK_IMAGE_LAYOUT_UNDEFINED, false, false);
EXPECT_EQ(noClear.depthLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
EXPECT_EQ(noClear.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
EXPECT_EQ(noClear.initialLayout, VK_IMAGE_LAYOUT_UNDEFINED);
auto depthOnlyClear = ResolveDepthStencilAttachmentLoadInfo(VK_IMAGE_LAYOUT_UNDEFINED, true, false);
EXPECT_EQ(depthOnlyClear.depthLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
EXPECT_EQ(depthOnlyClear.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
EXPECT_EQ(depthOnlyClear.initialLayout, VK_IMAGE_LAYOUT_UNDEFINED);
auto knownLayout = ResolveDepthStencilAttachmentLoadInfo(
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, false);
EXPECT_EQ(knownLayout.depthLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
EXPECT_EQ(knownLayout.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
EXPECT_EQ(knownLayout.initialLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
TEST(DirectVulkanSanity, SampledDepthStencilViewUsesSingleDepthAspect) {
using namespace MobileGL::MG_Backend::DirectVulkan;
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_COLOR_BIT),
VK_IMAGE_ASPECT_COLOR_BIT);
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT),
VK_IMAGE_ASPECT_DEPTH_BIT);
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_STENCIL_BIT),
VK_IMAGE_ASPECT_STENCIL_BIT);
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT),
VK_IMAGE_ASPECT_DEPTH_BIT);
}
TEST(RenderStateSanity, ProvokingVertexUpdatesStateAndValidatesEnum) {
using namespace MobileGL;
MG_State::pGLContext = MakeUnique<MG_State::GLState::GLContext>();
MG_Backend::pActiveBackendObject = MakeUnique<MG_Backend::DirectGLES::BackendObject_DirectGLES>();
GLint mode = 0;
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
EXPECT_EQ(mode, GL_LAST_VERTEX_CONVENTION);
const Uint initialVersion = MG_State::pGLContext->GetRenderStateParametersVersion();
MG_Impl::GLImpl::ProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
EXPECT_EQ(mode, GL_FIRST_VERTEX_CONVENTION);
EXPECT_GT(MG_State::pGLContext->GetRenderStateParametersVersion(), initialVersion);
const Uint updatedVersion = MG_State::pGLContext->GetRenderStateParametersVersion();
MG_Impl::GLImpl::ProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
EXPECT_EQ(MG_State::pGLContext->GetRenderStateParametersVersion(), updatedVersion);
MG_Impl::GLImpl::ProvokingVertex(GL_TRIANGLES);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_ENUM);
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
EXPECT_EQ(mode, GL_FIRST_VERTEX_CONVENTION);
MG_Backend::pActiveBackendObject.reset();
MG_State::pGLContext.reset();
}
TEST(LogSanity, UsesEnvOverrideForFilePath) {
namespace fs = std::filesystem;
@@ -62,11 +165,13 @@ TEST(LogSanity, UsesEnvOverrideForFilePath) {
MobileGL::MG_Util::Debug::Close();
UnsetEnvVar("MOBILEGL_LOG_FILE_PATH");
std::ifstream logFile(logPath);
ASSERT_TRUE(logFile.good());
{
std::ifstream logFile(logPath);
ASSERT_TRUE(logFile.good());
const std::string contents((std::istreambuf_iterator<char>(logFile)), std::istreambuf_iterator<char>());
EXPECT_NE(contents.find(message), std::string::npos);
const std::string contents((std::istreambuf_iterator<char>(logFile)), std::istreambuf_iterator<char>());
EXPECT_NE(contents.find(message), std::string::npos);
}
fs::remove(logPath);
}