mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat|Fix] (MG_Backend/DirectVulkan): Impl (Multi)DrawElementsBaseVertex. Fix Blitframebuffer.
This commit is contained in:
@@ -17,10 +17,165 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
|
||||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
|
||||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
|
||||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
|
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 MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||||
GLsizei drawcount, const GLint* basevertex) {}
|
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");
|
||||||
|
|
||||||
|
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 MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||||
void MultiDrawArraysIndirect(GLenum mode, 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,
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||||
@@ -270,20 +425,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
|
||||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
|
||||||
|
|
||||||
const auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
const auto& readFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||||
const auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||||
|
const auto readFbo = readFboSlot.GetBoundObject();
|
||||||
|
const auto drawFbo = drawFboSlot.GetBoundObject();
|
||||||
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
||||||
|
|
||||||
const Bool readIsDefault = (readFbo == defaultFbo) || (readFbo == nullptr && defaultFbo != nullptr);
|
const Bool readIsDefault = (readFbo == defaultFbo) || (readFbo == nullptr && defaultFbo != nullptr);
|
||||||
const Bool drawIsDefault = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
const Bool drawIsDefault = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
||||||
|
|
||||||
Uint readFboExternalIndex = 0;
|
Uint readFboExternalIndex = 0;
|
||||||
Uint drawFboExternalIndex = 0;
|
|
||||||
if (readFbo) {
|
if (readFbo) {
|
||||||
readFboExternalIndex = readFbo->GetExternalIndex();
|
readFboExternalIndex = readFbo->GetExternalIndex();
|
||||||
} else if (defaultFbo) {
|
} else if (defaultFbo) {
|
||||||
readFboExternalIndex = defaultFbo->GetExternalIndex();
|
readFboExternalIndex = defaultFbo->GetExternalIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uint drawFboExternalIndex = 0;
|
||||||
if (drawFbo) {
|
if (drawFbo) {
|
||||||
drawFboExternalIndex = drawFbo->GetExternalIndex();
|
drawFboExternalIndex = drawFbo->GetExternalIndex();
|
||||||
} else if (defaultFbo) {
|
} else if (defaultFbo) {
|
||||||
|
|||||||
@@ -53,13 +53,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto& target = it->second;
|
auto& target = it->second;
|
||||||
if (!TransitionImageLayout(commandBuffer,
|
if (!TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
target.image,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
|
||||||
target.layout,
|
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
0,
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT)) {
|
VK_IMAGE_ASPECT_COLOR_BIT)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -75,16 +70,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TransitionImageLayout(commandBuffer,
|
return TransitionImageLayout(
|
||||||
target.depthStencilImage,
|
commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||||
target.depthStencilLayout,
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0,
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, aspectMask);
|
||||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
|
||||||
0,
|
|
||||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
||||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
|
||||||
aspectMask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer,
|
Bool VkFramebufferManager::TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer,
|
||||||
@@ -96,37 +86,121 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto& target = it->second;
|
auto& target = it->second;
|
||||||
return TransitionImageLayout(commandBuffer,
|
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
target.image,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
target.layout,
|
VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
}
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
Bool VkFramebufferManager::TransitionOffscreenColorToTransferDst(VkCommandBuffer commandBuffer,
|
||||||
0,
|
Uint glFboExternalIndex) {
|
||||||
VK_ACCESS_TRANSFER_READ_BIT,
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
|
if (it == m_offscreenColorTargets.end()) {
|
||||||
|
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToTransferDst skipped: FBO %u not found",
|
||||||
|
glFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& target = it->second;
|
||||||
|
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkFramebufferManager::TransitionOffscreenColorToGeneral(VkCommandBuffer commandBuffer,
|
||||||
|
Uint glFboExternalIndex) {
|
||||||
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
|
if (it == m_offscreenColorTargets.end()) {
|
||||||
|
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToGeneral skipped: FBO %u not found",
|
||||||
|
glFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& target = it->second;
|
||||||
|
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToTransferSrc(VkCommandBuffer commandBuffer,
|
||||||
|
Uint glFboExternalIndex) {
|
||||||
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
|
if (it == m_offscreenColorTargets.end()) {
|
||||||
|
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToTransferSrc skipped: FBO %u not found",
|
||||||
|
glFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& target = it->second;
|
||||||
|
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||||
|
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||||
|
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT, aspectMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToTransferDst(VkCommandBuffer commandBuffer,
|
||||||
|
Uint glFboExternalIndex) {
|
||||||
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
|
if (it == m_offscreenColorTargets.end()) {
|
||||||
|
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToTransferDst skipped: FBO %u not found",
|
||||||
|
glFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& target = it->second;
|
||||||
|
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||||
|
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||||
|
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToGeneral(VkCommandBuffer commandBuffer,
|
||||||
|
Uint glFboExternalIndex) {
|
||||||
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
|
if (it == m_offscreenColorTargets.end()) {
|
||||||
|
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToGeneral skipped: FBO %u not found",
|
||||||
|
glFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& target = it->second;
|
||||||
|
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||||
|
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||||
|
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask);
|
||||||
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer,
|
Bool VkFramebufferManager::TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer,
|
||||||
Uint textureExternalIndex) {
|
Uint textureExternalIndex) {
|
||||||
for (auto& [_, target] : m_offscreenColorTargets) {
|
for (auto& [_, target] : m_offscreenColorTargets) {
|
||||||
if (target.colorTextureExternalIndex != textureExternalIndex || target.image == VK_NULL_HANDLE) {
|
if (target.colorTextureExternalIndex != textureExternalIndex || target.image == VK_NULL_HANDLE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const Bool fromUndefined = (target.layout == VK_IMAGE_LAYOUT_UNDEFINED);
|
const Bool fromUndefined = (target.layout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||||
return TransitionImageLayout(commandBuffer,
|
return TransitionImageLayout(
|
||||||
target.image,
|
commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
target.layout,
|
fromUndefined ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
: (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT),
|
||||||
fromUndefined ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
: (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
fromUndefined ? 0 : (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT),
|
VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
|
||||||
fromUndefined ? 0
|
|
||||||
: (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT),
|
|
||||||
VK_ACCESS_SHADER_READ_BIT,
|
|
||||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -142,7 +216,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const {
|
Bool VkFramebufferManager::GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage,
|
||||||
|
VkExtent2D& outExtent, VkFormat& outFormat) const {
|
||||||
|
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||||
|
if (it == m_offscreenColorTargets.end() || it->second.depthStencilImage == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
outImage = it->second.depthStencilImage;
|
||||||
|
outExtent = it->second.extent;
|
||||||
|
outFormat = it->second.depthStencilFormat;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool VkFramebufferManager::GetOffscreenColorViewByTexture(Uint textureExternalIndex,
|
||||||
|
VkImageView& outImageView) const {
|
||||||
for (const auto& [_, target] : m_offscreenColorTargets) {
|
for (const auto& [_, target] : m_offscreenColorTargets) {
|
||||||
if (target.colorTextureExternalIndex != textureExternalIndex || target.imageView == VK_NULL_HANDLE) {
|
if (target.colorTextureExternalIndex != textureExternalIndex || target.imageView == VK_NULL_HANDLE) {
|
||||||
continue;
|
continue;
|
||||||
@@ -170,8 +257,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
Bool VkFramebufferManager::RecreateOffscreenColorTarget(
|
Bool VkFramebufferManager::RecreateOffscreenColorTarget(
|
||||||
OffscreenColorTarget& target, const MG_State::GLState::FramebufferObject& glFbo,
|
OffscreenColorTarget& target, const MG_State::GLState::FramebufferObject& glFbo,
|
||||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment, Uint16 glObjectVersion) {
|
||||||
Uint16 glObjectVersion) {
|
|
||||||
DestroyOffscreenColorTarget(target);
|
DestroyOffscreenColorTarget(target);
|
||||||
|
|
||||||
const auto size = colorAttachment.GetSize();
|
const auto size = colorAttachment.GetSize();
|
||||||
@@ -198,7 +284,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &target.image), "vkCreateImage(offscreen color)");
|
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &target.image), "vkCreateImage(offscreen color)");
|
||||||
@@ -209,7 +295,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkMemoryAllocateInfo allocInfo{};
|
VkMemoryAllocateInfo allocInfo{};
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
allocInfo.allocationSize = memoryRequirements.size;
|
allocInfo.allocationSize = memoryRequirements.size;
|
||||||
allocInfo.memoryTypeIndex = FindMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
allocInfo.memoryTypeIndex =
|
||||||
|
FindMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &target.memory), "vkAllocateMemory(offscreen color)");
|
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &target.memory), "vkAllocateMemory(offscreen color)");
|
||||||
VK_VERIFY(vkBindImageMemory(m_device, target.image, target.memory, 0), "vkBindImageMemory(offscreen color)");
|
VK_VERIFY(vkBindImageMemory(m_device, target.image, target.memory, 0), "vkBindImageMemory(offscreen color)");
|
||||||
|
|
||||||
@@ -223,16 +310,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
viewInfo.subresourceRange.levelCount = 1;
|
viewInfo.subresourceRange.levelCount = 1;
|
||||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
viewInfo.subresourceRange.layerCount = 1;
|
viewInfo.subresourceRange.layerCount = 1;
|
||||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView), "vkCreateImageView(offscreen color)");
|
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView),
|
||||||
|
"vkCreateImageView(offscreen color)");
|
||||||
|
|
||||||
const auto& depthAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Depth);
|
const auto& depthAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||||
const auto& stencilAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
const auto& stencilAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||||
const Bool requestedDepthStencil =
|
const Bool requestedDepthStencil = (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) ||
|
||||||
(depthAttachment.IsValid() && !depthAttachment.IsEmpty()) ||
|
(stencilAttachment.IsValid() && !stencilAttachment.IsEmpty());
|
||||||
(stencilAttachment.IsValid() && !stencilAttachment.IsEmpty());
|
|
||||||
VkFormat depthStencilFormat = ResolveDepthStencilFormat(depthAttachment, stencilAttachment);
|
VkFormat depthStencilFormat = ResolveDepthStencilFormat(depthAttachment, stencilAttachment);
|
||||||
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
|
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
|
||||||
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT});
|
depthStencilFormat =
|
||||||
|
FindSupportedDepthStencilFormat({VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT});
|
||||||
} else if (depthStencilFormat == VK_FORMAT_D32_SFLOAT) {
|
} else if (depthStencilFormat == VK_FORMAT_D32_SFLOAT) {
|
||||||
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM});
|
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM});
|
||||||
}
|
}
|
||||||
@@ -272,7 +360,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
"vkBindImageMemory(offscreen depth/stencil)");
|
"vkBindImageMemory(offscreen depth/stencil)");
|
||||||
|
|
||||||
VkImageAspectFlags depthAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
VkImageAspectFlags depthAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT || depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||||
|
depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||||
depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
}
|
}
|
||||||
VkImageViewCreateInfo depthViewInfo{};
|
VkImageViewCreateInfo depthViewInfo{};
|
||||||
@@ -365,9 +454,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
target.depthStencilFormat = depthStencilFormat;
|
target.depthStencilFormat = depthStencilFormat;
|
||||||
target.glObjectVersion = glObjectVersion;
|
target.glObjectVersion = glObjectVersion;
|
||||||
target.colorTextureExternalIndex =
|
target.colorTextureExternalIndex = (colorAttachment.IsTexture() && colorAttachment.GetTexture())
|
||||||
(colorAttachment.IsTexture() && colorAttachment.GetTexture()) ? colorAttachment.GetTexture()->GetExternalIndex()
|
? colorAttachment.GetTexture()->GetExternalIndex()
|
||||||
: 0;
|
: 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,15 +502,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
target.colorTextureExternalIndex = 0;
|
target.colorTextureExternalIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkFramebufferManager::TransitionImageLayout(VkCommandBuffer commandBuffer,
|
Bool VkFramebufferManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
|
||||||
VkImage image,
|
VkImageLayout& trackedLayout, VkImageLayout newLayout,
|
||||||
VkImageLayout& trackedLayout,
|
|
||||||
VkImageLayout newLayout,
|
|
||||||
VkPipelineStageFlags srcStageMask,
|
VkPipelineStageFlags srcStageMask,
|
||||||
VkPipelineStageFlags dstStageMask,
|
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
||||||
VkAccessFlags srcAccessMask,
|
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask) {
|
||||||
VkAccessFlags dstAccessMask,
|
|
||||||
VkImageAspectFlags aspectMask) {
|
|
||||||
if (image == VK_NULL_HANDLE) {
|
if (image == VK_NULL_HANDLE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
|
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
|
||||||
Bool TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
Bool TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
Bool TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
Bool TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
|
Bool TransitionOffscreenColorToTransferDst(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
|
Bool TransitionOffscreenColorToGeneral(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
|
Bool TransitionOffscreenDepthStencilToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
|
Bool TransitionOffscreenDepthStencilToTransferDst(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
|
Bool TransitionOffscreenDepthStencilToGeneral(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||||
Bool TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer, Uint textureExternalIndex);
|
Bool TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer, Uint textureExternalIndex);
|
||||||
Bool GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent) const;
|
Bool GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent) const;
|
||||||
|
Bool GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent,
|
||||||
|
VkFormat& outFormat) const;
|
||||||
Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const;
|
Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const;
|
||||||
Bool GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
Bool GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass,
|
||||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
|
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||||
|
VkFormat& outDepthStencilFormat) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct OffscreenColorTarget {
|
struct OffscreenColorTarget {
|
||||||
@@ -59,19 +67,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
||||||
Uint16 glObjectVersion);
|
Uint16 glObjectVersion);
|
||||||
void DestroyOffscreenColorTarget(OffscreenColorTarget& target);
|
void DestroyOffscreenColorTarget(OffscreenColorTarget& target);
|
||||||
Bool TransitionImageLayout(VkCommandBuffer commandBuffer,
|
Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
|
||||||
VkImage image,
|
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
|
||||||
VkImageLayout& trackedLayout,
|
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
||||||
VkImageLayout newLayout,
|
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
|
||||||
VkPipelineStageFlags srcStageMask,
|
|
||||||
VkPipelineStageFlags dstStageMask,
|
|
||||||
VkAccessFlags srcAccessMask,
|
|
||||||
VkAccessFlags dstAccessMask,
|
|
||||||
VkImageAspectFlags aspectMask);
|
|
||||||
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
||||||
static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment);
|
static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment);
|
||||||
static VkFormat ResolveDepthStencilFormat(const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
static VkFormat ResolveDepthStencilFormat(
|
||||||
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment);
|
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
||||||
|
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment);
|
||||||
VkFormat FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const;
|
VkFormat FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const;
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
|||||||
@@ -998,7 +998,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
vkCmdBindIndexBuffer(commandBuffer, frameIndexUploadBuffer.GetHandle(), writeOffset, vkIndexType);
|
vkCmdBindIndexBuffer(commandBuffer, frameIndexUploadBuffer.GetHandle(), writeOffset, vkIndexType);
|
||||||
vkCmdDrawIndexed(commandBuffer, static_cast<Uint32>(payload.drawArray.count), 1, 0, 0, 0);
|
vkCmdDrawIndexed(commandBuffer, static_cast<Uint32>(payload.drawArray.count), 1, 0,
|
||||||
|
static_cast<Int32>(payload.baseVertex), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::MultiDrawElements(const Vector<DrawElementPayload>& payloads) {
|
void VulkanRenderer::MultiDrawElements(const Vector<DrawElementPayload>& payloads) {
|
||||||
@@ -1060,6 +1061,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
SizeT sourceOffset = 0;
|
SizeT sourceOffset = 0;
|
||||||
SizeT sourceByteCount = 0;
|
SizeT sourceByteCount = 0;
|
||||||
Uint32 firstIndex = 0;
|
Uint32 firstIndex = 0;
|
||||||
|
Int32 vertexOffset = 0;
|
||||||
};
|
};
|
||||||
Vector<PreparedDraw> preparedDraws;
|
Vector<PreparedDraw> preparedDraws;
|
||||||
preparedDraws.reserve(payloads.size());
|
preparedDraws.reserve(payloads.size());
|
||||||
@@ -1086,6 +1088,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
draw.sourceOffset = payload.indexByteOffset;
|
draw.sourceOffset = payload.indexByteOffset;
|
||||||
draw.sourceByteCount = drawByteCount;
|
draw.sourceByteCount = drawByteCount;
|
||||||
draw.firstIndex = firstIndex;
|
draw.firstIndex = firstIndex;
|
||||||
|
draw.vertexOffset = static_cast<Int32>(payload.baseVertex);
|
||||||
preparedDraws.push_back(draw);
|
preparedDraws.push_back(draw);
|
||||||
|
|
||||||
firstIndex += draw.indexCount;
|
firstIndex += draw.indexCount;
|
||||||
@@ -1189,7 +1192,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
indirectCommands[i].indexCount = preparedDraws[i].indexCount;
|
indirectCommands[i].indexCount = preparedDraws[i].indexCount;
|
||||||
indirectCommands[i].instanceCount = 1;
|
indirectCommands[i].instanceCount = 1;
|
||||||
indirectCommands[i].firstIndex = preparedDraws[i].firstIndex;
|
indirectCommands[i].firstIndex = preparedDraws[i].firstIndex;
|
||||||
indirectCommands[i].vertexOffset = 0;
|
indirectCommands[i].vertexOffset = preparedDraws[i].vertexOffset;
|
||||||
indirectCommands[i].firstInstance = 0;
|
indirectCommands[i].firstInstance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1226,26 +1229,33 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// Fallback
|
// Fallback
|
||||||
for (const auto& draw : preparedDraws) {
|
for (const auto& draw : preparedDraws) {
|
||||||
vkCmdDrawIndexed(commandBuffer, draw.indexCount, 1, draw.firstIndex, 0, 0);
|
vkCmdDrawIndexed(commandBuffer, draw.indexCount, 1, draw.firstIndex, draw.vertexOffset, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VulkanRenderer::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
Bool VulkanRenderer::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter,
|
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter,
|
||||||
Uint readFboExternalIndex, Uint drawFboExternalIndex,
|
Uint readFboExternalIndex, Uint drawFboExternalIndex,
|
||||||
|
|
||||||
Bool readIsDefaultFramebuffer, Bool drawIsDefaultFramebuffer) {
|
Bool readIsDefaultFramebuffer, Bool drawIsDefaultFramebuffer) {
|
||||||
if ((mask & GL_COLOR_BUFFER_BIT) == 0 || (mask & ~GL_COLOR_BUFFER_BIT) != 0) {
|
if ((mask & (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) == 0) {
|
||||||
MGLOG_D("BlitFramebuffer skipped: only GL_COLOR_BUFFER_BIT is supported in Vulkan backend for now");
|
MGLOG_D("BlitFramebuffer skipped: empty mask");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (readIsDefaultFramebuffer || !drawIsDefaultFramebuffer) {
|
|
||||||
MGLOG_D("BlitFramebuffer skipped: currently only read=offscreen FBO and draw=default FBO is supported");
|
VkFilter vkFilter = VK_FILTER_NEAREST;
|
||||||
|
if (filter == GL_NEAREST) {
|
||||||
|
vkFilter = VK_FILTER_NEAREST;
|
||||||
|
} else if (filter == GL_LINEAR) {
|
||||||
|
vkFilter = VK_FILTER_LINEAR;
|
||||||
|
} else {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: filter %u is not supported", filter);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& frame = m_frameContext.GetCurrent();
|
auto& frame = m_frameContext.GetCurrent();
|
||||||
if (frame.hasCommandBufferRecorded) {
|
if (frame.hasCommandBufferRecorded) {
|
||||||
MGLOG_D("BlitFramebuffer skipped: current frame command buffer is already finalized");
|
MGLOG_D("BlitFramebuffer skipped: current frame command buffer already finalized");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1270,89 +1280,544 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_activeDrawFboExternalIndex = 0;
|
m_activeDrawFboExternalIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_framebufferManager || !MG_State::pGLContext) {
|
if (!m_framebufferManager && (!readIsDefaultFramebuffer || !drawIsDefaultFramebuffer)) {
|
||||||
MGLOG_D("BlitFramebuffer skipped: framebuffer manager is unavailable");
|
MGLOG_W("BlitFramebuffer skipped: offscreen framebuffer manager not available");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)drawFboExternalIndex;
|
auto consumePendingClearForTarget = [&](Bool targetIsDefault, Uint targetFboExternalIndex) {
|
||||||
const auto readFbo = MG_State::pGLContext->GetFramebufferObject(readFboExternalIndex);
|
const Uint64 pendingKey = BuildPendingClearKey(targetFboExternalIndex, targetIsDefault);
|
||||||
if (!readFbo) {
|
auto pendingIt = m_pendingClears.find(pendingKey);
|
||||||
MGLOG_D("BlitFramebuffer skipped: read FBO %u not found", readFboExternalIndex);
|
if (pendingIt == m_pendingClears.end()) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if (!m_framebufferManager->EnsureOffscreenColorTarget(readFboExternalIndex, *readFbo)) {
|
|
||||||
return false;
|
const PendingClearState pending = pendingIt->second;
|
||||||
}
|
m_pendingClears.erase(pendingIt);
|
||||||
if (!m_framebufferManager->TransitionOffscreenColorToTransferSrc(commandBuffer, readFboExternalIndex)) {
|
|
||||||
return false;
|
const auto prevExtent = m_activeRenderExtent;
|
||||||
|
const auto prevDepthStencilFormat = m_activeDepthStencilFormat;
|
||||||
|
|
||||||
|
if (targetIsDefault) {
|
||||||
|
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
|
||||||
|
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
|
||||||
|
|
||||||
|
VkRenderPassBeginInfo renderPassInfo{};
|
||||||
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
renderPassInfo.renderPass = m_renderPassLoad;
|
||||||
|
renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired];
|
||||||
|
renderPassInfo.renderArea.offset = {0, 0};
|
||||||
|
renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent();
|
||||||
|
renderPassInfo.clearValueCount = 0;
|
||||||
|
renderPassInfo.pClearValues = nullptr;
|
||||||
|
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
m_activeRenderExtent = renderPassInfo.renderArea.extent;
|
||||||
|
m_activeDepthStencilFormat = m_depthStencilFormat;
|
||||||
|
|
||||||
|
if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
|
RecordColorClear(commandBuffer, pending.color);
|
||||||
|
}
|
||||||
|
if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
||||||
|
RecordDepthStencilClear(commandBuffer, pending.mask, pending.depth, pending.stencil);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
} else if (m_framebufferManager && MG_State::pGLContext) {
|
||||||
|
const auto targetFbo = MG_State::pGLContext->GetFramebufferObject(targetFboExternalIndex);
|
||||||
|
if (targetFbo && m_framebufferManager->EnsureOffscreenColorTarget(targetFboExternalIndex, *targetFbo) &&
|
||||||
|
m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, targetFboExternalIndex)) {
|
||||||
|
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
|
||||||
|
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
|
||||||
|
VkExtent2D offscreenExtent{};
|
||||||
|
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
if (m_framebufferManager->GetOffscreenRenderTarget(targetFboExternalIndex, offscreenRenderPass,
|
||||||
|
offscreenFramebuffer, offscreenExtent,
|
||||||
|
offscreenDepthStencilFormat)) {
|
||||||
|
VkRenderPassBeginInfo offscreenPassInfo{};
|
||||||
|
offscreenPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
offscreenPassInfo.renderPass = offscreenRenderPass;
|
||||||
|
offscreenPassInfo.framebuffer = offscreenFramebuffer;
|
||||||
|
offscreenPassInfo.renderArea.offset = {0, 0};
|
||||||
|
offscreenPassInfo.renderArea.extent = offscreenExtent;
|
||||||
|
offscreenPassInfo.clearValueCount = 0;
|
||||||
|
offscreenPassInfo.pClearValues = nullptr;
|
||||||
|
vkCmdBeginRenderPass(commandBuffer, &offscreenPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
m_activeRenderExtent = offscreenPassInfo.renderArea.extent;
|
||||||
|
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
|
||||||
|
|
||||||
|
if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
|
RecordColorClear(commandBuffer, pending.color);
|
||||||
|
}
|
||||||
|
if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
||||||
|
RecordDepthStencilClear(commandBuffer, pending.mask, pending.depth, pending.stencil);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_activeRenderExtent = prevExtent;
|
||||||
|
m_activeDepthStencilFormat = prevDepthStencilFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
consumePendingClearForTarget(drawIsDefaultFramebuffer, drawFboExternalIndex);
|
||||||
|
|
||||||
|
auto selectSrcStageAccess = [](VkImageLayout layout, VkPipelineStageFlags& outStage, VkAccessFlags& outAccess) {
|
||||||
|
switch (layout) {
|
||||||
|
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||||
|
outStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
outAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||||
|
outStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
outAccess = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||||
|
outStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
outAccess = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_GENERAL:
|
||||||
|
outStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
outAccess = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||||
|
default:
|
||||||
|
outStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
outAccess = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto transitionSwapchainLayout = [&](VkImageLayout newLayout, VkPipelineStageFlags dstStage,
|
||||||
|
VkAccessFlags dstAccess) {
|
||||||
|
const auto oldLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
|
||||||
|
if (oldLayout == newLayout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkAccessFlags srcAccess = 0;
|
||||||
|
selectSrcStageAccess(oldLayout, srcStage, srcAccess);
|
||||||
|
|
||||||
|
VkImageMemoryBarrier barrier{};
|
||||||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
barrier.srcAccessMask = srcAccess;
|
||||||
|
barrier.dstAccessMask = dstAccess;
|
||||||
|
barrier.oldLayout = oldLayout;
|
||||||
|
barrier.newLayout = newLayout;
|
||||||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.image = m_swapchainObject.GetImage(m_imageIndexAcquired);
|
||||||
|
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
barrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
barrier.subresourceRange.levelCount = 1;
|
||||||
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
barrier.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
|
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, newLayout);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto clampCoord = [](GLint value, GLint minValue, GLint maxValue) -> GLint {
|
||||||
|
if (value < minValue) {
|
||||||
|
return minValue;
|
||||||
|
}
|
||||||
|
if (value > maxValue) {
|
||||||
|
return maxValue;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Bool wantColor = (mask & GL_COLOR_BUFFER_BIT) != 0;
|
||||||
|
if (wantColor) {
|
||||||
|
VkImage srcImage = VK_NULL_HANDLE;
|
||||||
|
VkImage dstImage = VK_NULL_HANDLE;
|
||||||
|
VkExtent2D srcExtent{};
|
||||||
|
VkExtent2D dstExtent{};
|
||||||
|
|
||||||
|
if (readIsDefaultFramebuffer) {
|
||||||
|
srcImage = m_swapchainObject.GetImage(m_imageIndexAcquired);
|
||||||
|
srcExtent = m_swapchainObject.GetExtent();
|
||||||
|
} else {
|
||||||
|
if (!MG_State::pGLContext) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: GL context unavailable for read FBO");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto readFbo = MG_State::pGLContext->GetFramebufferObject(readFboExternalIndex);
|
||||||
|
if (!readFbo) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: read FBO %u not found", readFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_framebufferManager->EnsureOffscreenColorTarget(readFboExternalIndex, *readFbo)) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: failed to materialize read FBO %u", readFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_framebufferManager->GetOffscreenColorImage(readFboExternalIndex, srcImage, srcExtent)) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: read FBO %u has no color target", readFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawIsDefaultFramebuffer) {
|
||||||
|
dstImage = m_swapchainObject.GetImage(m_imageIndexAcquired);
|
||||||
|
dstExtent = m_swapchainObject.GetExtent();
|
||||||
|
} else {
|
||||||
|
if (!MG_State::pGLContext) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: GL context unavailable for draw FBO");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto drawFbo = MG_State::pGLContext->GetFramebufferObject(drawFboExternalIndex);
|
||||||
|
if (!drawFbo) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: draw FBO %u not found", drawFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_framebufferManager->EnsureOffscreenColorTarget(drawFboExternalIndex, *drawFbo)) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: failed to materialize draw FBO %u", drawFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_framebufferManager->GetOffscreenColorImage(drawFboExternalIndex, dstImage, dstExtent)) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: draw FBO %u has no color target", drawFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcImage == VK_NULL_HANDLE || dstImage == VK_NULL_HANDLE) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: missing source/destination image");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool sameImage = (srcImage == dstImage);
|
||||||
|
|
||||||
|
if (readIsDefaultFramebuffer) {
|
||||||
|
if (sameImage) {
|
||||||
|
transitionSwapchainLayout(VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||||
|
} else {
|
||||||
|
transitionSwapchainLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT);
|
||||||
|
}
|
||||||
|
} else if (!m_framebufferManager->TransitionOffscreenColorToTransferSrc(commandBuffer,
|
||||||
|
readFboExternalIndex)) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: failed to transition read FBO %u to transfer src",
|
||||||
|
readFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawIsDefaultFramebuffer) {
|
||||||
|
if (sameImage) {
|
||||||
|
transitionSwapchainLayout(VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||||
|
} else {
|
||||||
|
transitionSwapchainLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||||
|
}
|
||||||
|
} else if (sameImage) {
|
||||||
|
if (!m_framebufferManager->TransitionOffscreenColorToGeneral(commandBuffer, drawFboExternalIndex)) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: failed to transition draw FBO %u to general",
|
||||||
|
drawFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!m_framebufferManager->TransitionOffscreenColorToTransferDst(commandBuffer,
|
||||||
|
drawFboExternalIndex)) {
|
||||||
|
MGLOG_W("BlitFramebuffer skipped: failed to transition draw FBO %u to transfer dst",
|
||||||
|
drawFboExternalIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint srcX0Clamped = clampCoord(srcX0, 0, static_cast<GLint>(srcExtent.width));
|
||||||
|
GLint srcX1Clamped = clampCoord(srcX1, 0, static_cast<GLint>(srcExtent.width));
|
||||||
|
GLint srcY0Clamped = clampCoord(srcY0, 0, static_cast<GLint>(srcExtent.height));
|
||||||
|
GLint srcY1Clamped = clampCoord(srcY1, 0, static_cast<GLint>(srcExtent.height));
|
||||||
|
if (readIsDefaultFramebuffer) {
|
||||||
|
const GLint height = static_cast<GLint>(srcExtent.height);
|
||||||
|
srcY0Clamped = height - srcY0Clamped;
|
||||||
|
srcY1Clamped = height - srcY1Clamped;
|
||||||
|
srcY0Clamped = clampCoord(srcY0Clamped, 0, height);
|
||||||
|
srcY1Clamped = clampCoord(srcY1Clamped, 0, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint dstX0Clamped = clampCoord(dstX0, 0, static_cast<GLint>(dstExtent.width));
|
||||||
|
GLint dstX1Clamped = clampCoord(dstX1, 0, static_cast<GLint>(dstExtent.width));
|
||||||
|
GLint dstY0Clamped = clampCoord(dstY0, 0, static_cast<GLint>(dstExtent.height));
|
||||||
|
GLint dstY1Clamped = clampCoord(dstY1, 0, static_cast<GLint>(dstExtent.height));
|
||||||
|
if (drawIsDefaultFramebuffer) {
|
||||||
|
const GLint height = static_cast<GLint>(dstExtent.height);
|
||||||
|
dstY0Clamped = height - dstY0Clamped;
|
||||||
|
dstY1Clamped = height - dstY1Clamped;
|
||||||
|
dstY0Clamped = clampCoord(dstY0Clamped, 0, height);
|
||||||
|
dstY1Clamped = clampCoord(dstY1Clamped, 0, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcX0Clamped == srcX1Clamped || srcY0Clamped == srcY1Clamped || dstX0Clamped == dstX1Clamped ||
|
||||||
|
dstY0Clamped == dstY1Clamped) {
|
||||||
|
MGLOG_D("BlitFramebuffer skipped: empty blit region");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageBlit blit{};
|
||||||
|
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
blit.srcSubresource.mipLevel = 0;
|
||||||
|
blit.srcSubresource.baseArrayLayer = 0;
|
||||||
|
blit.srcSubresource.layerCount = 1;
|
||||||
|
blit.srcOffsets[0] = {srcX0Clamped, srcY0Clamped, 0};
|
||||||
|
blit.srcOffsets[1] = {srcX1Clamped, srcY1Clamped, 1};
|
||||||
|
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
blit.dstSubresource.mipLevel = 0;
|
||||||
|
blit.dstSubresource.baseArrayLayer = 0;
|
||||||
|
blit.dstSubresource.layerCount = 1;
|
||||||
|
blit.dstOffsets[0] = {dstX0Clamped, dstY0Clamped, 0};
|
||||||
|
blit.dstOffsets[1] = {dstX1Clamped, dstY1Clamped, 1};
|
||||||
|
|
||||||
|
const VkImageLayout srcLayout = sameImage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
|
const VkImageLayout dstLayout = sameImage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
vkCmdBlitImage(commandBuffer, srcImage, srcLayout, dstImage, dstLayout, 1, &blit, vkFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImage srcImage = VK_NULL_HANDLE;
|
auto hasStencilComponent = [](VkFormat format) -> Bool {
|
||||||
VkExtent2D srcExtent{};
|
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||||
if (!m_framebufferManager->GetOffscreenColorImage(readFboExternalIndex, srcImage, srcExtent)) {
|
};
|
||||||
MGLOG_D("BlitFramebuffer skipped: offscreen image for FBO %u is unavailable", readFboExternalIndex);
|
|
||||||
return false;
|
const Bool wantDepth = (mask & GL_DEPTH_BUFFER_BIT) != 0;
|
||||||
|
const Bool wantStencil = (mask & GL_STENCIL_BUFFER_BIT) != 0;
|
||||||
|
|
||||||
|
if (wantDepth || wantStencil) {
|
||||||
|
if (filter != GL_NEAREST) {
|
||||||
|
MGLOG_W("BlitFramebuffer: depth/stencil blit requires GL_NEAREST, overriding filter");
|
||||||
|
vkFilter = VK_FILTER_NEAREST;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImage srcDepthImage = VK_NULL_HANDLE;
|
||||||
|
VkImage dstDepthImage = VK_NULL_HANDLE;
|
||||||
|
VkExtent2D srcDepthExtent{};
|
||||||
|
VkExtent2D dstDepthExtent{};
|
||||||
|
VkFormat srcDepthFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
VkFormat dstDepthFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
|
||||||
|
if (readIsDefaultFramebuffer) {
|
||||||
|
if (m_depthStencilImages.empty() || m_depthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||||
|
MGLOG_W("BlitFramebuffer: default framebuffer has no depth/stencil image");
|
||||||
|
} else {
|
||||||
|
srcDepthImage = m_depthStencilImages[m_imageIndexAcquired];
|
||||||
|
srcDepthExtent = m_swapchainObject.GetExtent();
|
||||||
|
srcDepthFormat = m_depthStencilFormat;
|
||||||
|
}
|
||||||
|
} else if (m_framebufferManager) {
|
||||||
|
if (!MG_State::pGLContext) {
|
||||||
|
MGLOG_W("BlitFramebuffer: GL context unavailable for read depth/stencil FBO");
|
||||||
|
} else {
|
||||||
|
const auto readFbo = MG_State::pGLContext->GetFramebufferObject(readFboExternalIndex);
|
||||||
|
if (!readFbo) {
|
||||||
|
MGLOG_W("BlitFramebuffer: read FBO %u not found", readFboExternalIndex);
|
||||||
|
} else if (!m_framebufferManager->EnsureOffscreenColorTarget(readFboExternalIndex, *readFbo)) {
|
||||||
|
MGLOG_W("BlitFramebuffer: failed to materialize read FBO %u for depth/stencil",
|
||||||
|
readFboExternalIndex);
|
||||||
|
} else if (!m_framebufferManager->GetOffscreenDepthStencilImage(readFboExternalIndex, srcDepthImage,
|
||||||
|
srcDepthExtent, srcDepthFormat)) {
|
||||||
|
MGLOG_W("BlitFramebuffer: read FBO %u has no depth/stencil image", readFboExternalIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawIsDefaultFramebuffer) {
|
||||||
|
if (m_depthStencilImages.empty() || m_depthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||||
|
MGLOG_W("BlitFramebuffer: default framebuffer has no depth/stencil image");
|
||||||
|
} else {
|
||||||
|
dstDepthImage = m_depthStencilImages[m_imageIndexAcquired];
|
||||||
|
dstDepthExtent = m_swapchainObject.GetExtent();
|
||||||
|
dstDepthFormat = m_depthStencilFormat;
|
||||||
|
}
|
||||||
|
} else if (m_framebufferManager) {
|
||||||
|
if (!MG_State::pGLContext) {
|
||||||
|
MGLOG_W("BlitFramebuffer: GL context unavailable for draw depth/stencil FBO");
|
||||||
|
} else {
|
||||||
|
const auto drawFbo = MG_State::pGLContext->GetFramebufferObject(drawFboExternalIndex);
|
||||||
|
if (!drawFbo) {
|
||||||
|
MGLOG_W("BlitFramebuffer: draw FBO %u not found", drawFboExternalIndex);
|
||||||
|
} else if (!m_framebufferManager->EnsureOffscreenColorTarget(drawFboExternalIndex, *drawFbo)) {
|
||||||
|
MGLOG_W("BlitFramebuffer: failed to materialize draw FBO %u for depth/stencil",
|
||||||
|
drawFboExternalIndex);
|
||||||
|
} else if (!m_framebufferManager->GetOffscreenDepthStencilImage(drawFboExternalIndex, dstDepthImage,
|
||||||
|
dstDepthExtent, dstDepthFormat)) {
|
||||||
|
MGLOG_W("BlitFramebuffer: draw FBO %u has no depth/stencil image", drawFboExternalIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcDepthImage != VK_NULL_HANDLE && dstDepthImage != VK_NULL_HANDLE) {
|
||||||
|
if (srcDepthFormat != dstDepthFormat) {
|
||||||
|
MGLOG_W("BlitFramebuffer: depth/stencil format mismatch (src=%d, dst=%d), skipping", srcDepthFormat,
|
||||||
|
dstDepthFormat);
|
||||||
|
} else {
|
||||||
|
VkImageAspectFlags srcAspectMask = 0;
|
||||||
|
VkImageAspectFlags dstAspectMask = 0;
|
||||||
|
if (wantDepth) {
|
||||||
|
srcAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
dstAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
}
|
||||||
|
if (wantStencil && hasStencilComponent(srcDepthFormat)) {
|
||||||
|
srcAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
dstAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
} else if (wantStencil) {
|
||||||
|
MGLOG_W("BlitFramebuffer: stencil bit requested but format has no stencil component");
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkImageAspectFlags aspectMask = srcAspectMask & dstAspectMask;
|
||||||
|
if (aspectMask != 0) {
|
||||||
|
const Bool sameDepthImage = (srcDepthImage == dstDepthImage);
|
||||||
|
const VkImageAspectFlags fullAspectMask =
|
||||||
|
VK_IMAGE_ASPECT_DEPTH_BIT |
|
||||||
|
(hasStencilComponent(srcDepthFormat) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
|
||||||
|
|
||||||
|
auto transitionDefaultDepthStencil = [&](VkImageLayout newLayout, VkPipelineStageFlags dstStage,
|
||||||
|
VkAccessFlags dstAccess) {
|
||||||
|
if (m_depthStencilImages.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto oldLayout = m_depthStencilImageLayouts[m_imageIndexAcquired];
|
||||||
|
if (oldLayout == newLayout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkAccessFlags srcAccess = 0;
|
||||||
|
switch (oldLayout) {
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||||
|
srcStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||||
|
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||||
|
srcAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
srcAccess = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
srcAccess = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_GENERAL:
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
srcAccess = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
srcAccess = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageMemoryBarrier barrier{};
|
||||||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
barrier.srcAccessMask = srcAccess;
|
||||||
|
barrier.dstAccessMask = dstAccess;
|
||||||
|
barrier.oldLayout = oldLayout;
|
||||||
|
barrier.newLayout = newLayout;
|
||||||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.image = m_depthStencilImages[m_imageIndexAcquired];
|
||||||
|
barrier.subresourceRange.aspectMask = fullAspectMask;
|
||||||
|
barrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
barrier.subresourceRange.levelCount = 1;
|
||||||
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
barrier.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1,
|
||||||
|
&barrier);
|
||||||
|
m_depthStencilImageLayouts[m_imageIndexAcquired] = newLayout;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (readIsDefaultFramebuffer) {
|
||||||
|
if (sameDepthImage) {
|
||||||
|
transitionDefaultDepthStencil(VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT |
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||||
|
} else {
|
||||||
|
transitionDefaultDepthStencil(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT);
|
||||||
|
}
|
||||||
|
} else if (!m_framebufferManager->TransitionOffscreenDepthStencilToTransferSrc(
|
||||||
|
commandBuffer, readFboExternalIndex)) {
|
||||||
|
MGLOG_W("BlitFramebuffer: failed to transition read depth/stencil FBO %u to transfer src",
|
||||||
|
readFboExternalIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawIsDefaultFramebuffer) {
|
||||||
|
if (sameDepthImage) {
|
||||||
|
transitionDefaultDepthStencil(VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT |
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||||
|
} else {
|
||||||
|
transitionDefaultDepthStencil(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||||
|
}
|
||||||
|
} else if (sameDepthImage) {
|
||||||
|
if (!m_framebufferManager->TransitionOffscreenDepthStencilToGeneral(commandBuffer,
|
||||||
|
drawFboExternalIndex)) {
|
||||||
|
MGLOG_W("BlitFramebuffer: failed to transition draw depth/stencil FBO %u to general",
|
||||||
|
drawFboExternalIndex);
|
||||||
|
}
|
||||||
|
} else if (!m_framebufferManager->TransitionOffscreenDepthStencilToTransferDst(
|
||||||
|
commandBuffer, drawFboExternalIndex)) {
|
||||||
|
MGLOG_W("BlitFramebuffer: failed to transition draw depth/stencil FBO %u to transfer dst",
|
||||||
|
drawFboExternalIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint srcDX0 = clampCoord(srcX0, 0, static_cast<GLint>(srcDepthExtent.width));
|
||||||
|
GLint srcDX1 = clampCoord(srcX1, 0, static_cast<GLint>(srcDepthExtent.width));
|
||||||
|
GLint srcDY0 = clampCoord(srcY0, 0, static_cast<GLint>(srcDepthExtent.height));
|
||||||
|
GLint srcDY1 = clampCoord(srcY1, 0, static_cast<GLint>(srcDepthExtent.height));
|
||||||
|
if (readIsDefaultFramebuffer) {
|
||||||
|
const GLint height = static_cast<GLint>(srcDepthExtent.height);
|
||||||
|
srcDY0 = height - srcDY0;
|
||||||
|
srcDY1 = height - srcDY1;
|
||||||
|
srcDY0 = clampCoord(srcDY0, 0, height);
|
||||||
|
srcDY1 = clampCoord(srcDY1, 0, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint dstDX0 = clampCoord(dstX0, 0, static_cast<GLint>(dstDepthExtent.width));
|
||||||
|
GLint dstDX1 = clampCoord(dstX1, 0, static_cast<GLint>(dstDepthExtent.width));
|
||||||
|
GLint dstDY0 = clampCoord(dstY0, 0, static_cast<GLint>(dstDepthExtent.height));
|
||||||
|
GLint dstDY1 = clampCoord(dstY1, 0, static_cast<GLint>(dstDepthExtent.height));
|
||||||
|
if (drawIsDefaultFramebuffer) {
|
||||||
|
const GLint height = static_cast<GLint>(dstDepthExtent.height);
|
||||||
|
dstDY0 = height - dstDY0;
|
||||||
|
dstDY1 = height - dstDY1;
|
||||||
|
dstDY0 = clampCoord(dstDY0, 0, height);
|
||||||
|
dstDY1 = clampCoord(dstDY1, 0, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcDX0 != srcDX1 && srcDY0 != srcDY1 && dstDX0 != dstDX1 && dstDY0 != dstDY1) {
|
||||||
|
VkImageBlit depthBlit{};
|
||||||
|
depthBlit.srcSubresource.aspectMask = aspectMask;
|
||||||
|
depthBlit.srcSubresource.mipLevel = 0;
|
||||||
|
depthBlit.srcSubresource.baseArrayLayer = 0;
|
||||||
|
depthBlit.srcSubresource.layerCount = 1;
|
||||||
|
depthBlit.srcOffsets[0] = {srcDX0, srcDY0, 0};
|
||||||
|
depthBlit.srcOffsets[1] = {srcDX1, srcDY1, 1};
|
||||||
|
depthBlit.dstSubresource.aspectMask = aspectMask;
|
||||||
|
depthBlit.dstSubresource.mipLevel = 0;
|
||||||
|
depthBlit.dstSubresource.baseArrayLayer = 0;
|
||||||
|
depthBlit.dstSubresource.layerCount = 1;
|
||||||
|
depthBlit.dstOffsets[0] = {dstDX0, dstDY0, 0};
|
||||||
|
depthBlit.dstOffsets[1] = {dstDX1, dstDY1, 1};
|
||||||
|
|
||||||
|
const VkImageLayout depthSrcLayout =
|
||||||
|
sameDepthImage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
|
const VkImageLayout depthDstLayout =
|
||||||
|
sameDepthImage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
vkCmdBlitImage(commandBuffer, srcDepthImage, depthSrcLayout, dstDepthImage, depthDstLayout,
|
||||||
|
1, &depthBlit, vkFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto swapchainOldLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
|
if (readIsDefaultFramebuffer || drawIsDefaultFramebuffer) {
|
||||||
if (swapchainOldLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
transitionSwapchainLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0);
|
||||||
VkImageMemoryBarrier toTransferDstBarrier{};
|
|
||||||
toTransferDstBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
toTransferDstBarrier.srcAccessMask = 0;
|
|
||||||
toTransferDstBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
toTransferDstBarrier.oldLayout = swapchainOldLayout;
|
|
||||||
toTransferDstBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
toTransferDstBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
toTransferDstBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
toTransferDstBarrier.image = m_swapchainObject.GetImage(m_imageIndexAcquired);
|
|
||||||
toTransferDstBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
toTransferDstBarrier.subresourceRange.baseMipLevel = 0;
|
|
||||||
toTransferDstBarrier.subresourceRange.levelCount = 1;
|
|
||||||
toTransferDstBarrier.subresourceRange.baseArrayLayer = 0;
|
|
||||||
toTransferDstBarrier.subresourceRange.layerCount = 1;
|
|
||||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
|
|
||||||
nullptr, 0, nullptr, 1, &toTransferDstBarrier);
|
|
||||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageBlit blitRegion{};
|
|
||||||
blitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
blitRegion.srcSubresource.mipLevel = 0;
|
|
||||||
blitRegion.srcSubresource.baseArrayLayer = 0;
|
|
||||||
blitRegion.srcSubresource.layerCount = 1;
|
|
||||||
blitRegion.srcOffsets[0] = {srcX0, srcY0, 0};
|
|
||||||
blitRegion.srcOffsets[1] = {srcX1, srcY1, 1};
|
|
||||||
blitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
blitRegion.dstSubresource.mipLevel = 0;
|
|
||||||
blitRegion.dstSubresource.baseArrayLayer = 0;
|
|
||||||
blitRegion.dstSubresource.layerCount = 1;
|
|
||||||
blitRegion.dstOffsets[0] = {dstX0, dstY0, 0};
|
|
||||||
blitRegion.dstOffsets[1] = {dstX1, dstY1, 1};
|
|
||||||
|
|
||||||
vkCmdBlitImage(commandBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
||||||
m_swapchainObject.GetImage(m_imageIndexAcquired), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
|
|
||||||
&blitRegion, (filter == GL_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST));
|
|
||||||
|
|
||||||
VkImageMemoryBarrier toPresentBarrier{};
|
|
||||||
toPresentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
toPresentBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
toPresentBarrier.dstAccessMask = 0;
|
|
||||||
toPresentBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
toPresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
||||||
toPresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
toPresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
toPresentBarrier.image = m_swapchainObject.GetImage(m_imageIndexAcquired);
|
|
||||||
toPresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
toPresentBarrier.subresourceRange.baseMipLevel = 0;
|
|
||||||
toPresentBarrier.subresourceRange.levelCount = 1;
|
|
||||||
toPresentBarrier.subresourceRange.baseArrayLayer = 0;
|
|
||||||
toPresentBarrier.subresourceRange.layerCount = 1;
|
|
||||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0,
|
|
||||||
nullptr, 0, nullptr, 1, &toPresentBarrier);
|
|
||||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
|
||||||
|
|
||||||
(void)srcExtent;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
DrawArrayPayload drawArray;
|
DrawArrayPayload drawArray;
|
||||||
GLenum indexType = GL_UNSIGNED_SHORT;
|
GLenum indexType = GL_UNSIGNED_SHORT;
|
||||||
SizeT indexByteOffset = 0;
|
SizeT indexByteOffset = 0;
|
||||||
|
GLint baseVertex = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices {
|
||||||
|
|||||||
Reference in New Issue
Block a user