mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 12:18:30 +09:00
[Fix] (DirectVulkan): implement color renderbuffer attachments - render pass/pipeline/blit/copy/readback/clear paths treated color renderbuffers as absent (writes masked to VK_ATTACHMENT_UNUSED, glClear dropped, readback zeros)
This commit is contained in:
@@ -251,11 +251,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const auto internalFormat = renderbuffer->GetInternalFormat();
|
||||
const VkFormat format = MG_Util::ConvertTextureInternalFormatToVkEnum(internalFormat);
|
||||
const VkImageAspectFlags aspect = ResolveImageAspectMaskForFormat(format);
|
||||
if ((aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
MGLOG_E("GetOrCreateRenderbufferResource: color renderbuffer %u is not supported by DirectVulkan render passes yet",
|
||||
renderbuffer->GetExternalIndex());
|
||||
return nullptr;
|
||||
}
|
||||
// Renderbuffers are never sampled (GL has no way to bind one to a sampler), so the
|
||||
// usage set is attachment + transfer: transfer covers readback (vkCmdCopyImageToBuffer),
|
||||
// BlitFramebuffer, CopyTexImage sources, and out-of-render-pass clear materialization.
|
||||
const VkImageUsageFlags imageUsage =
|
||||
((aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0 ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
: VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
auto& resource = m_renderbufferResources[renderbuffer.get()];
|
||||
const Bool needsCreate =
|
||||
@@ -285,7 +287,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.usage = imageUsage;
|
||||
imageInfo.samples = sampleCount;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
@@ -386,6 +388,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void VkRenderPassManager::QueueRenderbufferClear(
|
||||
GLbitfield mask, const ClearFramebufferPayload& clearPayload,
|
||||
const MG_State::GLState::FramebufferObject& drawFbo) {
|
||||
if ((mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||
// Color renderbuffer draw buffers take the framebuffer-level clear too; texture
|
||||
// attachments are skipped by the per-attachment overload's IsRenderbuffer guard.
|
||||
for (const auto attachmentType : drawFbo.GetDrawBuffers()) {
|
||||
if (attachmentType == FramebufferAttachmentType::None) {
|
||||
continue;
|
||||
}
|
||||
QueueRenderbufferClear(
|
||||
ClearAttachmentPayload{.mask = GL_COLOR_BUFFER_BIT, .color = clearPayload.color},
|
||||
drawFbo.GetAttachment(attachmentType));
|
||||
}
|
||||
}
|
||||
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
QueueRenderbufferClear(
|
||||
ClearAttachmentPayload{.mask = GL_DEPTH_BUFFER_BIT, .depth = clearPayload.depth},
|
||||
@@ -682,6 +696,83 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// assuming default FBO has the right param
|
||||
for (Uint32 i = 0; i < colorAttachmentSlotCount; ++i) {
|
||||
auto drawbuf = drawbufs[i];
|
||||
|
||||
// Renderbuffer color attachments mirror the texture path below, with the
|
||||
// resource (image/view/format/layout) coming from the render-pass manager's
|
||||
// renderbuffer store instead of the texture manager.
|
||||
if (drawbuf != FramebufferAttachmentType::None && !isDefaultFbo) {
|
||||
const auto& rbAtt = fbo.GetAttachment(drawbuf);
|
||||
if (rbAtt.IsRenderbuffer() && rbAtt.IsComplete()) {
|
||||
const auto& renderbuffer = rbAtt.GetRenderbuffer();
|
||||
auto* rbResource = GetOrCreateRenderbufferResource(renderbuffer);
|
||||
if (rbResource == nullptr || (rbResource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) == 0) {
|
||||
MGLOG_E("GetOrCreateRenderPass: draw buffer slot %u on FBO %u has an unsupported color "
|
||||
"renderbuffer %u; using VK_ATTACHMENT_UNUSED",
|
||||
i, fbo.GetExternalIndex(), renderbuffer->GetExternalIndex());
|
||||
continue;
|
||||
}
|
||||
|
||||
const Uint32 rbAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||
attachmentDescriptions.emplace_back();
|
||||
VkAttachmentDescription& rbDesc = attachmentDescriptions.back();
|
||||
|
||||
ClearAttachmentPayload rbClearPayload{};
|
||||
Bool rbHasClear = GetPendingRenderbufferClear(renderbuffer.get(), rbClearPayload) &&
|
||||
(rbClearPayload.mask & GL_COLOR_BUFFER_BIT) != 0;
|
||||
if (rbHasClear &&
|
||||
MG_Util::GetBaseInternalFormatComponentCount(renderbuffer->GetInternalFormat()) == 3) {
|
||||
// RGB renderbuffers are backed by an RGBA image; the missing alpha reads as 1.
|
||||
rbClearPayload.color =
|
||||
FloatVec4(rbClearPayload.color.x(), rbClearPayload.color.y(),
|
||||
rbClearPayload.color.z(), 1.0f);
|
||||
}
|
||||
|
||||
const VkImageLayout trackedRbLayout = rbResource->layout;
|
||||
rbDesc.flags = 0;
|
||||
rbDesc.format = rbResource->format;
|
||||
rbDesc.samples = rbResource->sampleCount;
|
||||
rbDesc.loadOp = rbHasClear ? VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
(trackedRbLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
||||
: VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
rbDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
rbDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
rbDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
rbDesc.initialLayout = (rbHasClear || trackedRbLayout == VK_IMAGE_LAYOUT_UNDEFINED) ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED : trackedRbLayout;
|
||||
rbDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
adoptRenderPassSampleCount(rbResource->sampleCount, "color",
|
||||
static_cast<Int>(renderbuffer->GetExternalIndex()));
|
||||
|
||||
if (rbHasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = rbAttachmentIndex,
|
||||
.colorAttachmentSlot = i,
|
||||
.renderbuffer = renderbuffer.get(),
|
||||
.hasInlinePayload = true,
|
||||
.inlinePayload = rbClearPayload,
|
||||
});
|
||||
}
|
||||
|
||||
if (width == 0)
|
||||
width = static_cast<Int>(rbResource->extent.width);
|
||||
if (height == 0)
|
||||
height = static_cast<Int>(rbResource->extent.height);
|
||||
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.target = TrackedAttachmentTarget::Renderbuffer,
|
||||
.renderbuffer = renderbuffer,
|
||||
.finalLayout = rbDesc.finalLayout,
|
||||
});
|
||||
textureResources.emplace_back(nullptr);
|
||||
attachmentViews.emplace_back(rbResource->view);
|
||||
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||
"GetOrCreateRenderPass: renderbuffer view missing at color attachment %d", i);
|
||||
|
||||
colorAttachmentRefs[i].attachment = rbAttachmentIndex;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto* texture = ResolveCompleteColorAttachmentTexture(fbo, drawbuf, i);
|
||||
if (texture == nullptr)
|
||||
continue;
|
||||
|
||||
@@ -211,6 +211,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint64 m_rpFastRbEpoch = 0;
|
||||
Uint64 m_rpFastRenderPassHash = 0;
|
||||
|
||||
public:
|
||||
struct RenderbufferResource {
|
||||
WeakPtr<MG_State::GLState::RenderbufferObject> renderbuffer;
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
@@ -227,6 +228,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void Destroy(VkDevice device, VmaAllocator allocator);
|
||||
};
|
||||
|
||||
// Public so the renderer's blit/copy/readback bindings can source renderbuffer
|
||||
// attachments the same way texture attachments go through the texture manager.
|
||||
RenderbufferResource* GetOrCreateRenderbufferResource(
|
||||
const SharedPtr<MG_State::GLState::RenderbufferObject>& renderbuffer);
|
||||
Bool GetPendingRenderbufferClear(MG_State::GLState::RenderbufferObject* renderbuffer,
|
||||
ClearAttachmentPayload& outPayload) const;
|
||||
|
||||
private:
|
||||
struct PendingRenderbufferClear {
|
||||
WeakPtr<MG_State::GLState::RenderbufferObject> renderbuffer;
|
||||
ClearAttachmentPayload payload{};
|
||||
@@ -235,10 +244,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
UnorderedMap<MG_State::GLState::RenderbufferObject*, RenderbufferResource> m_renderbufferResources;
|
||||
UnorderedMap<MG_State::GLState::RenderbufferObject*, PendingRenderbufferClear> m_pendingRenderbufferClears;
|
||||
|
||||
RenderbufferResource* GetOrCreateRenderbufferResource(
|
||||
const SharedPtr<MG_State::GLState::RenderbufferObject>& renderbuffer);
|
||||
Bool GetPendingRenderbufferClear(MG_State::GLState::RenderbufferObject* renderbuffer,
|
||||
ClearAttachmentPayload& outPayload) const;
|
||||
Bool HasPendingRenderbufferClear(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachment) const;
|
||||
void CollectRenderbufferGarbage();
|
||||
|
||||
@@ -1274,7 +1274,8 @@ void main() {
|
||||
|
||||
static Bool ResolveColorBlitBinding(MG_State::GLState::FramebufferObject& fbo, Bool isReadFramebuffer,
|
||||
Uint32 swapchainImageIndex, SwapchainObject& swapchainObject,
|
||||
VkTextureManager& textureManager, BlitImageBinding& outBinding) {
|
||||
VkTextureManager& textureManager,
|
||||
VkRenderPassManager& renderPassManager, BlitImageBinding& outBinding) {
|
||||
const Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||
const FramebufferAttachmentType attachmentType =
|
||||
isReadFramebuffer ? fbo.GetReadBuffer() : fbo.GetDrawBuffers()[0];
|
||||
@@ -1316,8 +1317,24 @@ void main() {
|
||||
return false;
|
||||
}
|
||||
if (attachment.IsRenderbuffer()) {
|
||||
MGLOG_E("BlitFramebuffer skipped: renderbuffer attachments are not supported yet");
|
||||
return false;
|
||||
const auto& renderbuffer = attachment.GetRenderbuffer();
|
||||
auto* rbResource = renderPassManager.GetOrCreateRenderbufferResource(renderbuffer);
|
||||
if (rbResource == nullptr || (rbResource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) == 0) {
|
||||
MGLOG_E("BlitFramebuffer skipped: %s framebuffer color renderbuffer %u is unsupported",
|
||||
outBinding.label, renderbuffer->GetExternalIndex());
|
||||
return false;
|
||||
}
|
||||
outBinding.image = rbResource->image;
|
||||
outBinding.trackedLayout = &rbResource->layout;
|
||||
outBinding.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
outBinding.format = rbResource->format;
|
||||
outBinding.extent = {static_cast<Int>(rbResource->extent.width),
|
||||
static_cast<Int>(rbResource->extent.height)};
|
||||
outBinding.mipLevel = 0;
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = 0;
|
||||
outBinding.layerCount = 1;
|
||||
return true;
|
||||
}
|
||||
if (!attachment.IsTexture()) {
|
||||
MGLOG_E("BlitFramebuffer skipped: unsupported framebuffer attachment type");
|
||||
@@ -1355,6 +1372,7 @@ void main() {
|
||||
static Bool ResolveFramebufferBlitBinding(MG_State::GLState::FramebufferObject& fbo, Bool isReadFramebuffer,
|
||||
Uint32 swapchainImageIndex, SwapchainObject& swapchainObject,
|
||||
VkTextureManager& textureManager,
|
||||
VkRenderPassManager& renderPassManager,
|
||||
VkImageAspectFlags requiredAspectMask,
|
||||
BlitImageBinding& outBinding) {
|
||||
const Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||
@@ -1398,8 +1416,29 @@ void main() {
|
||||
return false;
|
||||
}
|
||||
if (attachment.IsRenderbuffer()) {
|
||||
MGLOG_E("BlitFramebuffer skipped: renderbuffer attachments are not supported yet");
|
||||
return false;
|
||||
const auto& renderbuffer = attachment.GetRenderbuffer();
|
||||
auto* rbResource = renderPassManager.GetOrCreateRenderbufferResource(renderbuffer);
|
||||
if (rbResource == nullptr) {
|
||||
MGLOG_E("BlitFramebuffer skipped: %s framebuffer renderbuffer %u is unsupported",
|
||||
outBinding.label, renderbuffer->GetExternalIndex());
|
||||
return false;
|
||||
}
|
||||
if ((rbResource->aspect & requiredAspectMask) != requiredAspectMask) {
|
||||
MGLOG_E("BlitFramebuffer skipped: %s framebuffer renderbuffer %u is missing aspect mask=0x%x",
|
||||
outBinding.label, renderbuffer->GetExternalIndex(),
|
||||
static_cast<Uint32>(requiredAspectMask));
|
||||
return false;
|
||||
}
|
||||
outBinding.image = rbResource->image;
|
||||
outBinding.trackedLayout = &rbResource->layout;
|
||||
outBinding.aspectMask = requiredAspectMask;
|
||||
outBinding.extent = {static_cast<Int>(rbResource->extent.width),
|
||||
static_cast<Int>(rbResource->extent.height)};
|
||||
outBinding.mipLevel = 0;
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = 0;
|
||||
outBinding.layerCount = 1;
|
||||
return true;
|
||||
}
|
||||
if (!attachment.IsTexture()) {
|
||||
MGLOG_E("BlitFramebuffer skipped: unsupported framebuffer attachment type");
|
||||
@@ -1470,6 +1509,7 @@ void main() {
|
||||
static Bool ResolveTextureCopySourceBinding(MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex,
|
||||
SwapchainObject& swapchainObject,
|
||||
VkTextureManager& textureManager,
|
||||
VkRenderPassManager& renderPassManager,
|
||||
VkImageAspectFlags requiredAspectMask,
|
||||
BlitImageBinding& outBinding) {
|
||||
const Bool isDefaultFbo = fbo.IsDefaultFramebuffer();
|
||||
@@ -1514,8 +1554,30 @@ void main() {
|
||||
return false;
|
||||
}
|
||||
if (attachment.IsRenderbuffer()) {
|
||||
MGLOG_E("CopyTexSubImage2D skipped: renderbuffer read attachments are not supported yet");
|
||||
return false;
|
||||
const auto& renderbuffer = attachment.GetRenderbuffer();
|
||||
auto* rbResource = renderPassManager.GetOrCreateRenderbufferResource(renderbuffer);
|
||||
if (rbResource == nullptr) {
|
||||
MGLOG_E("CopyTexSubImage2D skipped: read framebuffer renderbuffer %u is unsupported",
|
||||
renderbuffer->GetExternalIndex());
|
||||
return false;
|
||||
}
|
||||
if ((rbResource->aspect & requiredAspectMask) != requiredAspectMask) {
|
||||
MGLOG_E("CopyTexSubImage2D skipped: read framebuffer renderbuffer %u aspect mask=0x%x "
|
||||
"does not satisfy requested mask=0x%x",
|
||||
renderbuffer->GetExternalIndex(), static_cast<Uint32>(rbResource->aspect),
|
||||
static_cast<Uint32>(requiredAspectMask));
|
||||
return false;
|
||||
}
|
||||
outBinding.image = rbResource->image;
|
||||
outBinding.trackedLayout = &rbResource->layout;
|
||||
outBinding.aspectMask = requiredAspectMask;
|
||||
outBinding.extent = {static_cast<Int>(rbResource->extent.width),
|
||||
static_cast<Int>(rbResource->extent.height)};
|
||||
outBinding.mipLevel = 0;
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = 0;
|
||||
outBinding.layerCount = 1;
|
||||
return true;
|
||||
}
|
||||
if (!attachment.IsTexture()) {
|
||||
MGLOG_E("CopyTexSubImage2D skipped: unsupported read framebuffer attachment type");
|
||||
@@ -3560,6 +3622,7 @@ void main() {
|
||||
(bufferMask.a() ? VK_COLOR_COMPONENT_A_BIT : 0u));
|
||||
Bool effectiveBlendEnabled = blendEnabled;
|
||||
MG_State::GLState::ITextureObject* colorAttachmentTexture = nullptr;
|
||||
MG_State::GLState::RenderbufferObject* colorAttachmentRenderbuffer = nullptr;
|
||||
if (isDefaultDrawFbo && i < drawBuffers.size() &&
|
||||
drawBuffers[i] == FramebufferAttachmentType::None) {
|
||||
// The default framebuffer spans the same MAX_DRAW_BUFFERS slots as an FBO
|
||||
@@ -3574,12 +3637,24 @@ void main() {
|
||||
if (!isDefaultDrawFbo && i < drawBuffers.size()) {
|
||||
const auto drawBuffer = drawBuffers[i];
|
||||
colorAttachmentTexture = resolveCompleteColorAttachmentTexture(i);
|
||||
if (drawBuffer == FramebufferAttachmentType::None || colorAttachmentTexture == nullptr) {
|
||||
if (colorAttachmentTexture == nullptr && drawBuffer != FramebufferAttachmentType::None) {
|
||||
const auto& attachment = drawFboBinding->GetAttachment(drawBuffer);
|
||||
if (attachment.IsRenderbuffer() && attachment.IsComplete()) {
|
||||
colorAttachmentRenderbuffer = attachment.GetRenderbuffer().get();
|
||||
}
|
||||
}
|
||||
if (drawBuffer == FramebufferAttachmentType::None ||
|
||||
(colorAttachmentTexture == nullptr && colorAttachmentRenderbuffer == nullptr)) {
|
||||
// GL ignores writes and per-target blend state for GL_NONE draw buffer slots.
|
||||
// Depth-only or otherwise unattached draw buffers should also discard color writes.
|
||||
attachmentColorWriteMask = 0;
|
||||
effectiveBlendEnabled = false;
|
||||
}
|
||||
if (colorAttachmentRenderbuffer != nullptr) {
|
||||
const SizeT componentCount = MG_Util::GetBaseInternalFormatComponentCount(
|
||||
colorAttachmentRenderbuffer->GetInternalFormat());
|
||||
attachmentColorWriteMask &= GetSupportedColorWriteMaskForComponentCount(componentCount);
|
||||
}
|
||||
if (colorAttachmentTexture != nullptr) {
|
||||
auto* texture = colorAttachmentTexture;
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
@@ -3656,10 +3731,14 @@ void main() {
|
||||
Int textureExternalIndex = -1;
|
||||
if (isDefaultDrawFbo) {
|
||||
colorAttachmentFormat = m_swapchainObject.GetSurfaceFormat().format;
|
||||
} else if (colorAttachmentRenderbuffer != nullptr) {
|
||||
textureExternalIndex = static_cast<Int>(colorAttachmentRenderbuffer->GetExternalIndex());
|
||||
colorAttachmentFormat = MG_Util::ConvertTextureInternalFormatToVkEnum(
|
||||
colorAttachmentRenderbuffer->GetInternalFormat());
|
||||
} else {
|
||||
auto* texture = colorAttachmentTexture;
|
||||
MOBILEGL_ASSERT(texture != nullptr,
|
||||
"GetOrCreatePipeline: blend is enabled on draw buffer %u but no complete texture attachment is bound",
|
||||
"GetOrCreatePipeline: blend is enabled on draw buffer %u but no complete color attachment is bound",
|
||||
i);
|
||||
textureExternalIndex = texture->GetExternalIndex();
|
||||
auto* textureResource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
||||
@@ -4810,6 +4889,98 @@ void main() {
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VulkanRenderer::MaterializePendingClearForRenderbuffer(
|
||||
VkCommandBuffer commandBuffer, const SharedPtr<MG_State::GLState::RenderbufferObject>& renderbuffer) {
|
||||
if (renderbuffer == nullptr) {
|
||||
return true;
|
||||
}
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
if (!m_renderPassManager->GetPendingRenderbufferClear(renderbuffer.get(), clearPayload)) {
|
||||
return true;
|
||||
}
|
||||
MOBILEGL_ASSERT(VkRenderPassManager::GetActiveRenderPass() == nullptr,
|
||||
"MaterializePendingClearForRenderbuffer requires no active render pass");
|
||||
|
||||
auto* resource = m_renderPassManager->GetOrCreateRenderbufferResource(renderbuffer);
|
||||
if (resource == nullptr) {
|
||||
MGLOG_E("MaterializePendingClearForRenderbuffer: no resource for renderbuffer %u",
|
||||
renderbuffer->GetExternalIndex());
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
GetImageTransitionSourceState(resource->layout, srcStageMask, srcAccessMask);
|
||||
|
||||
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, resource->image, resource->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, srcAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
resource->aspect, 0, 1, 1);
|
||||
MOBILEGL_ASSERT(ok,
|
||||
"MaterializePendingClearForRenderbuffer: failed to transition renderbuffer %u to TRANSFER_DST",
|
||||
renderbuffer->GetExternalIndex());
|
||||
|
||||
VkImageSubresourceRange subresourceRange{};
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
VkImageLayout steadyLayout;
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
VkClearColorValue clearValue{};
|
||||
clearValue.float32[0] = clearPayload.color.x();
|
||||
clearValue.float32[1] = clearPayload.color.y();
|
||||
clearValue.float32[2] = clearPayload.color.z();
|
||||
// RGB renderbuffers are backed by an RGBA image; the missing alpha reads as 1.
|
||||
clearValue.float32[3] =
|
||||
MG_Util::GetBaseInternalFormatComponentCount(renderbuffer->GetInternalFormat()) == 3 ?
|
||||
1.0f : clearPayload.color.w();
|
||||
vkCmdClearColorImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
&clearValue, 1, &subresourceRange);
|
||||
steadyLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
} else {
|
||||
VkImageAspectFlags clearAspectMask = 0;
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0 &&
|
||||
(clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
clearAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
|
||||
(clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||
clearAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
if (clearAspectMask != 0) {
|
||||
subresourceRange.aspectMask = clearAspectMask;
|
||||
VkClearDepthStencilValue clearValue{};
|
||||
clearValue.depth = clearPayload.depth;
|
||||
clearValue.stencil = clearPayload.stencil;
|
||||
vkCmdClearDepthStencilImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
&clearValue, 1, &subresourceRange);
|
||||
}
|
||||
steadyLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
VkImageLayout clearLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
ok = VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, resource->image, clearLayout, steadyLayout,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
resource->aspect, 0, 1, 1);
|
||||
MOBILEGL_ASSERT(ok,
|
||||
"MaterializePendingClearForRenderbuffer: failed to transition renderbuffer %u to steady layout",
|
||||
renderbuffer->GetExternalIndex());
|
||||
resource->layout = steadyLayout;
|
||||
|
||||
m_renderPassManager->PopPendingRenderbufferClear(renderbuffer.get());
|
||||
MGLOG_D("MaterializePendingClearForRenderbuffer: renderbuffer %u pending clear materialized",
|
||||
renderbuffer->GetExternalIndex());
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VulkanRenderer::TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,
|
||||
MG_State::GLState::FramebufferObject& readFbo,
|
||||
MG_State::GLState::FramebufferObject& drawFbo,
|
||||
@@ -4823,8 +4994,10 @@ void main() {
|
||||
|
||||
BlitImageBinding srcBinding{};
|
||||
BlitImageBinding dstBinding{};
|
||||
if (!ResolveColorBlitBinding(readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager, srcBinding) ||
|
||||
!ResolveColorBlitBinding(drawFbo, false, m_imageIndexAcquired, m_swapchainObject, *m_textureManager, dstBinding)) {
|
||||
if (!ResolveColorBlitBinding(readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||
*m_renderPassManager, srcBinding) ||
|
||||
!ResolveColorBlitBinding(drawFbo, false, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||
*m_renderPassManager, dstBinding)) {
|
||||
return false;
|
||||
}
|
||||
if (srcBinding.trackedLayout == nullptr) {
|
||||
@@ -5010,9 +5183,11 @@ void main() {
|
||||
BlitImageBinding srcBinding{};
|
||||
BlitImageBinding dstBinding{};
|
||||
if (!ResolveFramebufferBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject,
|
||||
*m_textureManager, VK_IMAGE_ASPECT_DEPTH_BIT, srcBinding) ||
|
||||
*m_textureManager, *m_renderPassManager,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT, srcBinding) ||
|
||||
!ResolveFramebufferBlitBinding(*drawFbo, false, m_imageIndexAcquired, m_swapchainObject,
|
||||
*m_textureManager, VK_IMAGE_ASPECT_DEPTH_BIT, dstBinding)) {
|
||||
*m_textureManager, *m_renderPassManager,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT, dstBinding)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5177,8 +5352,10 @@ void main() {
|
||||
|
||||
BlitImageBinding srcBinding{};
|
||||
BlitImageBinding dstBinding{};
|
||||
if (!ResolveColorBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager, srcBinding) ||
|
||||
!ResolveColorBlitBinding(*drawFbo, false, m_imageIndexAcquired, m_swapchainObject, *m_textureManager, dstBinding)) {
|
||||
if (!ResolveColorBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||
*m_renderPassManager, srcBinding) ||
|
||||
!ResolveColorBlitBinding(*drawFbo, false, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||
*m_renderPassManager, dstBinding)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5382,7 +5559,7 @@ void main() {
|
||||
|
||||
BlitImageBinding srcBinding{};
|
||||
if (!ResolveTextureCopySourceBinding(*readFbo, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||
dstBinding.aspectMask, srcBinding)) {
|
||||
*m_renderPassManager, dstBinding.aspectMask, srcBinding)) {
|
||||
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
|
||||
"CopyTexSubImage2D requires a complete read attachment compatible with the destination texture.");
|
||||
return;
|
||||
@@ -5723,7 +5900,7 @@ void main() {
|
||||
const Bool readIsDefaultFbo = readFbo->IsDefaultFramebuffer();
|
||||
BlitImageBinding srcBinding{};
|
||||
if (!ResolveColorBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||
srcBinding)) {
|
||||
*m_renderPassManager, srcBinding)) {
|
||||
return;
|
||||
}
|
||||
if (!readIsDefaultFbo) {
|
||||
@@ -5734,6 +5911,12 @@ void main() {
|
||||
MOBILEGL_ASSERT(clearReady,
|
||||
"ReadPixels: failed to materialize pending clear for source textureId=%d",
|
||||
sourceTexture->GetExternalIndex());
|
||||
} else if (sourceAttachment.IsRenderbuffer()) {
|
||||
const Bool clearReady =
|
||||
MaterializePendingClearForRenderbuffer(frame.commandBuffer, sourceAttachment.GetRenderbuffer());
|
||||
MOBILEGL_ASSERT(clearReady,
|
||||
"ReadPixels: failed to materialize pending clear for source renderbuffer %u",
|
||||
sourceAttachment.GetRenderbuffer()->GetExternalIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -561,6 +561,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
GLenum filter);
|
||||
Bool MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
||||
MG_State::GLState::ITextureObject& texture);
|
||||
Bool MaterializePendingClearForRenderbuffer(
|
||||
VkCommandBuffer commandBuffer,
|
||||
const SharedPtr<MG_State::GLState::RenderbufferObject>& renderbuffer);
|
||||
VkPipeline GetOrCreateBlitPipeline(const RenderPassEntry& renderPassEntry);
|
||||
Bool GenerateDepthMipmapWithShader(FrameContext::FrameData& frame,
|
||||
MG_State::GLState::ITextureObject& texture,
|
||||
|
||||
Reference in New Issue
Block a user