dawn-cmake/src/dawn_native/vulkan/RenderPassCache.cpp
Kai Ninomiya f44a809f9a Remove VK_DEFINE_NON_DISPATCHABLE_HANDLE magic, use explicit VkHandle wrapper
Overriding VK_DEFINE_NON_DISPATCHABLE_HANDLE changes the function
signatures of Vulkan functions, changing their ABI and making us
incompatible with real drivers. This removes that magic, and replaces it
with an explicit wrapper, VkHandle, which has much of the same
functionality as the original VkNonDispatchableHandle.

It adds definitions for dawn_native::vulkan::VkBuffer et al, which
shadow the native ::VkBuffer et al. This retains type safety throughout
the Vulkan backend without changing every single usage.

Notably, the following things had to change:
- An explicit conversion from VkBuffer* to ::VkBuffer* is needed for
  arrays. This is implemented as a reinterpret_cast, which is still
  safe as the new VkHandle still has the same memory layout properties
  as VkNonDispatchableHandle did.
- When pointing to a VkHandle as an output pointer, it's now necessary
  to explicitly get the native ::VkBuffer (via operator*) and point to
  it.

Previously reviewed on:
https://dawn-review.googlesource.com/c/dawn/+/15580

Bug: chromium:1046362
Change-Id: I7d34ec38a805025f92165ea9a7ee07ae5c182076
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15641
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
2020-01-31 04:04:16 +00:00

256 lines
10 KiB
C++

