blob: 67a8c5d6a0d406ece054d98198ecaf878bcc9f4b [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/graphite/vk/VulkanRenderPass.h"
#include "include/gpu/graphite/vk/VulkanGraphiteTypes.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/Texture.h"
#include "src/gpu/graphite/vk/VulkanCommandBuffer.h"
#include "src/gpu/graphite/vk/VulkanGraphiteUtils.h"
#include "src/gpu/graphite/vk/VulkanSharedContext.h"
#include "src/gpu/graphite/vk/VulkanTexture.h"
#include <limits>
static constexpr uint32_t kColorFormatOffset = 0;
static constexpr uint32_t kDepthStencilFormatOffset = kColorFormatOffset + 8;
static constexpr uint32_t kSampleCountOffset = kDepthStencilFormatOffset + 8;
static constexpr uint32_t kColorLoadOpOffset = kSampleCountOffset + 5;
static constexpr uint32_t kColorStoreOpOffset = kColorLoadOpOffset + 2;
static constexpr uint32_t kResolveLoadOpOffset = kColorStoreOpOffset + 1;
static constexpr uint32_t kResolveStoreOpOffset = kResolveLoadOpOffset + 2;
static constexpr uint32_t kMSRTTOffset = kResolveStoreOpOffset + 1;
static constexpr uint32_t kFormatMask = 0xFF;
static constexpr uint32_t kSampleCountMask = 0x1F;
static constexpr uint32_t kLoadOpMask = 0x3;
static constexpr uint32_t kStoreOpMask = 0x1;
static constexpr uint32_t kMSRTTMask = 0x1;
namespace skgpu::graphite {
uint32_t VulkanRenderPass::GetRenderPassKey(const RenderPassDesc& originalRenderPassDesc,
bool compatibleForPipelineKey) {
const RenderPassDesc renderPassDesc =
compatibleForPipelineKey ? MakePipelineCompatibleRenderPass(originalRenderPassDesc)
: originalRenderPassDesc;
const AttachmentDesc color = renderPassDesc.fColorAttachment;
const AttachmentDesc resolve = renderPassDesc.fColorResolveAttachment;
const AttachmentDesc depthStencil = renderPassDesc.fDepthStencilAttachment;
const bool hasResolveAttachment = resolve.fFormat != TextureFormat::kUnsupported;
const bool isMultisampledRenderToSingleSampled =
RenderPassDescWillImplicitlyLoadMSAA(renderPassDesc);
// Silence warning about unused variable in release builds.
(void)hasResolveAttachment;
// Current assumptions in the render pass desc, allowing us to create a smaller key:
SkASSERT(color.fFormat != TextureFormat::kUnsupported);
SkASSERT(!hasResolveAttachment || resolve.fFormat == color.fFormat);
SkASSERT(depthStencil.fFormat == TextureFormat::kUnsupported ||
depthStencil.fSampleCount == color.fSampleCount);
SkASSERT(depthStencil.fFormat == TextureFormat::kUnsupported ||
depthStencil.fLoadOp == LoadOp::kClear);
SkASSERT(depthStencil.fFormat == TextureFormat::kUnsupported ||
depthStencil.fStoreOp == StoreOp::kDiscard);
SkASSERT(!hasResolveAttachment || resolve.fSampleCount == 1);
SkASSERT(color.fSampleCount == renderPassDesc.fSampleCount ||
isMultisampledRenderToSingleSampled);
SkASSERT(!hasResolveAttachment || color.fLoadOp == LoadOp::kDiscard ||
color.fLoadOp == LoadOp::kClear);
SkASSERT(!hasResolveAttachment || resolve.fLoadOp == LoadOp::kDiscard ||
resolve.fLoadOp == LoadOp::kLoad);
SkASSERT(!hasResolveAttachment || color.fStoreOp == StoreOp::kDiscard);
// The following information uniquely defines the render pass:
//
// Color format (CF): TextureFormat, fits in 6 bits
// Depth/stencil format (DSF): TextureFormat, fits in 6 bits
// Sample count (M): Up to 16, fits in 5 bit
// Color load op (L): LoadOp, fits in 2 bits
// Color store op (S): StoreOp, fits in 1 bit
// Whether multisampled data s loaded from resolve attachment: fits in 1 bit
// Whether rendering multisampled->single-sampled (MSRTSS): fits in 1 bit
//
// Note that technically, renderable color formats can fit in 5 bits and depth/stencil formats
// in 3 bits if more packing is needed. Sample count can also be `log()`'ed to reduce the bit
// count.
//
// Depth/stencil load op is always kClear, and store op is always kDiscard.
// Color load op is either found in fColorAttachment if no resolve attachment, or can be derived
// from a combination of the load ops specified in the color and resolve attachments:
// * If color attachment is kClear, load op is kClear
// * Otherwise, if resolve attachment is kLoad, load op is kLoad
// * Otherwise, it's kDiscard
// Color store op is either found in fColorAttachment if no resolve attachment, or it's found in
// fColorResolveAttachment.
//
// There are currently lots of free bits, so with regards to load/store ops, we don't try too
// hard to pack things. Including the color and resolve's load and store ops obviates the need
// to store a "load MSAA from resolve" bit. The format of the key is thus:
//
// LSB MSB
// +----+-----+---+---+---+------------+------------+--------+---+
// | CF | DSF | M | L | S | L(resolve) | S(resolve) | MSRTSS | 0 |
// +----+-----+---+---+---+------------+------------+--------+---+
// bits 8 8 5 2 1 2 1 1 4
//
SkASSERT(renderPassDesc.fSampleCount < (1 << 5));
static_assert(static_cast<uint32_t>(TextureFormat::kLast) < (1 << 8));
static_assert(static_cast<uint32_t>(LoadOp::kLast) < (1 << 2));
static_assert(static_cast<uint32_t>(StoreOp::kLast) < (1 << 1));
const uint32_t key =
(static_cast<uint32_t>(color.fFormat) << kColorFormatOffset) |
(static_cast<uint32_t>(depthStencil.fFormat) << kDepthStencilFormatOffset) |
(static_cast<uint32_t>(renderPassDesc.fSampleCount) << kSampleCountOffset) |
(static_cast<uint32_t>(color.fLoadOp) << kColorLoadOpOffset) |
(static_cast<uint32_t>(color.fStoreOp) << kColorStoreOpOffset) |
(static_cast<uint32_t>(resolve.fLoadOp) << kResolveLoadOpOffset) |
(static_cast<uint32_t>(resolve.fStoreOp) << kResolveStoreOpOffset) |
(static_cast<uint32_t>(isMultisampledRenderToSingleSampled) << kMSRTTOffset);
return key;
}
void VulkanRenderPass::ExtractRenderPassDesc(uint32_t key,
Swizzle writeSwizzle,
DstReadStrategy dstReadStrategy,
RenderPassDesc* renderPassDesc) {
// See comment in GetRenderPassKey() describing the format of the key.
const TextureFormat colorFormat =
SkTo<TextureFormat>((key >> kColorFormatOffset) & kFormatMask);
const TextureFormat depthStencilFormat =
SkTo<TextureFormat>((key >> kDepthStencilFormatOffset) & kFormatMask);
const uint8_t sampleCount = SkTo<uint8_t>((key >> kSampleCountOffset) & kSampleCountMask);
const LoadOp colorLoadOp = SkTo<LoadOp>((key >> kColorLoadOpOffset) & kLoadOpMask);
const StoreOp colorStoreOp = SkTo<StoreOp>((key >> kColorStoreOpOffset) & kStoreOpMask);
const LoadOp resolveLoadOp = SkTo<LoadOp>((key >> kResolveLoadOpOffset) & kLoadOpMask);
const StoreOp resolveStoreOp = SkTo<StoreOp>((key >> kResolveStoreOpOffset) & kStoreOpMask);
const bool isMultisampledRenderToSingleSampled = SkTo<bool>((key >> kMSRTTOffset) & kMSRTTMask);
// Relationship between render pass sample count, attachment's sample counts and resolve
// attachments:
//
// | RP Samples == 1 | RP Samples > 1 && MSRTSS | RP Samples > 1 && !MSRTSS |
// +-----------------+--------------------------+---------------------------+
// Has Resolve? | No | No | Yes |
// +-----------------+--------------------------+---------------------------+
// Resolve Format | Unsupported | Unsupported | Color Format |
// +-----------------+--------------------------+---------------------------+
// Color Samples | RP Samples (1) | 1 | RP Samples |
// +-----------------+--------------------------+---------------------------+
// D/S Samples | RP Samples (1) | 1 | RP Samples |
// +-----------------+--------------------------+---------------------------+
//
// The color and resolve attachment's load/store op are already stored in the key. For
// depth/stencil, load op is always Clear and store op is always Discard.
const uint8_t attachmentSamples = isMultisampledRenderToSingleSampled ? 1 : sampleCount;
*renderPassDesc = {};
renderPassDesc->fColorAttachment = {colorFormat, colorLoadOp, colorStoreOp, attachmentSamples};
renderPassDesc->fDepthStencilAttachment = {
depthStencilFormat, LoadOp::kClear, StoreOp::kDiscard, attachmentSamples};
if (attachmentSamples > 1 && !isMultisampledRenderToSingleSampled) {
renderPassDesc->fColorResolveAttachment = {colorFormat,
resolveLoadOp,
resolveStoreOp,
/*fSampleCount=*/1};
}
renderPassDesc->fSampleCount = sampleCount;
renderPassDesc->fWriteSwizzle = writeSwizzle;
renderPassDesc->fDstReadStrategy = dstReadStrategy;
}
namespace {
template <typename AttachmentDescription>
void setup_vk_attachment_description(AttachmentDescription* outAttachment,
const AttachmentDesc& desc,
const AttachmentDescription& defaultAttachmentDescription,
bool isColor) {
static_assert((int) LoadOp::kLoad == (int) VK_ATTACHMENT_LOAD_OP_LOAD);
static_assert((int) LoadOp::kClear == (int) VK_ATTACHMENT_LOAD_OP_CLEAR);
static_assert((int) LoadOp::kDiscard == (int) VK_ATTACHMENT_LOAD_OP_DONT_CARE);
static_assert((int) StoreOp::kStore == (int) VK_ATTACHMENT_STORE_OP_STORE);
static_assert((int) StoreOp::kDiscard == (int) VK_ATTACHMENT_STORE_OP_DONT_CARE);
VkAttachmentLoadOp vkLoadOp = static_cast<VkAttachmentLoadOp>(desc.fLoadOp);
VkAttachmentStoreOp vkStoreOp = static_cast<VkAttachmentStoreOp>(desc.fStoreOp);
*outAttachment = defaultAttachmentDescription;
outAttachment->format = TextureFormatToVkFormat(desc.fFormat);
VkSampleCountFlagBits sampleCount;
SkAssertResult(SampleCountToVkSampleCount(desc.fSampleCount, &sampleCount));
outAttachment->samples = sampleCount;
outAttachment->loadOp = vkLoadOp;
outAttachment->storeOp = vkStoreOp;
if (isColor) {
outAttachment->initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
outAttachment->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
outAttachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
outAttachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
} else {
outAttachment->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
outAttachment->finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
outAttachment->stencilLoadOp = vkLoadOp;
outAttachment->stencilStoreOp = vkStoreOp;
}
}
template <typename AttachmentDescription, typename AttachmentReference>
void populate_attachment_refs(const RenderPassDesc& renderPassDesc,
bool needLoadMSAAFromResolveSubpass,
skia_private::TArray<AttachmentDescription>& descs,
AttachmentReference& colorRef,
AttachmentReference& resolveRef,
AttachmentReference& resolveLoadInputRef,
AttachmentReference& depthStencilRef,
const AttachmentDescription& defaultAttachmentDescription) {
// Note: See assumptions regarding RenderPassDesc structure in AddToKey().
const AttachmentDesc color = renderPassDesc.fColorAttachment;
const AttachmentDesc resolve = renderPassDesc.fColorResolveAttachment;
const AttachmentDesc depthStencil = renderPassDesc.fDepthStencilAttachment;
SkASSERT(color.fFormat != TextureFormat::kUnsupported);
// If MSAA data needs to be loaded from the resolve attachment, there must be a resolve
// attachment!
SkASSERT(!needLoadMSAAFromResolveSubpass || resolve.fFormat != TextureFormat::kUnsupported);
// If reading from the dst as an input attachment, we must use VK_IMAGE_LAYOUT_GENERAL
// for the color attachment description. Use a general image layout for all renderpasses to
// support this.
//
// As long as the initial/final layouts are VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, the
// choice of the VK_IMAGE_LAYOUT_GENERAL for the subpass layout is efficient; the few GPUs
// that treat VK_IMAGE_LAYOUT_GENERAL differently recognize this pattern and keep the
// internal layout optimal.
colorRef.layout = VK_IMAGE_LAYOUT_GENERAL;
colorRef.attachment = descs.size();
AttachmentDescription& vkColorAttachDesc = descs.push_back();
setup_vk_attachment_description(&vkColorAttachDesc,
color,
defaultAttachmentDescription,
/*isColor=*/true);
if (resolve.fFormat != TextureFormat::kUnsupported) {
resolveRef.attachment = descs.size();
resolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (needLoadMSAAFromResolveSubpass) {
resolveLoadInputRef.attachment = resolveRef.attachment;
// The resolve attachment is used as input attachment in the first subpass. In that
// subpass, it is only read from so the layout could have been read-only. To avoid
// special-casing this input attachment though, the VK_IMAGE_LAYOUT_GENERAL layout
// is used like with the color attachment. This is no less efficient than the
// read-only layout when specified on the attachment ref.
resolveLoadInputRef.layout = VK_IMAGE_LAYOUT_GENERAL;
} else {
resolveLoadInputRef.attachment = VK_ATTACHMENT_UNUSED;
}
AttachmentDescription& vkResolveAttachDesc = descs.push_back();
setup_vk_attachment_description(&vkResolveAttachDesc,
resolve,
defaultAttachmentDescription,
/*isColor=*/true);
} else {
resolveRef.attachment = resolveLoadInputRef.attachment = VK_ATTACHMENT_UNUSED;
}
if (depthStencil.fFormat != TextureFormat::kUnsupported) {
depthStencilRef.attachment = descs.size();
depthStencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
AttachmentDescription& vkDepthStencilAttachDesc = descs.push_back();
setup_vk_attachment_description(&vkDepthStencilAttachDesc,
depthStencil,
defaultAttachmentDescription,
/*isColor=*/false);
} else {
depthStencilRef.attachment = VK_ATTACHMENT_UNUSED;
}
}
template <typename SubpassDependency, typename SubpassDependencyArray>
void populate_subpass_dependencies(const VulkanSharedContext* context,
SubpassDependencyArray& deps,
bool needLoadMSAAFromResolveSubpass,
const SubpassDependency& defaultSubpassDependency) {
const int mainSubpassIdx = needLoadMSAAFromResolveSubpass ? 1 : 0;
// Adding a single subpass self-dependency for color attachments is basically free, so apply
// one to every RenderPass which has an input attachment on the main subpass. This is useful
// because it means that as we perform draw calls, if we encounter a draw that uses a blend
// operation requiring a dst read, we can avoid having to switch RenderPasses.
const bool hasRasterizationOrderColorAttachmentAccess =
context->vulkanCaps().supportsRasterizationOrderColorAttachmentAccess();
const bool hasNonCoherentAdvancedBlend = context->vulkanCaps().blendEquationSupport() ==
Caps::BlendEquationSupport::kAdvancedNoncoherent;
if (!hasRasterizationOrderColorAttachmentAccess || hasNonCoherentAdvancedBlend) {
SubpassDependency& selfDependency = deps.push_back();
selfDependency = defaultSubpassDependency;
selfDependency.srcSubpass = mainSubpassIdx;
selfDependency.dstSubpass = mainSubpassIdx;
selfDependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
selfDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
selfDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
selfDependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
selfDependency.dstAccessMask = 0;
if (!hasRasterizationOrderColorAttachmentAccess) {
selfDependency.dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
selfDependency.dstAccessMask |= VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
}
if (hasNonCoherentAdvancedBlend) {
selfDependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT;
}
}
// If loading MSAA from resolve, enforce that subpass goes first with a subpass dependency.
if (needLoadMSAAFromResolveSubpass) {
SubpassDependency& dependency = deps.push_back();
dependency = defaultSubpassDependency;
dependency.srcSubpass = 0;
dependency.dstSubpass = mainSubpassIdx;
dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
}
template <typename SubpassDescription, typename AttachmentReference>
void populate_main_subpass_desc(const VulkanCaps& caps,
SubpassDescription& mainSubpassDesc,
const AttachmentReference& colorRef,
const AttachmentReference& resolveRef,
const AttachmentReference& depthStencilRef) {
mainSubpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
// In the main subpass, the input attachment is the color attachment. We could have excluded
// this attachment if unused, but always assigning it to be the color attachment even when
// unused allows for compatible-only renderpasses to be shared for pipelines that do read from
// the dst and those that do not.
mainSubpassDesc.inputAttachmentCount = 1;
mainSubpassDesc.pInputAttachments = &colorRef;
mainSubpassDesc.colorAttachmentCount = 1;
mainSubpassDesc.pColorAttachments = &colorRef;
mainSubpassDesc.pResolveAttachments = &resolveRef;
mainSubpassDesc.pDepthStencilAttachment = &depthStencilRef;
}
void populate_subpass_descs(const VulkanCaps& caps,
skia_private::TArray<VkSubpassDescription>& descs,
const VkAttachmentReference& colorRef,
const VkAttachmentReference& resolveRef,
const VkAttachmentReference& resolveLoadInputRef,
const VkAttachmentReference& depthStencilRef) {
// If loading MSAA from resolve, add the additional subpass to do so.
if (resolveLoadInputRef.attachment != VK_ATTACHMENT_UNUSED) {
VkSubpassDescription& loadSubpassDesc = descs.push_back();
loadSubpassDesc = {};
loadSubpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
loadSubpassDesc.inputAttachmentCount = 1;
loadSubpassDesc.pInputAttachments = &resolveLoadInputRef;
loadSubpassDesc.colorAttachmentCount = 1;
loadSubpassDesc.pColorAttachments = &colorRef;
}
VkSubpassDescription& mainSubpassDesc = descs.push_back();
mainSubpassDesc = {};
populate_main_subpass_desc(caps, mainSubpassDesc, colorRef, resolveRef, depthStencilRef);
if (caps.supportsRasterizationOrderColorAttachmentAccess()) {
for (VkSubpassDescription& desc : descs) {
desc.flags = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT;
}
}
}
} // anonymous namespace
sk_sp<VulkanRenderPass> VulkanRenderPass::Make(const VulkanSharedContext* context,
const RenderPassDesc& renderPassDesc) {
const bool needLoadMSAAFromResolveSubpass =
RenderPassDescWillLoadMSAAFromResolve(renderPassDesc);
const bool isMultisampledRenderToSingleSampled =
RenderPassDescWillImplicitlyLoadMSAA(renderPassDesc);
VkResult result;
VkRenderPass renderPass = VK_NULL_HANDLE;
// VK_EXT_multisampled_render_to_single_sampled usage requires vkCreateRenderPass2.
if (isMultisampledRenderToSingleSampled) {
// Set up attachment descriptions + references. Declare them before having a helper populate
// their values so we can reference them later during RP creation.
SkASSERT(renderPassDesc.fColorResolveAttachment.fFormat == TextureFormat::kUnsupported);
SkASSERT(!needLoadMSAAFromResolveSubpass);
VkAttachmentDescription2 defaultAttachmentDescription = {};
defaultAttachmentDescription.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
VkAttachmentReference2 defaultAttachmentReference = {};
defaultAttachmentReference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
defaultAttachmentReference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
skia_private::TArray<VkAttachmentDescription2> attachmentDescs;
VkAttachmentReference2 colorRef = defaultAttachmentReference;
VkAttachmentReference2 resolveRef = defaultAttachmentReference;
VkAttachmentReference2 resolveLoadInputRef = defaultAttachmentReference;
VkAttachmentReference2 depthStencilRef = defaultAttachmentReference;
depthStencilRef.aspectMask =
GetVkImageAspectFlags(renderPassDesc.fDepthStencilAttachment.fFormat);
populate_attachment_refs(renderPassDesc,
/*needLoadMSAAFromResolveSubpass=*/false,
attachmentDescs,
colorRef,
resolveRef,
resolveLoadInputRef,
depthStencilRef,
defaultAttachmentDescription);
SkASSERT(resolveLoadInputRef.attachment == VK_ATTACHMENT_UNUSED);
// Assemble subpass information before creating the renderpass. Each renderpass has at least
// one subpass dependency (self-dependency for reading the dst texture).
VkSubpassDescription2 mainSubpassDesc = {};
mainSubpassDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
populate_main_subpass_desc(
context->vulkanCaps(), mainSubpassDesc, colorRef, resolveRef, depthStencilRef);
// Enable multisampled render to single-sampled with the render pass's sample count.
VkMultisampledRenderToSingleSampledInfoEXT msrtss = {};
msrtss.sType = VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT;
msrtss.multisampledRenderToSingleSampledEnable = VK_TRUE;
SampleCountToVkSampleCount(renderPassDesc.fSampleCount, &msrtss.rasterizationSamples);
AddToPNextChain(&mainSubpassDesc, &msrtss);
// Depth/stencil resolve needs additional configuration (even though Graphite always
// discards depth/stencil).
SkASSERT(renderPassDesc.fDepthStencilAttachment.fStoreOp == StoreOp::kDiscard);
VkSubpassDescriptionDepthStencilResolve dsResolve = {};
dsResolve.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
dsResolve.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
dsResolve.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
AddToPNextChain(&mainSubpassDesc, &dsResolve);
VkSubpassDependency2 defaultSubpassDependency = {};
defaultSubpassDependency.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
skia_private::STArray<1, VkSubpassDependency2> dependencies;
populate_subpass_dependencies(context,
dependencies,
/*needLoadMSAAFromResolveSubpass=*/false,
defaultSubpassDependency);
// Create VkRenderPass
VkRenderPassCreateInfo2 renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &mainSubpassDesc;
renderPassInfo.dependencyCount = dependencies.size();
renderPassInfo.pDependencies = dependencies.data();
renderPassInfo.attachmentCount = attachmentDescs.size();
renderPassInfo.pAttachments = attachmentDescs.data();
VULKAN_CALL_RESULT(
context,
result,
CreateRenderPass2(context->device(), &renderPassInfo, nullptr, &renderPass));
} else {
// Same thing as above, but using Vulkan 1.0 render pass API. Practically every usable
// driver supports VK_KHR_create_renderpass2, but that is not yet a minimum requirement of
// Graphite.
skia_private::TArray<VkAttachmentDescription> attachmentDescs;
VkAttachmentReference colorRef = {};
VkAttachmentReference resolveRef = {};
VkAttachmentReference resolveLoadInputRef = {};
VkAttachmentReference depthStencilRef = {};
populate_attachment_refs(renderPassDesc,
needLoadMSAAFromResolveSubpass,
attachmentDescs,
colorRef,
resolveRef,
resolveLoadInputRef,
depthStencilRef,
/*defaultAttachmentDescription=*/{});
// If loading MSAA from resolve, an extra subpass and an additional dependency is needed.
skia_private::STArray<2, VkSubpassDescription> subpassDescs;
populate_subpass_descs(context->vulkanCaps(),
subpassDescs,
colorRef,
resolveRef,
resolveLoadInputRef,
depthStencilRef);
skia_private::STArray<2, VkSubpassDependency> dependencies;
populate_subpass_dependencies(context,
dependencies,
needLoadMSAAFromResolveSubpass,
/*defaultSubpassDependency=*/VkSubpassDependency{});
// Create VkRenderPass
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.subpassCount = subpassDescs.size();
renderPassInfo.pSubpasses = subpassDescs.begin();
renderPassInfo.dependencyCount = dependencies.size();
renderPassInfo.pDependencies = dependencies.data();
renderPassInfo.attachmentCount = attachmentDescs.size();
renderPassInfo.pAttachments = attachmentDescs.data();
VULKAN_CALL_RESULT(
context,
result,
CreateRenderPass(context->device(), &renderPassInfo, nullptr, &renderPass));
}
if (result != VK_SUCCESS) {
return nullptr;
}
VkExtent2D granularity;
VULKAN_CALL(context->interface(), GetRenderAreaGranularity(context->device(),
renderPass,
&granularity));
return sk_sp<VulkanRenderPass>(new VulkanRenderPass(context, renderPass, granularity));
}
VulkanRenderPass::VulkanRenderPass(const VulkanSharedContext* context,
VkRenderPass renderPass,
VkExtent2D granularity)
: Resource(context,
Ownership::kOwned,
/*gpuMemorySize=*/0)
, fSharedContext(context)
, fRenderPass(renderPass)
, fGranularity(granularity) {}
void VulkanRenderPass::freeGpuData() {
VULKAN_CALL(fSharedContext->interface(),
DestroyRenderPass(fSharedContext->device(), fRenderPass, nullptr));
}
} // namespace skgpu::graphite