1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
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 "VkRenderPass.hpp"
16 #include "VkStringify.hpp"
17 #include <cstring>
18
19 namespace {
20
21 template<class T>
ComputeRequiredAllocationSizeT(const T * pCreateInfo)22 size_t ComputeRequiredAllocationSizeT(const T *pCreateInfo)
23 {
24 size_t attachmentSize = pCreateInfo->attachmentCount * sizeof(VkAttachmentDescription) + pCreateInfo->attachmentCount * sizeof(int) // first use
25 + pCreateInfo->attachmentCount * sizeof(uint32_t); // union of subpass view masks, per attachment
26 size_t subpassesSize = 0;
27 for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i)
28 {
29 const auto &subpass = pCreateInfo->pSubpasses[i];
30 uint32_t nbAttachments = subpass.inputAttachmentCount + subpass.colorAttachmentCount;
31 if(subpass.pResolveAttachments)
32 {
33 nbAttachments += subpass.colorAttachmentCount;
34 }
35 if(subpass.pDepthStencilAttachment)
36 {
37 nbAttachments += 1;
38 }
39 subpassesSize += sizeof(VkSubpassDescription) +
40 sizeof(VkAttachmentReference) * nbAttachments +
41 sizeof(uint32_t) * subpass.preserveAttachmentCount +
42 sizeof(uint32_t); // view mask
43 }
44 size_t dependenciesSize = pCreateInfo->dependencyCount * sizeof(VkSubpassDependency);
45
46 return attachmentSize + subpassesSize + dependenciesSize;
47 }
48
49 template<class T>
CopySubpasses(VkSubpassDescription * dst,const T * src,uint32_t count)50 void CopySubpasses(VkSubpassDescription *dst, const T *src, uint32_t count)
51 {
52 for(uint32_t i = 0; i < count; ++i)
53 {
54 dst[i].flags = src[i].flags;
55 dst[i].pipelineBindPoint = src[i].pipelineBindPoint;
56 dst[i].inputAttachmentCount = src[i].inputAttachmentCount;
57 dst[i].pInputAttachments = nullptr;
58 dst[i].colorAttachmentCount = src[i].colorAttachmentCount;
59 dst[i].pColorAttachments = nullptr;
60 dst[i].pResolveAttachments = nullptr;
61 dst[i].pDepthStencilAttachment = nullptr;
62 dst[i].preserveAttachmentCount = src[i].preserveAttachmentCount;
63 dst[i].pPreserveAttachments = nullptr;
64 }
65 }
66
67 template<class T>
CopyAttachmentDescriptions(VkAttachmentDescription * dst,const T * src,uint32_t count)68 void CopyAttachmentDescriptions(VkAttachmentDescription *dst, const T *src, uint32_t count)
69 {
70 for(uint32_t i = 0; i < count; ++i)
71 {
72 dst[i].flags = src[i].flags;
73 dst[i].format = src[i].format;
74 dst[i].samples = src[i].samples;
75 dst[i].loadOp = src[i].loadOp;
76 dst[i].storeOp = src[i].storeOp;
77 dst[i].stencilLoadOp = src[i].stencilLoadOp;
78 dst[i].stencilStoreOp = src[i].stencilStoreOp;
79 dst[i].initialLayout = src[i].initialLayout;
80 dst[i].finalLayout = src[i].finalLayout;
81 }
82 }
83
84 template<class T>
CopyAttachmentReferences(VkAttachmentReference * dst,const T * src,uint32_t count)85 void CopyAttachmentReferences(VkAttachmentReference *dst, const T *src, uint32_t count)
86 {
87 for(uint32_t i = 0; i < count; ++i)
88 {
89 dst[i].attachment = src[i].attachment;
90 dst[i].layout = src[i].layout;
91 }
92 }
93
94 template<class T>
CopySubpassDependencies(VkSubpassDependency * dst,const T * src,uint32_t count)95 void CopySubpassDependencies(VkSubpassDependency *dst, const T *src, uint32_t count)
96 {
97 for(uint32_t i = 0; i < count; ++i)
98 {
99 dst[i].srcSubpass = src[i].srcSubpass;
100 dst[i].dstSubpass = src[i].dstSubpass;
101 dst[i].srcStageMask = src[i].srcStageMask;
102 dst[i].dstStageMask = src[i].dstStageMask;
103 dst[i].srcAccessMask = src[i].srcAccessMask;
104 dst[i].dstAccessMask = src[i].dstAccessMask;
105 dst[i].dependencyFlags = src[i].dependencyFlags;
106 }
107 }
108
GetViewMasks(const VkRenderPassCreateInfo * pCreateInfo,uint32_t * masks)109 bool GetViewMasks(const VkRenderPassCreateInfo *pCreateInfo, uint32_t *masks)
110 {
111 return false;
112 }
113
GetViewMasks(const VkRenderPassCreateInfo2KHR * pCreateInfo,uint32_t * masks)114 bool GetViewMasks(const VkRenderPassCreateInfo2KHR *pCreateInfo, uint32_t *masks)
115 {
116 for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i)
117 {
118 masks[i] = pCreateInfo->pSubpasses[i].viewMask;
119 }
120 return true;
121 }
122
123 } // namespace
124
125 namespace vk {
126
RenderPass(const VkRenderPassCreateInfo * pCreateInfo,void * mem)127 RenderPass::RenderPass(const VkRenderPassCreateInfo *pCreateInfo, void *mem)
128 : attachmentCount(pCreateInfo->attachmentCount)
129 , subpassCount(pCreateInfo->subpassCount)
130 , dependencyCount(pCreateInfo->dependencyCount)
131 {
132 init(pCreateInfo, &mem);
133 }
134
RenderPass(const VkRenderPassCreateInfo2KHR * pCreateInfo,void * mem)135 RenderPass::RenderPass(const VkRenderPassCreateInfo2KHR *pCreateInfo, void *mem)
136 : attachmentCount(pCreateInfo->attachmentCount)
137 , subpassCount(pCreateInfo->subpassCount)
138 , dependencyCount(pCreateInfo->dependencyCount)
139 {
140 init(pCreateInfo, &mem);
141 // Note: the init function above ignores:
142 // - pCorrelatedViewMasks: This provides a potential performance optimization
143 // - VkAttachmentReference2::aspectMask : This specifies which aspects may be used
144 // - VkSubpassDependency2::viewOffset : This is the same as VkRenderPassMultiviewCreateInfo::pViewOffsets, which is currently ignored
145 // - Any pNext pointer in VkRenderPassCreateInfo2KHR's internal structures
146
147 char *hostMemory = reinterpret_cast<char *>(mem);
148
149 // Handle the extensions in each subpass
150 for(uint32_t i = 0; i < subpassCount; i++)
151 {
152 const auto &subpass = pCreateInfo->pSubpasses[i];
153 const auto *extension = reinterpret_cast<const VkBaseInStructure *>(subpass.pNext);
154 while(extension)
155 {
156 switch(extension->sType)
157 {
158 case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE:
159 {
160 const auto *ext = reinterpret_cast<const VkSubpassDescriptionDepthStencilResolve *>(extension);
161 // If any subpass includes depthStencilResolve, allocate a DSR struct for each subpass
162 // This allows us to index into subpassDepthStencilResolves using the subpass index.
163 if(ext->pDepthStencilResolveAttachment != nullptr && ext->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED)
164 {
165 if(subpassDepthStencilResolves == nullptr)
166 {
167 subpassDepthStencilResolves = reinterpret_cast<VkSubpassDescriptionDepthStencilResolve *>(hostMemory);
168 hostMemory += subpassCount * sizeof(VkSubpassDescriptionDepthStencilResolve);
169 for(uint32_t subpass = 0; subpass < subpassCount; subpass++)
170 {
171 subpassDepthStencilResolves[subpass].sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
172 subpassDepthStencilResolves[subpass].pNext = nullptr;
173 subpassDepthStencilResolves[subpass].depthResolveMode = VK_RESOLVE_MODE_NONE;
174 subpassDepthStencilResolves[subpass].stencilResolveMode = VK_RESOLVE_MODE_NONE;
175 subpassDepthStencilResolves[subpass].pDepthStencilResolveAttachment = nullptr;
176 }
177 }
178
179 VkAttachmentReference2 *reference = reinterpret_cast<VkAttachmentReference2 *>(hostMemory);
180 hostMemory += sizeof(VkAttachmentReference2);
181
182 subpassDepthStencilResolves[i].depthResolveMode = ext->depthResolveMode;
183 subpassDepthStencilResolves[i].stencilResolveMode = ext->stencilResolveMode;
184 reference->pNext = nullptr;
185 reference->sType = ext->pDepthStencilResolveAttachment->sType;
186 reference->attachment = ext->pDepthStencilResolveAttachment->attachment;
187 reference->layout = ext->pDepthStencilResolveAttachment->layout;
188 reference->aspectMask = ext->pDepthStencilResolveAttachment->aspectMask;
189 subpassDepthStencilResolves[i].pDepthStencilResolveAttachment = reinterpret_cast<const VkAttachmentReference2 *>(reference);
190
191 MarkFirstUse(reference->attachment, i);
192 }
193 }
194 break;
195 default:
196 UNSUPPORTED("VkRenderPassCreateInfo2KHR->subpass[%d]->pNext sType: %s",
197 i, vk::Stringify(extension->sType).c_str());
198 break;
199 }
200
201 extension = extension->pNext;
202 }
203 }
204 }
205
206 template<class T>
init(const T * pCreateInfo,void ** mem)207 void RenderPass::init(const T *pCreateInfo, void **mem)
208 {
209 char *hostMemory = reinterpret_cast<char *>(*mem);
210
211 // subpassCount must be greater than 0
212 ASSERT(pCreateInfo->subpassCount > 0);
213
214 size_t subpassesSize = pCreateInfo->subpassCount * sizeof(VkSubpassDescription);
215 subpasses = reinterpret_cast<VkSubpassDescription *>(hostMemory);
216 CopySubpasses(subpasses, pCreateInfo->pSubpasses, pCreateInfo->subpassCount);
217 hostMemory += subpassesSize;
218 uint32_t *masks = reinterpret_cast<uint32_t *>(hostMemory);
219 hostMemory += subpassCount * sizeof(uint32_t);
220
221 if(attachmentCount > 0)
222 {
223 size_t attachmentSize = pCreateInfo->attachmentCount * sizeof(VkAttachmentDescription);
224 attachments = reinterpret_cast<VkAttachmentDescription *>(hostMemory);
225 CopyAttachmentDescriptions(attachments, pCreateInfo->pAttachments, pCreateInfo->attachmentCount);
226 hostMemory += attachmentSize;
227
228 size_t firstUseSize = pCreateInfo->attachmentCount * sizeof(int);
229 attachmentFirstUse = reinterpret_cast<int *>(hostMemory);
230 hostMemory += firstUseSize;
231
232 attachmentViewMasks = reinterpret_cast<uint32_t *>(hostMemory);
233 hostMemory += pCreateInfo->attachmentCount * sizeof(uint32_t);
234 for(auto i = 0u; i < pCreateInfo->attachmentCount; i++)
235 {
236 attachmentFirstUse[i] = -1;
237 attachmentViewMasks[i] = 0;
238 }
239 }
240
241 const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
242 while(extensionCreateInfo)
243 {
244 switch(extensionCreateInfo->sType)
245 {
246 case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO:
247 {
248 // Renderpass uses multiview if this structure is present AND some subpass specifies
249 // a nonzero view mask
250 const auto *multiviewCreateInfo = reinterpret_cast<const VkRenderPassMultiviewCreateInfo *>(extensionCreateInfo);
251 for(auto i = 0u; i < pCreateInfo->subpassCount; i++)
252 {
253 masks[i] = multiviewCreateInfo->pViewMasks[i];
254 // This is now a multiview renderpass, so make the masks available
255 if(masks[i])
256 {
257 viewMasks = masks;
258 }
259 }
260 }
261 break;
262 case VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO:
263 // VkRenderPassInputAttachmentAspectCreateInfo has already been handled in libvulkan.
264 break;
265 case VK_STRUCTURE_TYPE_MAX_ENUM:
266 // dEQP tests that this value is ignored.
267 break;
268 default:
269 UNSUPPORTED("pCreateInfo->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());
270 break;
271 }
272
273 extensionCreateInfo = extensionCreateInfo->pNext;
274 }
275
276 if(!viewMasks && (GetViewMasks(pCreateInfo, masks)))
277 {
278 for(auto i = 0u; i < pCreateInfo->subpassCount; i++)
279 {
280 if(masks[i])
281 {
282 viewMasks = masks;
283 }
284 }
285 }
286
287 // Deep copy subpasses
288 for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i)
289 {
290 const auto &subpass = pCreateInfo->pSubpasses[i];
291
292 if(subpass.inputAttachmentCount > 0)
293 {
294 size_t inputAttachmentsSize = subpass.inputAttachmentCount * sizeof(VkAttachmentReference);
295 subpasses[i].pInputAttachments = reinterpret_cast<VkAttachmentReference *>(hostMemory);
296 CopyAttachmentReferences(const_cast<VkAttachmentReference *>(subpasses[i].pInputAttachments),
297 pCreateInfo->pSubpasses[i].pInputAttachments, subpass.inputAttachmentCount);
298 hostMemory += inputAttachmentsSize;
299
300 for(auto j = 0u; j < subpasses[i].inputAttachmentCount; j++)
301 {
302 if(subpass.pInputAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
303 MarkFirstUse(subpass.pInputAttachments[j].attachment, i);
304 }
305 }
306
307 if(subpass.colorAttachmentCount > 0)
308 {
309 size_t colorAttachmentsSize = subpass.colorAttachmentCount * sizeof(VkAttachmentReference);
310 subpasses[i].pColorAttachments = reinterpret_cast<VkAttachmentReference *>(hostMemory);
311 CopyAttachmentReferences(const_cast<VkAttachmentReference *>(subpasses[i].pColorAttachments),
312 subpass.pColorAttachments, subpass.colorAttachmentCount);
313 hostMemory += colorAttachmentsSize;
314
315 if(subpass.pResolveAttachments)
316 {
317 subpasses[i].pResolveAttachments = reinterpret_cast<VkAttachmentReference *>(hostMemory);
318 CopyAttachmentReferences(const_cast<VkAttachmentReference *>(subpasses[i].pResolveAttachments),
319 subpass.pResolveAttachments, subpass.colorAttachmentCount);
320 hostMemory += colorAttachmentsSize;
321 }
322
323 for(auto j = 0u; j < subpasses[i].colorAttachmentCount; j++)
324 {
325 if(subpass.pColorAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
326 MarkFirstUse(subpass.pColorAttachments[j].attachment, i);
327 if(subpass.pResolveAttachments &&
328 subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
329 MarkFirstUse(subpass.pResolveAttachments[j].attachment, i);
330 }
331 }
332
333 if(subpass.pDepthStencilAttachment)
334 {
335 subpasses[i].pDepthStencilAttachment = reinterpret_cast<VkAttachmentReference *>(hostMemory);
336 CopyAttachmentReferences(const_cast<VkAttachmentReference *>(subpasses[i].pDepthStencilAttachment),
337 subpass.pDepthStencilAttachment, 1);
338 hostMemory += sizeof(VkAttachmentReference);
339
340 if(subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
341 MarkFirstUse(subpass.pDepthStencilAttachment->attachment, i);
342 }
343
344 if(subpass.preserveAttachmentCount > 0)
345 {
346 size_t preserveAttachmentSize = subpass.preserveAttachmentCount * sizeof(uint32_t);
347 subpasses[i].pPreserveAttachments = reinterpret_cast<uint32_t *>(hostMemory);
348 for(uint32_t j = 0u; j < subpass.preserveAttachmentCount; j++)
349 {
350 const_cast<uint32_t *>(subpasses[i].pPreserveAttachments)[j] = pCreateInfo->pSubpasses[i].pPreserveAttachments[j];
351 }
352 hostMemory += preserveAttachmentSize;
353
354 for(auto j = 0u; j < subpasses[i].preserveAttachmentCount; j++)
355 {
356 if(subpass.pPreserveAttachments[j] != VK_ATTACHMENT_UNUSED)
357 MarkFirstUse(subpass.pPreserveAttachments[j], i);
358 }
359 }
360 }
361
362 if(pCreateInfo->dependencyCount > 0)
363 {
364 dependencies = reinterpret_cast<VkSubpassDependency *>(hostMemory);
365 CopySubpassDependencies(dependencies, pCreateInfo->pDependencies, pCreateInfo->dependencyCount);
366 hostMemory += dependencyCount * sizeof(VkSubpassDependency);
367 }
368 *mem = hostMemory;
369 }
370
destroy(const VkAllocationCallbacks * pAllocator)371 void RenderPass::destroy(const VkAllocationCallbacks *pAllocator)
372 {
373 vk::freeHostMemory(subpasses, pAllocator); // attachments and dependencies are in the same allocation
374 }
375
ComputeRequiredAllocationSize(const VkRenderPassCreateInfo * pCreateInfo)376 size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo *pCreateInfo)
377 {
378 return ComputeRequiredAllocationSizeT(pCreateInfo);
379 }
380
ComputeRequiredAllocationSize(const VkRenderPassCreateInfo2KHR * pCreateInfo)381 size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo2KHR *pCreateInfo)
382 {
383 size_t requiredMemory = ComputeRequiredAllocationSizeT(pCreateInfo);
384
385 // Calculate the memory required to handle depth stencil resolves
386 bool usesDSR = false;
387 for(uint32_t i = 0; i < pCreateInfo->subpassCount; i++)
388 {
389 const auto &subpass = pCreateInfo->pSubpasses[i];
390 const VkBaseInStructure *extension = reinterpret_cast<const VkBaseInStructure *>(subpass.pNext);
391 while(extension)
392 {
393 switch(extension->sType)
394 {
395 case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE:
396 {
397 const auto *ext = reinterpret_cast<const VkSubpassDescriptionDepthStencilResolve *>(extension);
398 if(ext->pDepthStencilResolveAttachment != nullptr && ext->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED)
399 {
400 if(!usesDSR)
401 {
402 // If any subpass uses DSR, then allocate a VkSubpassDescriptionDepthStencilResolve
403 // for all subpasses. This allows us to index into our DSR structs using the subpass index.
404 requiredMemory += sizeof(VkSubpassDescriptionDepthStencilResolve) * pCreateInfo->subpassCount;
405 usesDSR = true;
406 }
407 // For each subpass that actually uses DSR, allocate a VkAttachmentReference2.
408 requiredMemory += sizeof(VkAttachmentReference2);
409 }
410 }
411 break;
412 default:
413 UNSUPPORTED("VkRenderPassCreateInfo2KHR->subpass[%d]->pNext sType: %s",
414 i, vk::Stringify(extension->sType).c_str());
415 break;
416 }
417
418 extension = extension->pNext;
419 }
420 }
421
422 return requiredMemory;
423 }
424
getRenderAreaGranularity(VkExtent2D * pGranularity) const425 void RenderPass::getRenderAreaGranularity(VkExtent2D *pGranularity) const
426 {
427 pGranularity->width = 1;
428 pGranularity->height = 1;
429 }
430
MarkFirstUse(int attachment,int subpass)431 void RenderPass::MarkFirstUse(int attachment, int subpass)
432 {
433 // FIXME: we may not actually need to track attachmentFirstUse if we're going to eagerly
434 // clear attachments at the start of the renderpass; can use attachmentViewMasks always instead.
435
436 if(attachmentFirstUse[attachment] == -1)
437 attachmentFirstUse[attachment] = subpass;
438
439 if(isMultiView())
440 attachmentViewMasks[attachment] |= viewMasks[subpass];
441 }
442
443 } // namespace vk
444