[Fix] (MG_Backend/DirectVulkan): refactor VkRenderPassManager and hook it up (this commit only compiles and does not work)

This commit is contained in:
2026-03-01 18:17:34 +08:00
parent e234d471fe
commit f61f068e28
12 changed files with 305 additions and 1318 deletions
@@ -475,11 +475,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (!samplerToUse) {
return false;
}
if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, outImageInfo)) {
VkTextureManager::TextureResource resource;
if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, resource)) {
return false;
}
outImageInfo.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse);
outImageInfo = {
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse),
.imageView = resource.view,
.imageLayout = resource.layout,
};
return outImageInfo.sampler != VK_NULL_HANDLE;
}
@@ -678,27 +682,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return true;
}
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout,
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program,
Uint32 frameIndex) {
if (m_frames.empty()) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: binder is not initialized");
return false;
}
if (frameIndex >= m_frames.size()) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: invalid frame index %u", frameIndex);
return false;
}
ProgramLayout* layout = GetOrCreateProgramLayout(program);
if (!layout || layout->pipelineLayout == VK_NULL_HANDLE || layout->descriptorSetLayout == VK_NULL_HANDLE) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: cannot get program layout");
return false;
}
if (layout->pipelineLayout != pipelineLayout) {
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: pipelineLayout mismatch");
return false;
}
auto& frame = m_frames[frameIndex];
if (frame.descriptorPools.empty()) {
@@ -837,7 +824,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
}
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet,
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout->pipelineLayout, 0, 1, &descriptorSet,
static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
return true;
}
@@ -36,7 +36,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void BeginFrame(Uint32 frameIndex);
VkPipelineLayout GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program);
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout,
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex);
private:
@@ -81,6 +81,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
SizeT VkClearManager::CollectGarbage() {
m_gcCounter++;
if (m_gcCounter != 0) {
return 0;
}
SizeT count = 0;
for (const auto& [raw, weak]: m_aliveObjects) {
if (weak.expired()) {
@@ -45,6 +45,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
SizeT CollectGarbage();
private:
Uint8 m_gcCounter = 0;
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
};
@@ -94,9 +94,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Int width = 0;
Int height = 0;
Vector<VkAttachmentDescription> colorAttachmentDescriptions(validDrawBufCount);
Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
Vector<VkDescriptorImageInfo> descriptorImageInfo(validDrawBufCount);
Vector<VkTextureManager::TextureResource> textureResources(validDrawBufCount);
// This should automatically work on default & offscreen FBO
// assuming default FBO has the right param
for (Int i = 0; i < validDrawBufCount; ++i) {
@@ -110,7 +110,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const auto textureTarget = texture->GetTarget();
// Color attachment description
VkAttachmentDescription& desc = colorAttachmentDescriptions[i];
VkAttachmentDescription& desc = attachmentDescriptions[i];
switch (textureTarget) {
case TextureTarget::Texture2D: {
auto* texture2d =
@@ -135,8 +135,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (height == 0)
height = texture2d->GetBaseSize().y();
Bool ok = m_textureManager.SyncTextureAndGetDescriptor(*texture, descriptorImageInfo[i]);
MOBILEGL_ASSERT(ok, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed");
Bool ok = m_textureManager.SyncTextureAndGetDescriptor(*texture, textureResources[i]);
MOBILEGL_ASSERT(ok, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
break;
}
@@ -153,9 +153,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// Depth attachment description
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
VkAttachmentDescription depthAttachmentDescription;
if (depthAtt.IsComplete()) {
VkTextureManager::TextureResource depthTextureResource;
if (depthAtt.IsComplete() && depthAtt.IsTexture()) {
auto& texture = *depthAtt.GetTexture();
depthAttachmentDescription.format =
MG_Util::ConvertTextureInternalFormatToVkEnum(depthAtt.GetTexture()->GetFormat());
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@@ -165,6 +167,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
depthAttachmentDescription.finalLayout = isDefaultFbo ?
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
Bool ok = m_textureManager.SyncTextureAndGetDescriptor(texture, depthTextureResource);
MOBILEGL_ASSERT(ok, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
attachmentDescriptions.emplace_back(depthAttachmentDescription);
}
// Depth attachment ref
@@ -190,8 +195,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCreateInfo.pNext = VK_NULL_HANDLE;
renderPassCreateInfo.flags = 0;
renderPassCreateInfo.attachmentCount = colorAttachmentDescriptions.size();
renderPassCreateInfo.pAttachments = colorAttachmentDescriptions.data();
renderPassCreateInfo.attachmentCount = attachmentDescriptions.size();
renderPassCreateInfo.pAttachments = attachmentDescriptions.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpassDesc;
renderPassCreateInfo.dependencyCount = 0;
@@ -200,9 +205,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkRenderPass renderPass = VK_NULL_HANDLE;
VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass));
Vector<VkImageView> attachmentViews(descriptorImageInfo.size(), VK_NULL_HANDLE);
for (Int i = 0; i < descriptorImageInfo.size(); i++) {
attachmentViews[i] = descriptorImageInfo[i].imageView;
Vector<VkImageView> attachmentViews(textureResources.size(), VK_NULL_HANDLE);
for (Int i = 0; i < textureResources.size(); i++) {
attachmentViews[i] = textureResources[i].view;
}
// Framebuffer
@@ -219,23 +224,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkFramebuffer framebuffer = VK_NULL_HANDLE;
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
IntVec2 extent = {width, height};
m_renderPasses[hash] = { renderPass, framebuffer, Move(descriptorImageInfo), extent };
m_renderPasses[hash] = { renderPass, framebuffer, Move(textureResources), extent, 1 };
return m_renderPasses[hash];
}
Bool VkRenderPassManager::StartRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
if (m_activeRenderPass != nullptr)
return false;
Bool VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
// TODO: Transition all the attachments into proper layout before starting the render pass
m_activeRenderPass = &renderPassEntry;
VkRenderPassBeginInfo renderPassBeginInfo;
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderPass = m_activeRenderPass->renderPass;
renderPassBeginInfo.framebuffer = m_activeRenderPass->framebuffer;
renderPassBeginInfo.renderPass = renderPassEntry.renderPass;
renderPassBeginInfo.framebuffer = renderPassEntry.framebuffer;
renderPassBeginInfo.renderArea.offset = { 0, 0 };
renderPassBeginInfo.renderArea.extent = {
(Uint32)m_activeRenderPass->extent.x(), (Uint32)m_activeRenderPass->extent.y() };
(Uint32)renderPassEntry.extent.x(), (Uint32)renderPassEntry.extent.y() };
// TODO: should query proper clear color
VkClearValue clearValue;
@@ -251,8 +255,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
if (m_activeRenderPass == nullptr)
return false;
vkCmdEndRenderPass(commandBuffer);
return true;
}
@@ -21,8 +21,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
static inline VkDevice s_device;
VkRenderPass renderPass = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
Vector<VkDescriptorImageInfo> descriptorImageInfo;
Vector<VkTextureManager::TextureResource> textureResources;
IntVec2 extent = {0, 0};
Uint32 subpass = 0;
~RenderPassEntry() {
if (renderPass != VK_NULL_HANDLE) {
@@ -46,16 +47,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
HashType ComputeHash(const MG_State::GLState::FramebufferObject& fbo) const;
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo);
RenderPassEntry* GetActiveRenderPass() const { return m_activeRenderPass; }
Bool StartRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
Bool EndRenderPass(VkCommandBuffer commandBuffer);
static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
static Bool EndRenderPass(VkCommandBuffer commandBuffer);
private:
VkDevice m_device = VK_NULL_HANDLE;
const VulkanRendererConfig& m_config;
VkClearManager& m_clearManager;
VkTextureManager& m_textureManager;
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
RenderPassEntry* m_activeRenderPass = nullptr;
static inline XXH64_state_t* m_hashState = XXH64_createState();
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -41,7 +41,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
Bool VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture,
VkDescriptorImageInfo& outImageInfo) {
TextureResource& outTextureResource) {
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "SyncTextureAndGetDescriptor: m_device == VK_NULL_HANDLE");
auto it = m_textureResources.find(texture.GetExternalIndex());
@@ -56,15 +56,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false;
}
if (it->second.view == VK_NULL_HANDLE) {
return false;
}
outTextureResource = it->second;
outImageInfo.sampler = VK_NULL_HANDLE;
outImageInfo.imageView = it->second.view;
// Will be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
// Shouldn't hardcode VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL here
// outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
return true;
}
Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
@@ -28,17 +28,6 @@ public:
VkQueue graphicsQueue = VK_NULL_HANDLE;
};
Bool Initialize(const InitInfo& initInfo);
void Shutdown();
Bool SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture, VkDescriptorImageInfo& outImageInfo);
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
private:
struct TextureResource {
VkImage image = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr;
@@ -50,6 +39,19 @@ private:
Uint textureExternalIndex = 0;
};
Bool Initialize(const InitInfo& initInfo);
void Shutdown();
Bool SyncTextureAndGetDescriptor(
MG_State::GLState::ITextureObject& texture, TextureResource& outTextureResource);
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
private:
Bool SyncTexture(MG_State::GLState::ITextureObject &texture,
TextureResource &outResource);
Bool SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
File diff suppressed because it is too large Load Diff
@@ -32,16 +32,23 @@ namespace MobileGL::MG_State::GLState {
} // namespace MobileGL::MG_State::GLState
namespace MobileGL::MG_Backend::DirectVulkan {
struct DrawArrayPayload {
enum class DrawSetupAspect: Uint8 {
FramebufferObject = 1 << 0,
VertexArrayObject = 1 << 1,
UniformBuffer = 1 << 2,
VertexBuffer = 1 << 3,
IndexBuffer = 1 << 4,
Viewport = 1 << 5,
Scissor = 1 << 6,
};
struct DrawArrayCmd {
GLenum mode = GL_TRIANGLES;
GLint first = 0;
GLsizei count = 0;
const MG_State::GLState::ProgramObject* program = nullptr;
const MG_State::GLState::VertexArrayObject* vertexArray = nullptr;
};
struct DrawElementPayload {
DrawArrayPayload drawArray;
struct DrawElementCmd: public DrawArrayCmd {
GLenum indexType = GL_UNSIGNED_SHORT;
SizeT indexByteOffset = 0;
GLint baseVertex = 0;
@@ -70,13 +77,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void Initialize();
void Shutdown();
void QueueClearRequest(GLbitfield mask, const FloatVec4& color, Float depth, Uint32 stencil,
Uint drawFboExternalIndex, Bool isDefaultFramebufferTarget);
Bool ConsumePendingColorClear(VkClearColorValue& outClearColor);
void EnsureFrameRecordingStarted();
void DrawArrays(const DrawArrayPayload& payload);
void DrawElements(const DrawElementPayload& payload);
void MultiDrawElements(const Vector<DrawElementPayload>& payloads);
void SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects);
void Clear(GLbitfield mask);
void DrawArrays(const DrawArrayCmd& payload);
void DrawElements(const DrawElementCmd& payload);
void MultiDrawElements(const Vector<DrawElementCmd>& payloads);
void Present();
const PhysicalDevice& GetPhysicalDevice() const;
@@ -85,15 +91,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void RecreateSwapchain();
private:
struct PendingClearState {
GLbitfield mask = 0;
VkClearColorValue color = {{0.0f, 0.0f, 0.0f, 1.0f}};
Float depth = 1.0f;
Uint32 stencil = 0;
Uint drawFboExternalIndex = 0;
Bool targetsDefaultFramebuffer = true;
};
NativeWindowType m_window = 0;
VulkanRendererConfig m_config;
@@ -123,6 +120,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkCommandPool m_commandPool = VK_NULL_HANDLE;
RenderPassEntry* m_activeRenderPass = nullptr;
Vector<VkBufferObject> m_frameVertexUploadBuffers;
Vector<VkDeviceSize> m_frameVertexUploadHeads;
Vector<VkBufferObject> m_frameIndexUploadBuffers;
@@ -131,13 +130,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uint m_imageIndexAcquired = 0;
FrameContext m_frameContext;
UnorderedMap<Uint64, PendingClearState> m_pendingClears;
Bool m_isMainRenderPassActive = false;
VkRenderPass m_activeRenderPass = VK_NULL_HANDLE;
VkExtent2D m_activeRenderExtent = {0, 0};
VkFormat m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
Bool m_activeRenderTargetIsDefault = true;
Uint m_activeDrawFboExternalIndex = 0;
UniquePtr<PipelineFactory> m_pipelineFactory;
UniquePtr<ProgramFactory> m_programFactory;
@@ -160,9 +152,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void CreateSwapchain();
void CreateCommandPool();
void CreateFrameContexts();
VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout,
Uint64 vertexInputHash,
const VkPipelineVertexInputStateCreateInfo& vertexInputState);
VkPipeline GetOrCreatePipeline(
GLenum mode,
const MG_State::GLState::ProgramObject& program,
const MG_State::GLState::VertexArrayObject& vao,
const MG_State::GLState::FramebufferObject& drawFbo);
void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
void EndFrameRecordingIfNeeded();
@@ -170,9 +166,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void CollectDeferredBufferReleases(Uint32 frameIndex);
Bool EnsureFrameUploadBufferCapacity(Uint32 frameIndex, Bool isIndexBuffer, VkDeviceSize requiredEndOffset,
VkDeviceSize minCapacity, VkBufferUsageFlags usage);
Bool UploadAndBindVertexStreams(const VertexInputStateFactory::BackendVertexInputState& vertexInputState,
const DrawArrayPayload& payload, VkCommandBuffer commandBuffer);
void ApplyPendingClearsForActiveTarget(VkCommandBuffer commandBuffer, Uint64 drawTargetKey);
Bool UploadAndBindVertexStreams(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao);
void ShutdownSwapchain();