Skip to content

Commit b889650

Browse files
tojiDawn LUCI CQ
authored andcommitted
Implement VK_KHR_dynamic_rendering
Controlled with the vulkan_use_dynamic_rendering toggle. Matches WebGPU's render pass model much better and removes the need to perform complex caching of VkRenderPass and VkFramebuffer objects. Bug: 463893794 Change-Id: I67f6505e26cb9b0567a284e3863fedaf8d828d6c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/278638 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Loko Kung <lokokung@google.com> Commit-Queue: Brandon Jones <bajones@chromium.org> Auto-Submit: Brandon Jones <bajones@chromium.org>
1 parent 1a97ad9 commit b889650

23 files changed

+469
-139
lines changed

src/dawn/native/Toggles.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,10 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
722722
"Enables RenderDoc process injection. If RenderDoc is used to inject into the GPU process, "
723723
"send RenderDoc frame capture info.",
724724
"https://crbug.com/449708316", ToggleStage::Device}},
725+
{Toggle::VulkanUseDynamicRendering,
726+
{"vulkan_use_dynamic_rendering",
727+
"Makes use of VK_KHR_dynamic_rendering to implement WebGPU RenderPass.",
728+
"https://crbug.com/dawn/463893794", ToggleStage::Device}},
725729
{Toggle::WaitIsThreadSafe,
726730
{"wait_is_thread_safe",
727731
"WaitFor* functions are thread-safe and can be called without the device-lock if implicit "

src/dawn/native/Toggles.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ enum class Toggle {
173173
DecomposeUniformBuffers,
174174
VulkanEnableF16OnNvidia,
175175
EnableRenderDocProcessInjection,
176+
VulkanUseDynamicRendering,
176177

177178
// Once all backends have been updated to be thread safe for waiting, we can remove this toggle.
178179
WaitIsThreadSafe,

src/dawn/native/vulkan/CommandBufferVk.cpp

Lines changed: 168 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <vector>
3333

3434
#include "dawn/common/Enumerator.h"
35+
#include "dawn/common/Range.h"
3536
#include "dawn/native/BindGroupTracker.h"
3637
#include "dawn/native/CommandEncoder.h"
3738
#include "dawn/native/CommandValidation.h"
@@ -484,11 +485,165 @@ void RecordResolveQuerySetCmd(VkCommandBuffer commands,
484485
}
485486
}
486487

488+
VkClearValue ToVkClearValue(dawn::native::Color clearColor, TextureComponentType baseType) {
489+
VkClearValue clearValue;
490+
switch (baseType) {
491+
case TextureComponentType::Float: {
492+
const std::array<float, 4> appliedClearColor = ConvertToFloatColor(clearColor);
493+
for (uint32_t j = 0; j < 4; ++j) {
494+
clearValue.color.float32[j] = appliedClearColor[j];
495+
}
496+
break;
497+
}
498+
case TextureComponentType::Uint: {
499+
const std::array<uint32_t, 4> appliedClearColor =
500+
ConvertToUnsignedIntegerColor(clearColor);
501+
for (uint32_t j = 0; j < 4; ++j) {
502+
clearValue.color.uint32[j] = appliedClearColor[j];
503+
}
504+
break;
505+
}
506+
case TextureComponentType::Sint: {
507+
const std::array<int32_t, 4> appliedClearColor =
508+
ConvertToSignedIntegerColor(clearColor);
509+
for (uint32_t j = 0; j < 4; ++j) {
510+
clearValue.color.int32[j] = appliedClearColor[j];
511+
}
512+
break;
513+
}
514+
}
515+
return clearValue;
516+
}
517+
487518
} // anonymous namespace
488519

520+
MaybeError RecordBeginDynamicRenderPass(CommandRecordingContext* recordingContext,
521+
Device* device,
522+
BeginRenderPassCmd* renderPass) {
523+
// Needed to work around some quirks introduced by vulkan_platform.h which causes some platforms
524+
// to hit compiler errors if Vulkan struct members are assigned to VK_NULL_HANDLE directly.
525+
static const VkImageView nullImageView = VK_NULL_HANDLE;
526+
527+
VkRenderingInfoKHR renderInfo;
528+
renderInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
529+
renderInfo.pNext = nullptr;
530+
renderInfo.flags = 0;
531+
renderInfo.renderArea.offset.x = 0;
532+
renderInfo.renderArea.offset.y = 0;
533+
renderInfo.renderArea.extent.width = renderPass->width;
534+
renderInfo.renderArea.extent.height = renderPass->height;
535+
renderInfo.layerCount = 1;
536+
renderInfo.viewMask = 0;
537+
renderInfo.pDepthAttachment = nullptr;
538+
renderInfo.pStencilAttachment = nullptr;
539+
540+
PerColorAttachment<VkRenderingAttachmentInfoKHR> colorAttachments;
541+
542+
ColorAttachmentMask attachmentMask = renderPass->attachmentState->GetColorAttachmentsMask();
543+
ColorAttachmentIndex attachmentCount = GetHighestBitIndexPlusOne(attachmentMask);
544+
545+
// Initialize all potentially used color attachments with null/default values, which allows the
546+
// attachments to be sparse.
547+
for (auto i : Range(attachmentCount)) {
548+
auto& colorAttachment = colorAttachments[i];
549+
colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
550+
colorAttachment.pNext = nullptr;
551+
colorAttachment.imageView = nullImageView;
552+
colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
553+
colorAttachment.resolveMode = VK_RESOLVE_MODE_NONE;
554+
colorAttachment.resolveImageView = nullImageView;
555+
colorAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
556+
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
557+
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
558+
}
559+
560+
// Set the color attachments used by this pass. May be sparse.
561+
for (auto i : attachmentMask) {
562+
auto& attachmentInfo = renderPass->colorAttachments[i];
563+
TextureView* view = ToBackend(attachmentInfo.view.Get());
564+
if (view == nullptr) {
565+
continue;
566+
}
567+
568+
auto& colorAttachment = colorAttachments[i];
569+
if (view->GetDimension() == wgpu::TextureViewDimension::e3D) {
570+
VkImageView handleFor2DViewOn3D;
571+
DAWN_TRY_ASSIGN(handleFor2DViewOn3D,
572+
view->GetOrCreate2DViewOn3D(attachmentInfo.depthSlice));
573+
colorAttachment.imageView = handleFor2DViewOn3D;
574+
} else {
575+
colorAttachment.imageView = view->GetHandle();
576+
}
577+
578+
if (attachmentInfo.resolveTarget != nullptr) {
579+
TextureView* resolveView = ToBackend(attachmentInfo.resolveTarget.Get());
580+
colorAttachment.resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT;
581+
colorAttachment.resolveImageView = resolveView->GetHandle();
582+
colorAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
583+
}
584+
585+
colorAttachment.loadOp = VulkanAttachmentLoadOp(attachmentInfo.loadOp);
586+
colorAttachment.storeOp = VulkanAttachmentStoreOp(attachmentInfo.storeOp);
587+
colorAttachment.clearValue = ToVkClearValue(
588+
attachmentInfo.clearColor, view->GetFormat().GetAspectInfo(Aspect::Color).baseType);
589+
}
590+
591+
renderInfo.colorAttachmentCount = static_cast<uint32_t>(attachmentCount);
592+
renderInfo.pColorAttachments = colorAttachments.data();
593+
594+
// Set the depth/stencil attachment used by this pass.
595+
VkRenderingAttachmentInfoKHR depthAttachment;
596+
VkRenderingAttachmentInfoKHR stencilAttachment;
597+
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
598+
const auto& attachmentInfo = renderPass->depthStencilAttachment;
599+
TextureView* view = ToBackend(attachmentInfo.view.Get());
600+
DAWN_ASSERT(view);
601+
602+
const Format& dsFormat = view->GetTexture()->GetFormat();
603+
VkImageLayout imageLayout = VulkanImageLayoutForDepthStencilAttachment(
604+
dsFormat, attachmentInfo.depthReadOnly, attachmentInfo.stencilReadOnly);
605+
606+
if (dsFormat.HasDepth()) {
607+
depthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
608+
depthAttachment.pNext = nullptr;
609+
depthAttachment.imageView = view->GetHandle();
610+
depthAttachment.imageLayout = imageLayout;
611+
depthAttachment.resolveMode = VK_RESOLVE_MODE_NONE;
612+
depthAttachment.resolveImageView = nullImageView;
613+
depthAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
614+
depthAttachment.loadOp = VulkanAttachmentLoadOp(attachmentInfo.depthLoadOp);
615+
depthAttachment.storeOp = VulkanAttachmentStoreOp(attachmentInfo.depthStoreOp);
616+
depthAttachment.clearValue.depthStencil.depth = attachmentInfo.clearDepth;
617+
renderInfo.pDepthAttachment = &depthAttachment;
618+
}
619+
620+
if (dsFormat.HasStencil()) {
621+
stencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
622+
stencilAttachment.pNext = nullptr;
623+
stencilAttachment.imageView = view->GetHandle();
624+
stencilAttachment.imageLayout = imageLayout;
625+
stencilAttachment.resolveMode = VK_RESOLVE_MODE_NONE;
626+
stencilAttachment.resolveImageView = nullImageView;
627+
stencilAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
628+
stencilAttachment.loadOp = VulkanAttachmentLoadOp(attachmentInfo.stencilLoadOp);
629+
stencilAttachment.storeOp = VulkanAttachmentStoreOp(attachmentInfo.stencilStoreOp);
630+
stencilAttachment.clearValue.depthStencil.stencil = attachmentInfo.clearStencil;
631+
renderInfo.pStencilAttachment = &stencilAttachment;
632+
}
633+
}
634+
635+
device->fn.CmdBeginRenderingKHR(recordingContext->commandBuffer, &renderInfo);
636+
637+
return {};
638+
}
639+
489640
MaybeError RecordBeginRenderPass(CommandRecordingContext* recordingContext,
490641
Device* device,
491642
BeginRenderPassCmd* renderPass) {
643+
if (device->IsToggleEnabled(Toggle::VulkanUseDynamicRendering)) {
644+
return RecordBeginDynamicRenderPass(recordingContext, device, renderPass);
645+
}
646+
492647
VkCommandBuffer commands = recordingContext->commandBuffer;
493648

494649
// Query a VkRenderPass from the cache
@@ -537,34 +692,8 @@ MaybeError RecordBeginRenderPass(CommandRecordingContext* recordingContext,
537692
continue;
538693
}
539694

540-
VkClearValue clearValue;
541-
switch (view->GetFormat().GetAspectInfo(Aspect::Color).baseType) {
542-
case TextureComponentType::Float: {
543-
const std::array<float, 4> appliedClearColor =
544-
ConvertToFloatColor(attachmentInfo.clearColor);
545-
for (uint32_t j = 0; j < 4; ++j) {
546-
clearValue.color.float32[j] = appliedClearColor[j];
547-
}
548-
break;
549-
}
550-
case TextureComponentType::Uint: {
551-
const std::array<uint32_t, 4> appliedClearColor =
552-
ConvertToUnsignedIntegerColor(attachmentInfo.clearColor);
553-
for (uint32_t j = 0; j < 4; ++j) {
554-
clearValue.color.uint32[j] = appliedClearColor[j];
555-
}
556-
break;
557-
}
558-
case TextureComponentType::Sint: {
559-
const std::array<int32_t, 4> appliedClearColor =
560-
ConvertToSignedIntegerColor(attachmentInfo.clearColor);
561-
for (uint32_t j = 0; j < 4; ++j) {
562-
clearValue.color.int32[j] = appliedClearColor[j];
563-
}
564-
break;
565-
}
566-
}
567-
695+
VkClearValue clearValue = ToVkClearValue(
696+
attachmentInfo.clearColor, view->GetFormat().GetAspectInfo(Aspect::Color).baseType);
568697
uint32_t depthSlice = view->GetDimension() == wgpu::TextureViewDimension::e3D
569698
? attachmentInfo.depthSlice
570699
: 0;
@@ -636,6 +765,16 @@ MaybeError RecordBeginRenderPass(CommandRecordingContext* recordingContext,
636765
return {};
637766
}
638767

768+
void RecordEndRenderPass(CommandRecordingContext* recordingContext, Device* device) {
769+
VkCommandBuffer commands = recordingContext->commandBuffer;
770+
771+
if (device->IsToggleEnabled(Toggle::VulkanUseDynamicRendering)) {
772+
device->fn.CmdEndRenderingKHR(commands);
773+
} else {
774+
device->fn.CmdEndRenderPass(commands);
775+
}
776+
}
777+
639778
// static
640779
Ref<CommandBuffer> CommandBuffer::Create(CommandEncoder* encoder,
641780
const CommandBufferDescriptor* descriptor) {
@@ -1560,7 +1699,7 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingCon
15601699
device->fn.CmdEndQuery(commands, ToBackend(querySet)->GetHandle(), 0);
15611700
}
15621701

1563-
device->fn.CmdEndRenderPass(commands);
1702+
RecordEndRenderPass(recordingContext, device);
15641703

15651704
// Write timestamp at the end of render pass if it's set.
15661705
// We've observed that this must be called after the render pass ends or the

src/dawn/native/vulkan/CommandBufferVk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ MaybeError RecordBeginRenderPass(CommandRecordingContext* recordingContext,
5050
Device* device,
5151
BeginRenderPassCmd* renderPass);
5252

53+
void RecordEndRenderPass(CommandRecordingContext* recordingContext, Device* device);
54+
5355
class CommandBuffer final : public CommandBufferBase {
5456
public:
5557
static Ref<CommandBuffer> Create(CommandEncoder* encoder,

src/dawn/native/vulkan/DeviceVk.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,12 @@ ResultOrError<VulkanDeviceKnobs> Device::CreateDevice(VkPhysicalDevice vkPhysica
648648
featuresChain.Add(&usedKnobs.descriptorIndexingFeatures);
649649
}
650650

651+
if (IsToggleEnabled(Toggle::VulkanUseDynamicRendering)) {
652+
DAWN_ASSERT(usedKnobs.HasExt(DeviceExt::DynamicRendering));
653+
usedKnobs.dynamicRenderingFeatures = mDeviceInfo.dynamicRenderingFeatures;
654+
featuresChain.Add(&usedKnobs.dynamicRenderingFeatures);
655+
}
656+
651657
// Find a universal queue family
652658
{
653659
// Note that GRAPHICS and COMPUTE imply TRANSFER so we don't need to check for it.

src/dawn/native/vulkan/PhysicalDeviceVk.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,20 @@ void PhysicalDevice::SetupBackendDeviceToggles(dawn::platform::Platform* platfor
11671167
} else {
11681168
deviceToggles->ForceSet(Toggle::UseSpirv14, false);
11691169
}
1170+
1171+
// Use dynamic rendering by default if the corresponding extension is available.
1172+
// Also disable on older Intel devices, which have been observed to have driver issues with
1173+
// the dynamic rendering path.
1174+
if (!GetDeviceInfo().HasExt(DeviceExt::DynamicRendering) ||
1175+
GetDeviceInfo().dynamicRenderingFeatures.dynamicRendering == VK_FALSE ||
1176+
(gpu_info::IsIntel(GetVendorId()) &&
1177+
gpu_info::GetIntelGen(GetVendorId(), GetDeviceId()) <= gpu_info::IntelGen::Gen9)) {
1178+
deviceToggles->ForceSet(Toggle::VulkanUseDynamicRendering, false);
1179+
} else {
1180+
// TODO(crbug.com/463893794): Defaulted to false until ExpandResolveTexture is supported
1181+
// when dynamic rendering is enabled.
1182+
deviceToggles->Default(Toggle::VulkanUseDynamicRendering, false);
1183+
}
11701184
}
11711185

11721186
ResultOrError<Ref<DeviceBase>> PhysicalDevice::CreateDeviceImpl(

src/dawn/native/vulkan/RenderPassCache.cpp

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,41 +33,12 @@
3333
#include "dawn/common/Range.h"
3434
#include "dawn/native/vulkan/DeviceVk.h"
3535
#include "dawn/native/vulkan/TextureVk.h"
36+
#include "dawn/native/vulkan/UtilsVulkan.h"
3637
#include "dawn/native/vulkan/VulkanError.h"
3738

3839
namespace dawn::native::vulkan {
3940

4041
namespace {
41-
VkAttachmentLoadOp VulkanAttachmentLoadOp(wgpu::LoadOp op) {
42-
switch (op) {
43-
case wgpu::LoadOp::Load:
44-
return VK_ATTACHMENT_LOAD_OP_LOAD;
45-
case wgpu::LoadOp::Clear:
46-
return VK_ATTACHMENT_LOAD_OP_CLEAR;
47-
case wgpu::LoadOp::ExpandResolveTexture:
48-
return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
49-
case wgpu::LoadOp::Undefined:
50-
DAWN_UNREACHABLE();
51-
break;
52-
}
53-
DAWN_UNREACHABLE();
54-
}
55-
56-
VkAttachmentStoreOp VulkanAttachmentStoreOp(wgpu::StoreOp op) {
57-
// TODO(crbug.com/dawn/485): return STORE_OP_STORE_NONE_QCOM if the device has required
58-
// extension.
59-
switch (op) {
60-
case wgpu::StoreOp::Store:
61-
return VK_ATTACHMENT_STORE_OP_STORE;
62-
case wgpu::StoreOp::Discard:
63-
return VK_ATTACHMENT_STORE_OP_DONT_CARE;
64-
case wgpu::StoreOp::Undefined:
65-
DAWN_UNREACHABLE();
66-
break;
67-
}
68-
DAWN_UNREACHABLE();
69-
}
70-
7142
void InitializeLoadResolveSubpassDependencies(
7243
absl::InlinedVector<VkSubpassDependency, 2>* subpassDependenciesOut) {
7344
VkSubpassDependency dependencies[2];

0 commit comments

Comments
 (0)