• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/vulkan/RenderPassCache.h"
16 
17 #include "common/BitSetIterator.h"
18 #include "common/HashUtils.h"
19 #include "dawn_native/vulkan/DeviceVk.h"
20 #include "dawn_native/vulkan/TextureVk.h"
21 #include "dawn_native/vulkan/VulkanError.h"
22 
23 namespace dawn_native { namespace vulkan {
24 
25     namespace {
VulkanAttachmentLoadOp(wgpu::LoadOp op)26         VkAttachmentLoadOp VulkanAttachmentLoadOp(wgpu::LoadOp op) {
27             switch (op) {
28                 case wgpu::LoadOp::Load:
29                     return VK_ATTACHMENT_LOAD_OP_LOAD;
30                 case wgpu::LoadOp::Clear:
31                     return VK_ATTACHMENT_LOAD_OP_CLEAR;
32             }
33             UNREACHABLE();
34         }
35 
VulkanAttachmentStoreOp(wgpu::StoreOp op)36         VkAttachmentStoreOp VulkanAttachmentStoreOp(wgpu::StoreOp op) {
37             // TODO(crbug.com/dawn/485): return STORE_OP_STORE_NONE_QCOM if the device has required
38             // extension.
39             switch (op) {
40                 case wgpu::StoreOp::Store:
41                     return VK_ATTACHMENT_STORE_OP_STORE;
42                 case wgpu::StoreOp::Discard:
43                     return VK_ATTACHMENT_STORE_OP_DONT_CARE;
44             }
45             UNREACHABLE();
46         }
47     }  // anonymous namespace
48 
49     // RenderPassCacheQuery
50 
SetColor(ColorAttachmentIndex index,wgpu::TextureFormat format,wgpu::LoadOp loadOp,wgpu::StoreOp storeOp,bool hasResolveTarget)51     void RenderPassCacheQuery::SetColor(ColorAttachmentIndex index,
52                                         wgpu::TextureFormat format,
53                                         wgpu::LoadOp loadOp,
54                                         wgpu::StoreOp storeOp,
55                                         bool hasResolveTarget) {
56         colorMask.set(index);
57         colorFormats[index] = format;
58         colorLoadOp[index] = loadOp;
59         colorStoreOp[index] = storeOp;
60         resolveTargetMask[index] = hasResolveTarget;
61     }
62 
SetDepthStencil(wgpu::TextureFormat format,wgpu::LoadOp depthLoadOpIn,wgpu::StoreOp depthStoreOpIn,wgpu::LoadOp stencilLoadOpIn,wgpu::StoreOp stencilStoreOpIn,bool readOnly)63     void RenderPassCacheQuery::SetDepthStencil(wgpu::TextureFormat format,
64                                                wgpu::LoadOp depthLoadOpIn,
65                                                wgpu::StoreOp depthStoreOpIn,
66                                                wgpu::LoadOp stencilLoadOpIn,
67                                                wgpu::StoreOp stencilStoreOpIn,
68                                                bool readOnly) {
69         hasDepthStencil = true;
70         depthStencilFormat = format;
71         depthLoadOp = depthLoadOpIn;
72         depthStoreOp = depthStoreOpIn;
73         stencilLoadOp = stencilLoadOpIn;
74         stencilStoreOp = stencilStoreOpIn;
75         readOnlyDepthStencil = readOnly;
76     }
77 
SetSampleCount(uint32_t sampleCount)78     void RenderPassCacheQuery::SetSampleCount(uint32_t sampleCount) {
79         this->sampleCount = sampleCount;
80     }
81 
82     // RenderPassCache
83 
RenderPassCache(Device * device)84     RenderPassCache::RenderPassCache(Device* device) : mDevice(device) {
85     }
86 
~RenderPassCache()87     RenderPassCache::~RenderPassCache() {
88         std::lock_guard<std::mutex> lock(mMutex);
89         for (auto it : mCache) {
90             mDevice->fn.DestroyRenderPass(mDevice->GetVkDevice(), it.second, nullptr);
91         }
92 
93         mCache.clear();
94     }
95 
GetRenderPass(const RenderPassCacheQuery & query)96     ResultOrError<VkRenderPass> RenderPassCache::GetRenderPass(const RenderPassCacheQuery& query) {
97         std::lock_guard<std::mutex> lock(mMutex);
98         auto it = mCache.find(query);
99         if (it != mCache.end()) {
100             return VkRenderPass(it->second);
101         }
102 
103         VkRenderPass renderPass;
104         DAWN_TRY_ASSIGN(renderPass, CreateRenderPassForQuery(query));
105         mCache.emplace(query, renderPass);
106         return renderPass;
107     }
108 
CreateRenderPassForQuery(const RenderPassCacheQuery & query) const109     ResultOrError<VkRenderPass> RenderPassCache::CreateRenderPassForQuery(
110         const RenderPassCacheQuery& query) const {
111         // The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
112         // Precompute them as they must be pointer-chained in VkSubpassDescription
113         std::array<VkAttachmentReference, kMaxColorAttachments> colorAttachmentRefs;
114         std::array<VkAttachmentReference, kMaxColorAttachments> resolveAttachmentRefs;
115         VkAttachmentReference depthStencilAttachmentRef;
116 
117         // Contains the attachment description that will be chained in the create info
118         // The order of all attachments in attachmentDescs is "color-depthstencil-resolve".
119         constexpr uint8_t kMaxAttachmentCount = kMaxColorAttachments * 2 + 1;
120         std::array<VkAttachmentDescription, kMaxAttachmentCount> attachmentDescs = {};
121 
122         VkSampleCountFlagBits vkSampleCount = VulkanSampleCount(query.sampleCount);
123 
124         uint32_t colorAttachmentIndex = 0;
125         for (ColorAttachmentIndex i : IterateBitSet(query.colorMask)) {
126             auto& attachmentRef = colorAttachmentRefs[colorAttachmentIndex];
127             auto& attachmentDesc = attachmentDescs[colorAttachmentIndex];
128 
129             attachmentRef.attachment = colorAttachmentIndex;
130             attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
131 
132             attachmentDesc.flags = 0;
133             attachmentDesc.format = VulkanImageFormat(mDevice, query.colorFormats[i]);
134             attachmentDesc.samples = vkSampleCount;
135             attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.colorLoadOp[i]);
136             attachmentDesc.storeOp = VulkanAttachmentStoreOp(query.colorStoreOp[i]);
137             attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
138             attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
139 
140             ++colorAttachmentIndex;
141         }
142 
143         uint32_t attachmentCount = colorAttachmentIndex;
144         VkAttachmentReference* depthStencilAttachment = nullptr;
145         if (query.hasDepthStencil) {
146             auto& attachmentDesc = attachmentDescs[attachmentCount];
147 
148             depthStencilAttachment = &depthStencilAttachmentRef;
149 
150             depthStencilAttachmentRef.attachment = attachmentCount;
151             depthStencilAttachmentRef.layout =
152                 query.readOnlyDepthStencil ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
153                                            : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
154 
155             attachmentDesc.flags = 0;
156             attachmentDesc.format = VulkanImageFormat(mDevice, query.depthStencilFormat);
157             attachmentDesc.samples = vkSampleCount;
158 
159             attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.depthLoadOp);
160             attachmentDesc.storeOp = VulkanAttachmentStoreOp(query.depthStoreOp);
161             attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(query.stencilLoadOp);
162             attachmentDesc.stencilStoreOp = VulkanAttachmentStoreOp(query.stencilStoreOp);
163 
164             // There is only one subpass, so it is safe to set both initialLayout and finalLayout to
165             // the only subpass's layout.
166             attachmentDesc.initialLayout = depthStencilAttachmentRef.layout;
167             attachmentDesc.finalLayout = depthStencilAttachmentRef.layout;
168 
169             ++attachmentCount;
170         }
171 
172         uint32_t resolveAttachmentIndex = 0;
173         for (ColorAttachmentIndex i : IterateBitSet(query.resolveTargetMask)) {
174             auto& attachmentRef = resolveAttachmentRefs[resolveAttachmentIndex];
175             auto& attachmentDesc = attachmentDescs[attachmentCount];
176 
177             attachmentRef.attachment = attachmentCount;
178             attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
179 
180             attachmentDesc.flags = 0;
181             attachmentDesc.format = VulkanImageFormat(mDevice, query.colorFormats[i]);
182             attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
183             attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
184             attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
185             attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
186             attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
187 
188             ++attachmentCount;
189             ++resolveAttachmentIndex;
190         }
191 
192         // All color attachments without a corresponding resolve attachment must be set to VK_ATTACHMENT_UNUSED
193         for (; resolveAttachmentIndex < colorAttachmentIndex; resolveAttachmentIndex++) {
194             auto& attachmentRef = resolveAttachmentRefs[resolveAttachmentIndex];
195             attachmentRef.attachment = VK_ATTACHMENT_UNUSED;
196             attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // The Khronos Vulkan validation layer will complain if not set
197         }
198 
199         VkAttachmentReference* resolveTargetAttachmentRefs =
200             query.resolveTargetMask.any() ? resolveAttachmentRefs.data() : nullptr;
201 
202         // Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
203         VkSubpassDescription subpassDesc;
204         subpassDesc.flags = 0;
205         subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
206         subpassDesc.inputAttachmentCount = 0;
207         subpassDesc.pInputAttachments = nullptr;
208         subpassDesc.colorAttachmentCount = colorAttachmentIndex;
209         subpassDesc.pColorAttachments = colorAttachmentRefs.data();
210         subpassDesc.pResolveAttachments = resolveTargetAttachmentRefs;
211         subpassDesc.pDepthStencilAttachment = depthStencilAttachment;
212         subpassDesc.preserveAttachmentCount = 0;
213         subpassDesc.pPreserveAttachments = nullptr;
214 
215         // Chain everything in VkRenderPassCreateInfo
216         VkRenderPassCreateInfo createInfo;
217         createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
218         createInfo.pNext = nullptr;
219         createInfo.flags = 0;
220         createInfo.attachmentCount = attachmentCount;
221         createInfo.pAttachments = attachmentDescs.data();
222         createInfo.subpassCount = 1;
223         createInfo.pSubpasses = &subpassDesc;
224         createInfo.dependencyCount = 0;
225         createInfo.pDependencies = nullptr;
226 
227         // Create the render pass from the zillion parameters
228         VkRenderPass renderPass;
229         DAWN_TRY(CheckVkSuccess(mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo,
230                                                              nullptr, &*renderPass),
231                                 "CreateRenderPass"));
232         return renderPass;
233     }
234 
235     // RenderPassCache
236 
operator ()(const RenderPassCacheQuery & query) const237     size_t RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& query) const {
238         size_t hash = Hash(query.colorMask);
239 
240         HashCombine(&hash, Hash(query.resolveTargetMask));
241 
242         for (ColorAttachmentIndex i : IterateBitSet(query.colorMask)) {
243             HashCombine(&hash, query.colorFormats[i], query.colorLoadOp[i]);
244         }
245 
246         HashCombine(&hash, query.hasDepthStencil);
247         if (query.hasDepthStencil) {
248             HashCombine(&hash, query.depthStencilFormat, query.depthLoadOp, query.stencilLoadOp,
249                         query.readOnlyDepthStencil);
250         }
251 
252         HashCombine(&hash, query.sampleCount);
253 
254         return hash;
255     }
256 
operator ()(const RenderPassCacheQuery & a,const RenderPassCacheQuery & b) const257     bool RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& a,
258                                                  const RenderPassCacheQuery& b) const {
259         if (a.colorMask != b.colorMask) {
260             return false;
261         }
262 
263         if (a.resolveTargetMask != b.resolveTargetMask) {
264             return false;
265         }
266 
267         if (a.sampleCount != b.sampleCount) {
268             return false;
269         }
270 
271         for (ColorAttachmentIndex i : IterateBitSet(a.colorMask)) {
272             if ((a.colorFormats[i] != b.colorFormats[i]) ||
273                 (a.colorLoadOp[i] != b.colorLoadOp[i])) {
274                 return false;
275             }
276         }
277 
278         if (a.hasDepthStencil != b.hasDepthStencil) {
279             return false;
280         }
281 
282         if (a.hasDepthStencil) {
283             if ((a.depthStencilFormat != b.depthStencilFormat) ||
284                 (a.depthLoadOp != b.depthLoadOp) || (a.stencilLoadOp != b.stencilLoadOp) ||
285                 (a.readOnlyDepthStencil != b.readOnlyDepthStencil)) {
286                 return false;
287             }
288         }
289 
290         return true;
291     }
292 }}  // namespace dawn_native::vulkan
293