[Fix] (MG_Backend/DirectVulkan): Properly handle front face state. save VkDevice as static member

This commit is contained in:
2026-03-04 15:08:23 +08:00
parent 592a69b1c4
commit 09f96e5ba5
6 changed files with 33 additions and 33 deletions
@@ -24,7 +24,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkRenderPass renderPass = VK_NULL_HANDLE; VkRenderPass renderPass = VK_NULL_HANDLE;
Uint32 subpass = 0; Uint32 subpass = 0;
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkCullModeFlags cullMode = VK_CULL_MODE_NONE; VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE; VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
Bool depthTestEnable = false; Bool depthTestEnable = false;
Bool depthWriteEnable = false; Bool depthWriteEnable = false;
@@ -364,7 +364,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
auto& entry = m_cache[hash]; auto& entry = m_cache[hash];
entry.device = m_device;
entry.hash = hash; entry.hash = hash;
auto& shaders = program.GetAttachedShaders(); auto& shaders = program.GetAttachedShaders();
auto& spirv = program.GetGeneratedSpirv(); auto& spirv = program.GetGeneratedSpirv();
@@ -26,39 +26,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}; };
using CompileOptionFlags = Flags<CompileOptionBit>; using CompileOptionFlags = Flags<CompileOptionBit>;
using HashType = Uint64; using HashType = Uint64;
struct BackendProgramObject { struct VkProgramObject {
HashType hash = 0; HashType hash = 0;
VkDevice device = VK_NULL_HANDLE;
Vector<VkPipelineShaderStageCreateInfo> stages; Vector<VkPipelineShaderStageCreateInfo> stages;
Vector<VkShaderModule> modules; Vector<VkShaderModule> modules;
static inline VkDevice s_device = VK_NULL_HANDLE;
BackendProgramObject() = default; VkProgramObject() = default;
BackendProgramObject(const BackendProgramObject&) = delete; VkProgramObject(const VkProgramObject&) = delete;
BackendProgramObject& operator=(const BackendProgramObject&) = delete; VkProgramObject& operator=(const VkProgramObject&) = delete;
BackendProgramObject(BackendProgramObject&& other) noexcept { VkProgramObject(VkProgramObject&& other) noexcept {
hash = other.hash; hash = other.hash;
device = other.device;
stages = std::move(other.stages); stages = std::move(other.stages);
modules = std::move(other.modules); modules = std::move(other.modules);
other.hash = 0; other.hash = 0;
other.device = VK_NULL_HANDLE;
} }
BackendProgramObject& operator=(BackendProgramObject&& other) noexcept { VkProgramObject& operator=(VkProgramObject&& other) noexcept {
if (this == &other) { if (this == &other) {
return *this; return *this;
} }
DestroyModules(); DestroyModules();
stages.clear(); stages.clear();
hash = other.hash; hash = other.hash;
device = other.device;
stages = std::move(other.stages); stages = std::move(other.stages);
modules = std::move(other.modules); modules = std::move(other.modules);
other.hash = 0; other.hash = 0;
other.device = VK_NULL_HANDLE;
return *this; return *this;
} }
~BackendProgramObject() { ~VkProgramObject() {
DestroyModules(); DestroyModules();
stages.clear(); stages.clear();
} }
@@ -66,8 +62,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
private: private:
void DestroyModules() { void DestroyModules() {
for (auto module : modules) { for (auto module : modules) {
if (module != VK_NULL_HANDLE && device != VK_NULL_HANDLE) { if (module != VK_NULL_HANDLE && s_device != VK_NULL_HANDLE) {
vkDestroyShaderModule(device, module, nullptr); vkDestroyShaderModule(s_device, module, nullptr);
} }
} }
modules.clear(); modules.clear();
@@ -75,7 +71,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}; };
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config) explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config)
: m_device(device), m_config(config) {} : m_device(device), m_config(config) {
VkProgramObject::s_device = device;
}
~ProgramFactory(); ~ProgramFactory();
ProgramFactory(const ProgramFactory&) = delete; ProgramFactory(const ProgramFactory&) = delete;
@@ -87,7 +85,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
private: private:
VkDevice m_device = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE;
UnorderedMap<HashType, BackendProgramObject> m_cache; UnorderedMap<HashType, VkProgramObject> m_cache;
const VulkanRendererConfig& m_config; const VulkanRendererConfig& m_config;
static inline XXH64_state_t* m_hashState = XXH64_createState(); static inline XXH64_state_t* m_hashState = XXH64_createState();
}; };
@@ -337,6 +337,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const MG_State::GLState::VertexArrayObject& vao, const MG_State::GLState::VertexArrayObject& vao,
const MG_State::GLState::FramebufferObject& drawFbo) { const MG_State::GLState::FramebufferObject& drawFbo) {
ProgramFactory::CompileOptionFlags transformFlags = GetShaderTransformFlags(m_swapchainObject.GetPreTransform()); ProgramFactory::CompileOptionFlags transformFlags = GetShaderTransformFlags(m_swapchainObject.GetPreTransform());
Bool invertClockwise = transformFlags & ProgramFactory::CompileOptionBit::PositionYFlip;
auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(program, transformFlags); auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(program, transformFlags);
if (stages.empty()) { if (stages.empty()) {
MGLOG_D("GetOrCreatePipeline skipped: program has no shader stages"); MGLOG_D("GetOrCreatePipeline skipped: program has no shader stages");
@@ -364,10 +365,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
.renderPass = renderPassEntry.renderPass, .renderPass = renderPassEntry.renderPass,
.subpass = 0, .subpass = 0,
.topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode), .topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode),
// .cullMode = cullFaceEnabled .cullMode = cullFaceEnabled
// ? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode()) ? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode(), invertClockwise)
// : VK_CULL_MODE_NONE, : VK_CULL_MODE_NONE,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_CLOCKWISE, .frontFace = VK_FRONT_FACE_CLOCKWISE,
.depthTestEnable = depthTestEnabled, .depthTestEnable = depthTestEnabled,
.depthWriteEnable = depthTestEnabled && MG_State::pGLContext->GetDepthMask(), .depthWriteEnable = depthTestEnabled && MG_State::pGLContext->GetDepthMask(),
@@ -389,17 +389,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void VulkanRenderer::SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects) { void VulkanRenderer::SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects) {
// Prepare render pass
const auto& drawFbo =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*drawFbo, m_imageIndexAcquired);
// Prepare pipeline
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
const auto& program = *MG_State::pGLContext->GetCurrentProgram();
auto pipeline = GetOrCreatePipeline(mode, program, vao, *drawFbo);
// Begin command recording if not yet // Begin command recording if not yet
if (!frame.isCommandRecording) { if (!frame.isCommandRecording) {
m_frameContext.BeginCommandRecording(); m_frameContext.BeginCommandRecording();
m_uniformDescriptorBinder->BeginFrame(m_frameContext.GetCurrentFrameIndex()); m_uniformDescriptorBinder->BeginFrame(m_frameContext.GetCurrentFrameIndex());
} }
const auto& drawFbo =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
// Begin render pass, and handle clear // Begin render pass, and handle clear
auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*drawFbo, m_imageIndexAcquired);
auto* activeRenderPass = VkRenderPassManager::GetActiveRenderPass(); auto* activeRenderPass = VkRenderPassManager::GetActiveRenderPass();
if (activeRenderPass && (activeRenderPass == &renderPassEntry || activeRenderPass->CompatibleWith(renderPassEntry))) { if (activeRenderPass && (activeRenderPass == &renderPassEntry || activeRenderPass->CompatibleWith(renderPassEntry))) {
@@ -413,9 +419,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(ok, "%s: BeginRenderPass failed", __func__); MOBILEGL_ASSERT(ok, "%s: BeginRenderPass failed", __func__);
} }
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
const auto& program = *MG_State::pGLContext->GetCurrentProgram();
auto pipeline = GetOrCreatePipeline(mode, program, vao, *drawFbo);
vkCmdBindPipeline(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindPipeline(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
m_uniformDescriptorBinder->BindProgramUniformBuffers(frame.commandBuffer, program, m_uniformDescriptorBinder->BindProgramUniformBuffers(frame.commandBuffer, program,
@@ -31,12 +31,12 @@ namespace MobileGL {
} }
} }
VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode v) { VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode v, Bool invertClockwise) {
switch (v) { switch (v) {
case CullFaceMode::Front: case CullFaceMode::Front:
return VK_CULL_MODE_FRONT_BIT; return invertClockwise ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_FRONT_BIT;
case CullFaceMode::Back: case CullFaceMode::Back:
return VK_CULL_MODE_BACK_BIT; return invertClockwise ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT;
case CullFaceMode::FrontAndBack: case CullFaceMode::FrontAndBack:
return VK_CULL_MODE_FRONT_AND_BACK; return VK_CULL_MODE_FRONT_AND_BACK;
case CullFaceMode::Unknown: case CullFaceMode::Unknown:
@@ -13,7 +13,7 @@
namespace MobileGL { namespace MobileGL {
namespace MG_Util { namespace MG_Util {
VkPrimitiveTopology ConvertPrimitiveModeToVkEnum(GLenum mode); VkPrimitiveTopology ConvertPrimitiveModeToVkEnum(GLenum mode);
VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode value); VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode value, Bool invertClockwise = false);
VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc value); VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc value);
VkBlendFactor ConvertBlendFactorToVkEnum(BlendFactor value); VkBlendFactor ConvertBlendFactorToVkEnum(BlendFactor value);
} // namespace MG_Util } // namespace MG_Util