// Copyright 2018 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/vulkan/RenderPassCache.h"
#include "common/BitSetIterator.h"
#include "common/HashUtils.h"
#include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/TextureVk.h"
#include "dawn_native/vulkan/VulkanError.h"
namespace dawn_native { namespace vulkan {
namespace {
VkAttachmentLoadOp VulkanAttachmentLoadOp(wgpu::LoadOp op) {
switch (op) {
case wgpu::LoadOp::Load:
return VK_ATTACHMENT_LOAD_OP_LOAD;
case wgpu::LoadOp::Clear:
return VK_ATTACHMENT_LOAD_OP_CLEAR;
default:
UNREACHABLE();
}
}
} // anonymous namespace
// RenderPassCacheQuery
void RenderPassCacheQuery::SetColor(uint32_t index,
wgpu::TextureFormat format,
wgpu::LoadOp loadOp,
bool hasResolveTarget) {
colorMask.set(index);
colorFormats[index] = format;
colorLoadOp[index] = loadOp;
resolveTargetMask[index] = hasResolveTarget;
}
void RenderPassCacheQuery::SetDepthStencil(wgpu::TextureFormat format,
wgpu::LoadOp depthLoadOp,
wgpu::LoadOp stencilLoadOp) {
hasDepthStencil = true;
depthStencilFormat = format;
this->depthLoadOp = depthLoadOp;
this->stencilLoadOp = stencilLoadOp;
}
void RenderPassCacheQuery::SetSampleCount(uint32_t sampleCount) {
this->sampleCount = sampleCount;
}
// RenderPassCache
RenderPassCache::RenderPassCache(Device* device) : mDevice(device) {
}
RenderPassCache::~RenderPassCache() {
for (auto it : mCache) {
mDevice->fn.DestroyRenderPass(mDevice->GetVkDevice(), it.second, nullptr);
}
mCache.clear();
}
ResultOrError<VkRenderPass> RenderPassCache::GetRenderPass(const RenderPassCacheQuery& query) {
auto it = mCache.find(query);
if (it != mCache.end()) {
return VkRenderPass(it->second);
}
VkRenderPass renderPass;
DAWN_TRY_ASSIGN(renderPass, CreateRenderPassForQuery(query));
mCache.emplace(query, renderPass);
return renderPass;
}
ResultOrError<VkRenderPass> RenderPassCache::CreateRenderPassForQuery(
const RenderPassCacheQuery& query) const {
// The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
// Precompute them as they must be pointer-chained in VkSubpassDescription
std::array<VkAttachmentReference, kMaxColorAttachments> colorAttachmentRefs;
std::array<VkAttachmentReference, kMaxColorAttachments> resolveAttachmentRefs;
VkAttachmentReference depthStencilAttachmentRef;
// Contains the attachment description that will be chained in the create info
// The order of all attachments in attachmentDescs is "color-depthstencil-resolve".
constexpr uint32_t kMaxAttachmentCount = kMaxColorAttachments * 2 + 1;
std::array<VkAttachmentDescription, kMaxAttachmentCount> attachmentDescs = {};
VkSampleCountFlagBits vkSampleCount = VulkanSampleCount(query.sampleCount);
uint32_t colorAttachmentIndex = 0;
for (uint32_t i : IterateBitSet(query.colorMask)) {
auto& attachmentRef = colorAttachmentRefs[colorAttachmentIndex];
auto& attachmentDesc = attachmentDescs[colorAttachmentIndex];
attachmentRef.attachment = colorAttachmentIndex;
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentDesc.flags = 0;
attachmentDesc.format = VulkanImageFormat(mDevice, query.colorFormats[i]);
attachmentDesc.samples = vkSampleCount;
attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.colorLoadOp[i]);
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
++colorAttachmentIndex;
}
uint32_t attachmentCount = colorAttachmentIndex;
VkAttachmentReference* depthStencilAttachment = nullptr;
if (query.hasDepthStencil) {
auto& attachmentDesc = attachmentDescs[attachmentCount];
depthStencilAttachment = &depthStencilAttachmentRef;
depthStencilAttachmentRef.attachment = attachmentCount;
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachmentDesc.flags = 0;
attachmentDesc.format = VulkanImageFormat(mDevice, query.depthStencilFormat);
attachmentDesc.samples = vkSampleCount;
attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.depthLoadOp);
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(query.stencilLoadOp);
attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
++attachmentCount;
}
uint32_t resolveAttachmentIndex = 0;
for (uint32_t i : IterateBitSet(query.resolveTargetMask)) {
auto& attachmentRef = resolveAttachmentRefs[resolveAttachmentIndex];
auto& attachmentDesc = attachmentDescs[attachmentCount];
attachmentRef.attachment = attachmentCount;
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentDesc.flags = 0;
attachmentDesc.format = VulkanImageFormat(mDevice, query.colorFormats[i]);
attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
++attachmentCount;
++resolveAttachmentIndex;
}
VkAttachmentReference* resolveTargetAttachmentRefs =
query.resolveTargetMask.any() ? resolveAttachmentRefs.data() : nullptr;
// Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
VkSubpassDescription subpassDesc;
subpassDesc.flags = 0;
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.inputAttachmentCount = 0;
subpassDesc.pInputAttachments = nullptr;
subpassDesc.colorAttachmentCount = colorAttachmentIndex;
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = resolveTargetAttachmentRefs;
subpassDesc.pDepthStencilAttachment = depthStencilAttachment;
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
// Chain everything in VkRenderPassCreateInfo
VkRenderPassCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.attachmentCount = attachmentCount;
createInfo.pAttachments = attachmentDescs.data();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpassDesc;
createInfo.dependencyCount = 0;
createInfo.pDependencies = nullptr;
// Create the render pass from the zillion parameters
VkRenderPass renderPass;
DAWN_TRY(CheckVkSuccess(mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo,
nullptr, &*renderPass),
"CreateRenderPass"));
return renderPass;
}
// RenderPassCache
size_t RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& query) const {
size_t hash = Hash(query.colorMask);
HashCombine(&hash, Hash(query.resolveTargetMask));
for (uint32_t i : IterateBitSet(query.colorMask)) {
HashCombine(&hash, query.colorFormats[i], query.colorLoadOp[i]);
}
HashCombine(&hash, query.hasDepthStencil);
if (query.hasDepthStencil) {
HashCombine(&hash, query.depthStencilFormat, query.depthLoadOp, query.stencilLoadOp);
}
HashCombine(&hash, query.sampleCount);
return hash;
}
bool RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& a,
const RenderPassCacheQuery& b) const {
if (a.colorMask != b.colorMask) {
return false;
}
if (a.resolveTargetMask != b.resolveTargetMask) {
return false;
}
if (a.sampleCount != b.sampleCount) {
return false;
}
for (uint32_t i : IterateBitSet(a.colorMask)) {
if ((a.colorFormats[i] != b.colorFormats[i]) ||
(a.colorLoadOp[i] != b.colorLoadOp[i])) {
return false;
}
}
if (a.hasDepthStencil != b.hasDepthStencil) {
return false;
}
if (a.hasDepthStencil) {
if ((a.depthStencilFormat != b.depthStencilFormat) ||
(a.depthLoadOp != b.depthLoadOp) || (a.stencilLoadOp != b.stencilLoadOp)) {
return false;
}
}
return true;
}
}} // namespace dawn_native::vulkan