CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/GPU/Vulkan/VulkanFramebuffer.cpp
Views: 1401
#include "Common/StringUtils.h"1#include "Common/GPU/Vulkan/VulkanFramebuffer.h"2#include "Common/GPU/Vulkan/VulkanQueueRunner.h"34static const char * const rpTypeDebugNames[] = {5"RENDER",6"RENDER_DEPTH",7"MV_RENDER",8"MV_RENDER_DEPTH",9"MS_RENDER",10"MS_RENDER_DEPTH",11"MS_MV_RENDER",12"MS_MV_RENDER_DEPTH",13"BACKBUF",14};1516const char *GetRPTypeName(RenderPassType rpType) {17uint32_t index = (uint32_t)rpType;18if (index < ARRAY_SIZE(rpTypeDebugNames)) {19return rpTypeDebugNames[index];20} else {21return "N/A";22}23}2425VkSampleCountFlagBits MultiSampleLevelToFlagBits(int count) {26// TODO: Check hardware support here, or elsewhere?27// Some hardware only supports 4x.28switch (count) {29case 0: return VK_SAMPLE_COUNT_1_BIT;30case 1: return VK_SAMPLE_COUNT_2_BIT;31case 2: return VK_SAMPLE_COUNT_4_BIT; // The only non-1 level supported on some mobile chips.32case 3: return VK_SAMPLE_COUNT_8_BIT;33case 4: return VK_SAMPLE_COUNT_16_BIT; // rare but exists, on Intel for example34default:35_assert_(false);36return VK_SAMPLE_COUNT_1_BIT;37}38}3940void VKRImage::Delete(VulkanContext *vulkan) {41// Get rid of the views first, feels cleaner (but in reality doesn't matter).42if (rtView)43vulkan->Delete().QueueDeleteImageView(rtView);44if (texAllLayersView)45vulkan->Delete().QueueDeleteImageView(texAllLayersView);46for (int i = 0; i < 2; i++) {47if (texLayerViews[i]) {48vulkan->Delete().QueueDeleteImageView(texLayerViews[i]);49}50}5152if (image) {53_dbg_assert_(alloc);54vulkan->Delete().QueueDeleteImageAllocation(image, alloc);55}56}5758VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VulkanBarrierBatch *barriers, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag)59: vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) {6061_dbg_assert_(tag);6263CreateImage(vulkan_, barriers, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);64if (createDepthStencilBuffer) {65CreateImage(vulkan_, barriers, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag);66}6768if (_multiSampleLevel > 0) {69sampleCount = MultiSampleLevelToFlagBits(_multiSampleLevel);7071// TODO: Create a different tag for these?72CreateImage(vulkan_, barriers, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);73if (createDepthStencilBuffer) {74CreateImage(vulkan_, barriers, initCmd, msaaDepth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag);75}76} else {77sampleCount = VK_SAMPLE_COUNT_1_BIT;78}7980UpdateTag(tag);8182// We create the actual framebuffer objects on demand, because some combinations might not make sense.83// Framebuffer objects are just pointers to a set of images, so no biggie.84}8586void VKRFramebuffer::UpdateTag(const char *newTag) {87char name[128];88snprintf(name, sizeof(name), "fb_color_%s", tag_.c_str());89vulkan_->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, name);90vulkan_->SetDebugName(color.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name);91if (depth.image) {92snprintf(name, sizeof(name), "fb_depth_%s", tag_.c_str());93vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, name);94vulkan_->SetDebugName(depth.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, name);95}96for (size_t rpType = 0; rpType < (size_t)RenderPassType::TYPE_COUNT; rpType++) {97if (framebuf[rpType]) {98snprintf(name, sizeof(name), "fb_%s", tag_.c_str());99vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name);100}101}102}103104VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) {105bool multiview = RenderPassTypeHasMultiView(rpType);106107if (framebuf[(int)rpType]) {108return framebuf[(int)rpType];109}110111VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };112VkImageView views[4]{};113114bool hasDepth = RenderPassTypeHasDepth(rpType);115int attachmentCount = 0;116views[attachmentCount++] = color.rtView; // 2D array texture if multilayered.117if (hasDepth) {118if (!depth.rtView) {119WARN_LOG(Log::G3D, "depth render type to non-depth fb: %p %p fmt=%d (%s %dx%d)", (void *)depth.image, (void *)depth.texAllLayersView, depth.format, tag_.c_str(), width, height);120// Will probably crash, depending on driver.121}122views[attachmentCount++] = depth.rtView;123}124if (rpType & RenderPassType::MULTISAMPLE) {125views[attachmentCount++] = msaaColor.rtView;126if (hasDepth) {127views[attachmentCount++] = msaaDepth.rtView;128}129}130131fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType, sampleCount);132fbci.attachmentCount = attachmentCount;133fbci.pAttachments = views;134fbci.width = width;135fbci.height = height;136fbci.layers = 1; // With multiview, this should be set as 1.137138VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]);139_assert_(res == VK_SUCCESS);140141if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) {142vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str());143}144145return framebuf[(int)rpType];146}147148VKRFramebuffer::~VKRFramebuffer() {149color.Delete(vulkan_);150depth.Delete(vulkan_);151msaaColor.Delete(vulkan_);152msaaDepth.Delete(vulkan_);153154for (auto &fb : framebuf) {155if (fb) {156vulkan_->Delete().QueueDeleteFramebuffer(fb);157}158}159}160161// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture.162// This requires a different sampling path!163void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VulkanBarrierBatch *barriers, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) {164// We don't support more exotic layer setups for now. Mono or stereo.165_dbg_assert_(numLayers == 1 || numLayers == 2);166167VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };168ici.arrayLayers = numLayers;169ici.mipLevels = 1;170ici.extent.width = width;171ici.extent.height = height;172ici.extent.depth = 1;173ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;174ici.imageType = VK_IMAGE_TYPE_2D;175ici.samples = sampleCount;176ici.tiling = VK_IMAGE_TILING_OPTIMAL;177ici.format = format;178ici.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;179if (sampleCount == VK_SAMPLE_COUNT_1_BIT) {180ici.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;181}182if (color) {183ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;184} else {185ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;186}187188VmaAllocationCreateInfo allocCreateInfo{};189allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;190VmaAllocationInfo allocInfo{};191192VkResult res = vmaCreateImage(vulkan->Allocator(), &ici, &allocCreateInfo, &img.image, &img.alloc, &allocInfo);193_dbg_assert_(res == VK_SUCCESS);194195vulkan->SetDebugName(img.image, VK_OBJECT_TYPE_IMAGE, tag);196197VkImageAspectFlags aspects = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);198199VkImageViewCreateInfo ivci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };200ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };201ivci.format = ici.format;202ivci.image = img.image;203ivci.viewType = numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY;204ivci.subresourceRange.aspectMask = aspects;205ivci.subresourceRange.layerCount = numLayers;206ivci.subresourceRange.levelCount = 1;207res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.rtView);208vulkan->SetDebugName(img.rtView, VK_OBJECT_TYPE_IMAGE_VIEW, tag);209_dbg_assert_(res == VK_SUCCESS);210211// Separate view for texture sampling all layers together.212if (!color) {213ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;214}215216ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; // layered for consistency, even if single image.217res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texAllLayersView);218vulkan->SetDebugName(img.texAllLayersView, VK_OBJECT_TYPE_IMAGE_VIEW, tag);219220// Create 2D views for both layers.221// Useful when multipassing shaders that don't yet exist in a single-pass-stereo version.222for (int i = 0; i < numLayers; i++) {223ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;224ivci.subresourceRange.layerCount = 1;225ivci.subresourceRange.baseArrayLayer = i;226res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.texLayerViews[i]);227if (vulkan->DebugLayerEnabled()) {228char temp[128];229snprintf(temp, sizeof(temp), "%s_layer%d", tag, i);230vulkan->SetDebugName(img.texLayerViews[i], VK_OBJECT_TYPE_IMAGE_VIEW, temp);231}232_dbg_assert_(res == VK_SUCCESS);233}234235VkPipelineStageFlags dstStage;236VkAccessFlagBits dstAccessMask;237switch (initialLayout) {238case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:239dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;240dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;241break;242case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:243dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;244dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;245break;246case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:247dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;248dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;249break;250default:251Crash();252return;253}254255VkImageMemoryBarrier *barrier = barriers->Add(img.image, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage, 0);256barrier->subresourceRange.layerCount = numLayers;257barrier->subresourceRange.aspectMask = aspects;258barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;259barrier->newLayout = initialLayout;260barrier->srcAccessMask = 0;261barrier->dstAccessMask = dstAccessMask;262263img.layout = initialLayout;264img.format = format;265img.sampleCount = sampleCount;266img.tag = tag ? tag : "N/A";267img.numLayers = numLayers;268}269270static VkAttachmentLoadOp ConvertLoadAction(VKRRenderPassLoadAction action) {271switch (action) {272case VKRRenderPassLoadAction::CLEAR: return VK_ATTACHMENT_LOAD_OP_CLEAR;273case VKRRenderPassLoadAction::KEEP: return VK_ATTACHMENT_LOAD_OP_LOAD;274case VKRRenderPassLoadAction::DONT_CARE: return VK_ATTACHMENT_LOAD_OP_DONT_CARE;275}276return VK_ATTACHMENT_LOAD_OP_DONT_CARE; // avoid compiler warning277}278279static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) {280switch (action) {281case VKRRenderPassStoreAction::STORE: return VK_ATTACHMENT_STORE_OP_STORE;282case VKRRenderPassStoreAction::DONT_CARE: return VK_ATTACHMENT_STORE_OP_DONT_CARE;283}284return VK_ATTACHMENT_STORE_OP_DONT_CARE; // avoid compiler warning285}286287// Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827288// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies289290VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType, VkSampleCountFlagBits sampleCount) {291bool isBackbuffer = rpType == RenderPassType::BACKBUFFER;292bool hasDepth = RenderPassTypeHasDepth(rpType);293bool multiview = RenderPassTypeHasMultiView(rpType);294bool multisample = RenderPassTypeHasMultisample(rpType);295296_dbg_assert_(!(isBackbuffer && multisample));297298if (isBackbuffer) {299_dbg_assert_(key.depthLoadAction != VKRRenderPassLoadAction::KEEP);300}301302if (multiview) {303// TODO: Assert that the device has multiview support enabled.304}305306int colorAttachmentIndex = 0;307int depthAttachmentIndex = 1;308309int attachmentCount = 0;310VkAttachmentDescription attachments[4]{};311attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;312attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT;313attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.colorLoadAction);314attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction);315attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;316attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;317attachments[attachmentCount].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;318attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;319attachmentCount++;320321if (hasDepth) {322attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat;323attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT;324attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.depthLoadAction);325attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction);326attachments[attachmentCount].stencilLoadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.stencilLoadAction);327attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction);328attachments[attachmentCount].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;329attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;330attachmentCount++;331}332333if (multisample) {334colorAttachmentIndex = attachmentCount;335attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;336attachments[attachmentCount].samples = sampleCount;337attachments[attachmentCount].loadOp = ConvertLoadAction(key.colorLoadAction);338attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction);339attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;340attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;341attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;342attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;343attachmentCount++;344345if (hasDepth) {346depthAttachmentIndex = attachmentCount;347attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat;348attachments[attachmentCount].samples = sampleCount;349attachments[attachmentCount].loadOp = ConvertLoadAction(key.depthLoadAction);350attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction);351attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction);352attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction);353attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;354attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;355attachmentCount++;356}357}358359VkAttachmentReference colorReference{};360colorReference.attachment = colorAttachmentIndex;361colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;362363VkAttachmentReference depthReference{};364depthReference.attachment = depthAttachmentIndex;365depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;366367VkSubpassDescription subpass{};368subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;369subpass.flags = 0;370subpass.colorAttachmentCount = 1;371subpass.pColorAttachments = &colorReference;372373VkAttachmentReference colorResolveReference;374if (multisample) {375colorResolveReference.attachment = 0; // the non-msaa color buffer.376colorResolveReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;377subpass.pResolveAttachments = &colorResolveReference;378} else {379subpass.pResolveAttachments = nullptr;380}381if (hasDepth) {382subpass.pDepthStencilAttachment = &depthReference;383}384subpass.preserveAttachmentCount = 0;385subpass.pPreserveAttachments = nullptr;386387// Not sure if this is really necessary.388VkSubpassDependency deps[2]{};389size_t numDeps = 0;390391VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };392rp.attachmentCount = attachmentCount;393rp.pAttachments = attachments;394rp.subpassCount = 1;395rp.pSubpasses = &subpass;396397VkRenderPassMultiviewCreateInfoKHR mv{ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR };398uint32_t viewMask = 0x3; // Must be outside the 'if (multiview)' scope!399int viewOffset = 0;400if (multiview) {401rp.pNext = &mv;402mv.subpassCount = 1;403mv.pViewMasks = &viewMask;404mv.dependencyCount = 0;405mv.pCorrelationMasks = &viewMask; // same masks406mv.correlationMaskCount = 1;407mv.pViewOffsets = &viewOffset;408}409410if (isBackbuffer) {411// We don't specify any explicit transitions for these, so let's use subpass dependencies.412// This makes sure that writes to the depth image are done before we try to write to it again.413// From Sascha's examples.414deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL;415deps[numDeps].dstSubpass = 0;416deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;417deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;418deps[numDeps].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;419deps[numDeps].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;420deps[numDeps].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;421numDeps++;422// Dependencies for the color image.423deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL;424deps[numDeps].dstSubpass = 0;425deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;426deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;427deps[numDeps].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;428deps[numDeps].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;429deps[numDeps].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;430numDeps++;431}432433if (numDeps > 0) {434rp.dependencyCount = (u32)numDeps;435rp.pDependencies = deps;436}437438VkRenderPass pass;439VkResult res;440441// We could always use renderpass2, but I think it'll get both paths better tested if we442// only use it with multisample enabled.443// if (vulkan->Extensions().KHR_create_renderpass2) {444if (multisample) {445// It's a bit unfortunate that we can't rely on vkCreateRenderPass2, because here we now have446// to do a bunch of struct conversion, just to not have to repeat the logic from above.447VkAttachmentDescription2KHR attachments2[4]{};448for (int i = 0; i < attachmentCount; i++) {449attachments2[i].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;450attachments2[i].format = attachments[i].format;451attachments2[i].samples = attachments[i].samples;452attachments2[i].loadOp = attachments[i].loadOp;453attachments2[i].storeOp = attachments[i].storeOp;454attachments2[i].stencilLoadOp = attachments[i].stencilLoadOp;455attachments2[i].stencilStoreOp = attachments[i].stencilStoreOp;456attachments2[i].initialLayout = attachments[i].initialLayout;457attachments2[i].finalLayout = attachments[i].finalLayout;458}459460VkAttachmentReference2KHR colorReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR };461colorReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;462colorReference2.attachment = colorReference.attachment;463colorReference2.layout = colorReference.layout;464465VkAttachmentReference2KHR depthReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR };466depthReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;467depthReference2.attachment = depthReference.attachment;468depthReference2.layout = depthReference.layout;469470VkSubpassDependency2KHR deps2[2]{};471for (int i = 0; i < numDeps; i++) {472deps2[i].sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;473deps2[i].dependencyFlags = deps[i].dependencyFlags;474deps2[i].srcAccessMask = deps[i].srcAccessMask;475deps2[i].dstAccessMask = deps[i].dstAccessMask;476deps2[i].srcStageMask = deps[i].srcStageMask;477deps2[i].dstStageMask = deps[i].dstStageMask;478deps2[i].srcSubpass = deps[i].srcSubpass;479deps2[i].dstSubpass = deps[i].dstSubpass;480deps2[i].dependencyFlags = deps[i].dependencyFlags;481deps2[i].viewOffset = 0;482}483484VkAttachmentReference2KHR colorResolveReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR };485486VkSubpassDescription2KHR subpass2{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR };487subpass2.colorAttachmentCount = subpass.colorAttachmentCount;488subpass2.flags = subpass.flags;489subpass2.pColorAttachments = &colorReference2;490if (hasDepth) {491subpass2.pDepthStencilAttachment = &depthReference2;492}493subpass2.pipelineBindPoint = subpass.pipelineBindPoint;494subpass2.viewMask = multiview ? viewMask : 0;495if (multisample) {496colorResolveReference2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;497colorResolveReference2.attachment = colorResolveReference.attachment; // the non-msaa color buffer.498colorResolveReference2.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;499subpass2.pResolveAttachments = &colorResolveReference2;500} else {501subpass2.pResolveAttachments = nullptr;502}503504VkAttachmentReference2KHR depthResolveReference2{ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR };505VkSubpassDescriptionDepthStencilResolveKHR depthStencilResolve{ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR };506if (hasDepth && multisample) {507ChainStruct(subpass2, &depthStencilResolve);508depthResolveReference2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;509depthResolveReference2.attachment = 1;510depthResolveReference2.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;511// TODO: Some games might benefit from the other depth resolve modes when depth texturing.512depthStencilResolve.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR;513depthStencilResolve.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR;514depthStencilResolve.pDepthStencilResolveAttachment = &depthResolveReference2;515}516517VkRenderPassCreateInfo2KHR rp2{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR };518rp2.pAttachments = attachments2;519rp2.pDependencies = deps2;520rp2.attachmentCount = rp.attachmentCount;521rp2.dependencyCount = rp.dependencyCount;522rp2.correlatedViewMaskCount = multiview ? 1 : 0;523rp2.pCorrelatedViewMasks = multiview ? &viewMask : nullptr;524rp2.pSubpasses = &subpass2;525rp2.subpassCount = 1;526res = vkCreateRenderPass2(vulkan->GetDevice(), &rp2, nullptr, &pass);527} else {528res = vkCreateRenderPass(vulkan->GetDevice(), &rp, nullptr, &pass);529}530531if (pass) {532vulkan->SetDebugName(pass, VK_OBJECT_TYPE_RENDER_PASS, GetRPTypeName(rpType));533}534535_assert_(res == VK_SUCCESS);536_assert_(pass != VK_NULL_HANDLE);537return pass;538}539540VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount) {541// When we create a render pass, we create all "types" of it immediately,542// practical later when referring to it. Could change to on-demand if it feels motivated543// but I think the render pass objects are cheap.544545// WARNING: We don't include sampleCount in the key, there's only the distinction multisampled or not546// which comes from the rpType.547// So you CAN NOT mix and match different non-one sample counts.548549_dbg_assert_(!((rpType & RenderPassType::MULTISAMPLE) && sampleCount == VK_SAMPLE_COUNT_1_BIT));550551if (!pass[(int)rpType] || sampleCounts[(int)rpType] != sampleCount) {552if (pass[(int)rpType]) {553vulkan->Delete().QueueDeleteRenderPass(pass[(int)rpType]);554}555pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType, sampleCount);556sampleCounts[(int)rpType] = sampleCount;557}558return pass[(int)rpType];559}560561562