mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Chore] (MG_Backend/DirectVulkan): get rid of more junk
This commit is contained in:
@@ -310,8 +310,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const auto& clearColor = MG_State::pGLContext->GetClearColor();
|
const auto& clearColor = MG_State::pGLContext->GetClearColor();
|
||||||
const auto clearDepth = MG_State::pGLContext->GetClearDepth();
|
const auto clearDepth = MG_State::pGLContext->GetClearDepth();
|
||||||
const auto clearStencil = static_cast<Uint32>(MG_State::pGLContext->GetClearStencil());
|
const auto clearStencil = static_cast<Uint32>(MG_State::pGLContext->GetClearStencil());
|
||||||
pVulkanRenderer->RequestClear(mask, clearColor, clearDepth, clearStencil, drawFboExternalIndex,
|
pVulkanRenderer->QueueClearRequest(mask, clearColor, clearDepth, clearStencil,
|
||||||
isDefaultFboTarget);
|
drawFboExternalIndex,
|
||||||
|
isDefaultFboTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
||||||
@@ -422,35 +423,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||||
GLint dstY1, GLbitfield mask, GLenum filter) {
|
GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
|
|
||||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
|
|
||||||
|
|
||||||
const auto& readFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
|
||||||
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 defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
|
||||||
|
|
||||||
const Bool readIsDefault = (readFbo == defaultFbo) || (readFbo == nullptr && defaultFbo != nullptr);
|
|
||||||
const Bool drawIsDefault = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
|
||||||
|
|
||||||
Uint readFboExternalIndex = 0;
|
|
||||||
if (readFbo) {
|
|
||||||
readFboExternalIndex = readFbo->GetExternalIndex();
|
|
||||||
} else if (defaultFbo) {
|
|
||||||
readFboExternalIndex = defaultFbo->GetExternalIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint drawFboExternalIndex = 0;
|
|
||||||
if (drawFbo) {
|
|
||||||
drawFboExternalIndex = drawFbo->GetExternalIndex();
|
|
||||||
} else if (defaultFbo) {
|
|
||||||
drawFboExternalIndex = defaultFbo->GetExternalIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter,
|
|
||||||
readFboExternalIndex, drawFboExternalIndex, readIsDefault, drawIsDefault);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Present() {
|
void Present() {
|
||||||
|
|||||||
@@ -327,8 +327,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
MGLOG_I("VulkanRenderer shut down completed");
|
MGLOG_I("VulkanRenderer shut down completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::RequestClear(GLbitfield mask, const FloatVec4& color, Float depth, Uint32 stencil,
|
void VulkanRenderer::QueueClearRequest(GLbitfield mask, const FloatVec4& color, Float depth, Uint32 stencil,
|
||||||
Uint drawFboExternalIndex, Bool isDefaultFramebufferTarget) {
|
Uint drawFboExternalIndex, Bool isDefaultFramebufferTarget) {
|
||||||
const GLbitfield supportedMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
const GLbitfield supportedMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||||
const GLbitfield requestMask = (mask & supportedMask);
|
const GLbitfield requestMask = (mask & supportedMask);
|
||||||
if (requestMask == 0) {
|
if (requestMask == 0) {
|
||||||
@@ -1190,600 +1190,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VulkanRenderer::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
|
||||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter,
|
|
||||||
Uint readFboExternalIndex, Uint drawFboExternalIndex,
|
|
||||||
|
|
||||||
Bool readIsDefaultFramebuffer, Bool drawIsDefaultFramebuffer) {
|
|
||||||
if ((mask & (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) == 0) {
|
|
||||||
MGLOG_D("BlitFramebuffer skipped: empty mask");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& frame = m_frameContext.GetCurrent();
|
|
||||||
if (frame.hasCommandBufferRecorded) {
|
|
||||||
MGLOG_D("BlitFramebuffer skipped: current frame command buffer already finalized");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!frame.isCommandRecording) {
|
|
||||||
m_frameContext.BeginCommandRecording();
|
|
||||||
MOBILEGL_ASSERT(m_uniformDescriptorBinder != nullptr, "BlitFramebuffer: binder is null");
|
|
||||||
m_uniformDescriptorBinder->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer = frame.commandBuffer;
|
|
||||||
if (m_isMainRenderPassActive) {
|
|
||||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "BlitFramebuffer: render pass manager is null");
|
|
||||||
m_renderPassManager->EndRenderPass(commandBuffer);
|
|
||||||
if (m_activeRenderTargetIsDefault) {
|
|
||||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
|
||||||
}
|
|
||||||
m_isMainRenderPassActive = false;
|
|
||||||
m_activeRenderPass = VK_NULL_HANDLE;
|
|
||||||
m_activeRenderExtent = {0, 0};
|
|
||||||
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
|
||||||
m_activeRenderTargetIsDefault = true;
|
|
||||||
m_activeDrawFboExternalIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOBILEGL_ASSERT(m_framebufferManager != nullptr, "BlitFramebuffer: framebuffer manager not available");
|
|
||||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "BlitFramebuffer: renderpass manager is null");
|
|
||||||
|
|
||||||
auto consumePendingClearForTarget = [&](Bool targetIsDefault, Uint targetFboExternalIndex) {
|
|
||||||
const Uint64 pendingKey = BuildPendingClearKey(targetFboExternalIndex, targetIsDefault);
|
|
||||||
auto pendingIt = m_pendingClears.find(pendingKey);
|
|
||||||
if (pendingIt == m_pendingClears.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PendingClearState pending = pendingIt->second;
|
|
||||||
m_pendingClears.erase(pendingIt);
|
|
||||||
|
|
||||||
const auto prevExtent = m_activeRenderExtent;
|
|
||||||
const auto prevDepthStencilFormat = m_activeDepthStencilFormat;
|
|
||||||
|
|
||||||
if (targetIsDefault) {
|
|
||||||
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
|
|
||||||
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
|
|
||||||
|
|
||||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
|
||||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
|
||||||
VkExtent2D extent{};
|
|
||||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
|
||||||
if (!GetDefaultRenderTargetForCurrentImage(renderPass, framebuffer, extent, depthStencilFormat)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_renderPassManager->BeginRenderPass(commandBuffer, renderPass, framebuffer, extent);
|
|
||||||
|
|
||||||
m_activeRenderExtent = extent;
|
|
||||||
m_activeDepthStencilFormat = depthStencilFormat;
|
|
||||||
|
|
||||||
if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
|
||||||
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pending.color);
|
|
||||||
}
|
|
||||||
if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
|
||||||
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, pending.mask,
|
|
||||||
pending.depth, pending.stencil,
|
|
||||||
m_activeDepthStencilFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_renderPassManager->EndRenderPass(commandBuffer);
|
|
||||||
} else {
|
|
||||||
const auto targetFbo = MG_State::pGLContext->GetFramebufferObject(targetFboExternalIndex);
|
|
||||||
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
|
|
||||||
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
|
|
||||||
VkExtent2D offscreenExtent{};
|
|
||||||
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
|
||||||
if (targetFbo &&
|
|
||||||
EnsureOffscreenRenderTarget(targetFboExternalIndex, *targetFbo, offscreenRenderPass,
|
|
||||||
offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat) &&
|
|
||||||
m_framebufferManager->Transition(commandBuffer,
|
|
||||||
VkRenderTargetManager::TransitionResource::OffscreenColor,
|
|
||||||
VkRenderTargetManager::TransitionUsage::Attachment,
|
|
||||||
targetFboExternalIndex)) {
|
|
||||||
m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer,
|
|
||||||
offscreenExtent);
|
|
||||||
|
|
||||||
m_activeRenderExtent = offscreenExtent;
|
|
||||||
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
|
|
||||||
|
|
||||||
if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
|
||||||
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pending.color);
|
|
||||||
}
|
|
||||||
if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
|
||||||
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, pending.mask,
|
|
||||||
pending.depth, pending.stencil,
|
|
||||||
m_activeDepthStencilFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_renderPassManager->EndRenderPass(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 {
|
|
||||||
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 {
|
|
||||||
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->Transition(commandBuffer,
|
|
||||||
VkRenderTargetManager::TransitionResource::OffscreenColor,
|
|
||||||
VkRenderTargetManager::TransitionUsage::TransferSrc,
|
|
||||||
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->Transition(commandBuffer,
|
|
||||||
VkRenderTargetManager::TransitionResource::OffscreenColor,
|
|
||||||
VkRenderTargetManager::TransitionUsage::General,
|
|
||||||
drawFboExternalIndex)) {
|
|
||||||
MGLOG_W("BlitFramebuffer skipped: failed to transition draw FBO %u to general",
|
|
||||||
drawFboExternalIndex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (!m_framebufferManager->Transition(commandBuffer,
|
|
||||||
VkRenderTargetManager::TransitionResource::OffscreenColor,
|
|
||||||
VkRenderTargetManager::TransitionUsage::TransferDst,
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hasStencilComponent = [](VkFormat format) -> Bool {
|
|
||||||
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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 {
|
|
||||||
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->Transition(
|
|
||||||
commandBuffer, VkRenderTargetManager::TransitionResource::OffscreenDepthStencil,
|
|
||||||
VkRenderTargetManager::TransitionUsage::TransferSrc, 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->Transition(
|
|
||||||
commandBuffer, VkRenderTargetManager::TransitionResource::OffscreenDepthStencil,
|
|
||||||
VkRenderTargetManager::TransitionUsage::General, drawFboExternalIndex)) {
|
|
||||||
MGLOG_W("BlitFramebuffer: failed to transition draw depth/stencil FBO %u to general",
|
|
||||||
drawFboExternalIndex);
|
|
||||||
}
|
|
||||||
} else if (!m_framebufferManager->Transition(
|
|
||||||
commandBuffer, VkRenderTargetManager::TransitionResource::OffscreenDepthStencil,
|
|
||||||
VkRenderTargetManager::TransitionUsage::TransferDst, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readIsDefaultFramebuffer || drawIsDefaultFramebuffer) {
|
|
||||||
transitionSwapchainLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::Render() {
|
|
||||||
// Route test rendering through the same frame-start logic used by draw calls,
|
|
||||||
// so pending glClear() state can be consumed consistently.
|
|
||||||
EnsureFrameRecordingStarted();
|
|
||||||
auto& frame = m_frameContext.GetCurrent();
|
|
||||||
if (!frame.isCommandRecording || !m_isMainRenderPassActive) {
|
|
||||||
MGLOG_D("Render skipped: frame recording was not started");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
|
||||||
const auto swapchainExtent = m_swapchainObject.GetExtent();
|
|
||||||
|
|
||||||
(void)commandBuffer;
|
|
||||||
(void)swapchainExtent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::Present() {
|
void VulkanRenderer::Present() {
|
||||||
MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(),
|
MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(),
|
||||||
"Present, acquired image index out of range");
|
"Present, acquired image index out of range");
|
||||||
|
|||||||
@@ -70,17 +70,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void Initialize();
|
void Initialize();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
void RequestClear(GLbitfield mask, const FloatVec4& color, Float depth, Uint32 stencil,
|
void QueueClearRequest(GLbitfield mask, const FloatVec4& color, Float depth, Uint32 stencil,
|
||||||
Uint drawFboExternalIndex, Bool isDefaultFramebufferTarget);
|
Uint drawFboExternalIndex, Bool isDefaultFramebufferTarget);
|
||||||
Bool ConsumePendingColorClear(VkClearColorValue& outClearColor);
|
Bool ConsumePendingColorClear(VkClearColorValue& outClearColor);
|
||||||
void EnsureFrameRecordingStarted();
|
void EnsureFrameRecordingStarted();
|
||||||
void DrawArrays(const DrawArrayPayload& payload);
|
void DrawArrays(const DrawArrayPayload& payload);
|
||||||
void DrawElements(const DrawElementPayload& payload);
|
void DrawElements(const DrawElementPayload& payload);
|
||||||
void MultiDrawElements(const Vector<DrawElementPayload>& payloads);
|
void MultiDrawElements(const Vector<DrawElementPayload>& payloads);
|
||||||
Bool BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
|
||||||
GLint dstY1, GLbitfield mask, GLenum filter, Uint readFboExternalIndex,
|
|
||||||
Uint drawFboExternalIndex, Bool readIsDefaultFramebuffer, Bool drawIsDefaultFramebuffer);
|
|
||||||
void Render();
|
|
||||||
void Present();
|
void Present();
|
||||||
|
|
||||||
const PhysicalDevice& GetPhysicalDevice() const;
|
const PhysicalDevice& GetPhysicalDevice() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user