[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
+1 -1
View File
@@ -58,7 +58,7 @@ namespace MobileGL::MG_ConfigLoader {
inline void InitBackendType() {
String backendTypeStr;
QueryEnvVariable("MOBILEGL_BACKEND_TYPE", backendTypeStr, "DirectGLES");
QueryEnvVariable("MOBILEGL_BACKEND_TYPE", backendTypeStr, "DirectVulkan");
#define ENTRY(backendType) \
if (backendTypeStr == #backendType) { \
MG_Config::ActiveBackendType = BackendType::backendType; \
+19 -334
View File
@@ -17,165 +17,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsBaseVertex called with null GL context");
if (count < 0) {
MGLOG_W("DrawElementsBaseVertex skipped: count (%d) must be non-negative", count);
return;
}
if (count == 0) {
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("DrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("DrawElementsBaseVertex skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("DrawElementsBaseVertex skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("DrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("DrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const SizeT byteOffset = reinterpret_cast<SizeT>(indices);
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
MGLOG_W("DrawElementsBaseVertex skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)",
byteOffset, requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count;
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
payload.indexType = type;
payload.indexByteOffset = byteOffset;
payload.baseVertex = basevertex;
pVulkanRenderer->DrawElements(payload);
}
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsBaseVertex called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context");
GLsizei drawcount, const GLint* basevertex) {}
if (drawcount < 0) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: drawcount (%d) must be non-negative", drawcount);
return;
}
if (drawcount == 0) {
return;
}
if (!count || !indices || !basevertex) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: count/indices/basevertex pointer is null");
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("MultiDrawElementsBaseVertex skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
Vector<DrawElementPayload> payloads;
payloads.reserve(static_cast<SizeT>(drawcount));
for (GLsizei i = 0; i < drawcount; ++i) {
if (count[i] < 0) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: count[%d] (%d) must be non-negative", i, count[i]);
return;
}
if (count[i] == 0) {
continue;
}
const SizeT byteOffset = reinterpret_cast<SizeT>(indices[i]);
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
MGLOG_W("MultiDrawElementsBaseVertex skipped: draw[%d] index range out of bounds (offset=%zu, "
"size=%zu, buffer=%zu)",
i, byteOffset, requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count[i];
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
payload.indexType = type;
payload.indexByteOffset = byteOffset;
payload.baseVertex = basevertex[i];
payloads.push_back(payload);
}
if (payloads.empty()) {
return;
}
pVulkanRenderer->MultiDrawElements(payloads);
}
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {}
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
@@ -206,181 +52,44 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
if (drawcount < 0) {
MGLOG_W("MultiDrawElements skipped: drawcount (%d) must be non-negative", drawcount);
return;
}
if (drawcount == 0) {
return;
}
if (!count || !indices) {
MGLOG_W("MultiDrawElements skipped: count/indices pointer is null");
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("MultiDrawElements skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("MultiDrawElements skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("MultiDrawElements skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("MultiDrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("MultiDrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
Vector<DrawElementPayload> payloads;
payloads.reserve(static_cast<SizeT>(drawcount));
Vector<DrawElementCmd> cmds;
cmds.reserve(static_cast<SizeT>(drawcount));
for (GLsizei i = 0; i < drawcount; ++i) {
if (count[i] < 0) {
MGLOG_W("MultiDrawElements skipped: count[%d] (%d) must be non-negative", i, count[i]);
return;
}
if (count[i] == 0) {
continue;
}
const auto byteOffset = reinterpret_cast<SizeT>(indices[i]);
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
MGLOG_W("MultiDrawElements skipped: draw[%d] index range out of bounds (offset=%zu, size=%zu, "
"buffer=%zu)",
i, byteOffset, requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count[i];
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
DrawElementCmd payload{};
payload.mode = mode;
payload.first = 0;
payload.count = count[i];
payload.indexType = type;
payload.indexByteOffset = byteOffset;
payloads.push_back(payload);
payload.indexByteOffset = reinterpret_cast<SizeT>(indices[i]);
cmds.push_back(payload);
}
if (payloads.empty()) {
if (cmds.empty()) {
return;
}
pVulkanRenderer->MultiDrawElements(payloads);
pVulkanRenderer->MultiDrawElements(cmds);
}
void Clear(GLbitfield mask) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context");
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
const auto drawFbo = drawFboSlot.GetBoundObject();
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
const Bool isDefaultFboTarget = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
Uint drawFboExternalIndex = 0;
if (drawFbo) {
drawFboExternalIndex = drawFbo->GetExternalIndex();
} else if (defaultFbo) {
drawFboExternalIndex = defaultFbo->GetExternalIndex();
}
const auto& clearColor = MG_State::pGLContext->GetClearColor();
const auto clearDepth = MG_State::pGLContext->GetClearDepth();
const auto clearStencil = static_cast<Uint32>(MG_State::pGLContext->GetClearStencil());
pVulkanRenderer->QueueClearRequest(mask, clearColor, clearDepth, clearStencil,
drawFboExternalIndex,
isDefaultFboTarget);
pVulkanRenderer->Clear(mask);
}
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context");
if (count < 0) {
MGLOG_W("DrawElements skipped: count (%d) must be non-negative", count);
return;
}
if (count == 0) {
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("DrawElements skipped: primitive mode %u is not supported yet", mode);
return;
}
SizeT indexSize = 0;
switch (type) {
case GL_UNSIGNED_SHORT:
indexSize = sizeof(Uint16);
break;
case GL_UNSIGNED_INT:
indexSize = sizeof(Uint32);
break;
default:
MGLOG_W("DrawElements skipped: index type %u is not supported yet", type);
return;
}
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MGLOG_W("DrawElements skipped: no bound VAO");
return;
}
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
if (!indexBuffer) {
MGLOG_W("DrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
return;
}
const auto indexData = indexBuffer->GetDataReadOnly();
if (!indexData || indexData->empty()) {
MGLOG_W("DrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
return;
}
const auto byteOffset = reinterpret_cast<SizeT>(indices);
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
MGLOG_W("DrawElements skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)", byteOffset,
requiredBytes, indexBuffer->GetSize());
return;
}
DrawElementPayload payload{};
payload.drawArray.mode = mode;
payload.drawArray.first = 0;
payload.drawArray.count = count;
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
payload.drawArray.vertexArray = vao.get();
DrawElementCmd payload{};
payload.mode = mode;
payload.first = 0;
payload.count = count;
payload.indexType = type;
payload.indexByteOffset = byteOffset;
payload.indexByteOffset = reinterpret_cast<SizeT>(indices);
pVulkanRenderer->DrawElements(payload);
}
@@ -389,34 +98,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context");
if (first < 0) {
MGLOG_W("DrawArrays skipped: first (%d) must be non-negative", first);
return;
}
if (count < 0) {
MGLOG_W("DrawArrays skipped: count (%d) must be non-negative", count);
return;
}
if (count == 0) {
return;
}
if (mode != GL_TRIANGLES) {
MGLOG_W("DrawArrays skipped: primitive mode %u is not supported yet", mode);
return;
}
DrawArrayPayload payload{};
DrawArrayCmd payload{};
payload.mode = mode;
payload.first = first;
payload.count = count;
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
payload.program = currentProgram ? currentProgram.get() : nullptr;
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
payload.vertexArray = vao ? vao.get() : nullptr;
pVulkanRenderer->DrawArrays(payload);
}
@@ -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();