mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Fix] (MG_Backend/DirectVulkan): refactor VkRenderPassManager and hook it up (this commit only compiles and does not work)
This commit is contained in:
@@ -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; \
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user