2 * Copyright © 2016 Red Hat.
3 * Copyright © 2016 Bas Nieuwenhuizen
5 * based in part on anv driver which is:
6 * Copyright © 2015 Intel Corporation
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
27 #include "tu_private.h"
30 #include "vk_format.h"
33 tu_render_pass_add_subpass_dep(struct tu_render_pass
*pass
,
34 const VkSubpassDependency2
*dep
)
36 uint32_t src
= dep
->srcSubpass
;
37 uint32_t dst
= dep
->dstSubpass
;
39 /* Ignore subpass self-dependencies as they allow the app to call
40 * vkCmdPipelineBarrier() inside the render pass and the driver should only
41 * do the barrier when called, not when starting the render pass.
46 struct tu_subpass_barrier
*src_barrier
;
47 if (src
== VK_SUBPASS_EXTERNAL
) {
48 src_barrier
= &pass
->subpasses
[0].start_barrier
;
49 } else if (src
== pass
->subpass_count
- 1) {
50 src_barrier
= &pass
->end_barrier
;
52 src_barrier
= &pass
->subpasses
[src
+ 1].start_barrier
;
55 struct tu_subpass_barrier
*dst_barrier
;
56 if (dst
== VK_SUBPASS_EXTERNAL
) {
57 dst_barrier
= &pass
->end_barrier
;
59 dst_barrier
= &pass
->subpasses
[dst
].start_barrier
;
62 if (dep
->dstStageMask
!= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
)
63 src_barrier
->src_stage_mask
|= dep
->srcStageMask
;
64 src_barrier
->src_access_mask
|= dep
->srcAccessMask
;
65 dst_barrier
->dst_access_mask
|= dep
->dstAccessMask
;
66 if (src
== VK_SUBPASS_EXTERNAL
)
67 pass
->subpasses
[dst
].has_external_src
= true;
68 if (dst
== VK_SUBPASS_EXTERNAL
)
69 pass
->subpasses
[src
].has_external_dst
= true;
72 /* We currently only care about undefined layouts, because we have to
73 * flush/invalidate CCU for those. PREINITIALIZED is the same thing as
74 * UNDEFINED for anything not linear tiled, but we don't know yet whether the
75 * images used are tiled, so just assume they are.
79 layout_undefined(VkImageLayout layout
)
81 return layout
== VK_IMAGE_LAYOUT_UNDEFINED
||
82 layout
== VK_IMAGE_LAYOUT_PREINITIALIZED
;
85 /* This implements the following bit of spec text:
87 * If there is no subpass dependency from VK_SUBPASS_EXTERNAL to the
88 * first subpass that uses an attachment, then an implicit subpass
89 * dependency exists from VK_SUBPASS_EXTERNAL to the first subpass it is
90 * used in. The implicit subpass dependency only exists if there
91 * exists an automatic layout transition away from initialLayout.
92 * The subpass dependency operates as if defined with the
93 * following parameters:
95 * VkSubpassDependency implicitDependency = {
96 * .srcSubpass = VK_SUBPASS_EXTERNAL;
97 * .dstSubpass = firstSubpass; // First subpass attachment is used in
98 * .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
99 * .dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
100 * .srcAccessMask = 0;
101 * .dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
102 * VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
103 * VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
104 * VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
105 * VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
106 * .dependencyFlags = 0;
109 * Similarly, if there is no subpass dependency from the last subpass
110 * that uses an attachment to VK_SUBPASS_EXTERNAL, then an implicit
111 * subpass dependency exists from the last subpass it is used in to
112 * VK_SUBPASS_EXTERNAL. The implicit subpass dependency only exists
113 * if there exists an automatic layout transition into finalLayout.
114 * The subpass dependency operates as if defined with the following
117 * VkSubpassDependency implicitDependency = {
118 * .srcSubpass = lastSubpass; // Last subpass attachment is used in
119 * .dstSubpass = VK_SUBPASS_EXTERNAL;
120 * .srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
121 * .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
122 * .srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
123 * VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
124 * VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
125 * VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
126 * VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
127 * .dstAccessMask = 0;
128 * .dependencyFlags = 0;
131 * Note: currently this is the only use we have for layout transitions,
132 * besides needing to invalidate CCU at the beginning, so we also flag
133 * transitions from UNDEFINED here.
136 tu_render_pass_add_implicit_deps(struct tu_render_pass
*pass
)
138 bool att_used
[pass
->attachment_count
];
140 memset(att_used
, 0, sizeof(att_used
));
142 for (unsigned i
= 0; i
< pass
->subpass_count
; i
++) {
143 struct tu_subpass
*subpass
= &pass
->subpasses
[i
];
144 if (!subpass
->has_external_src
)
147 bool src_implicit_dep
= false;
149 for (unsigned j
= 0; j
< subpass
->input_count
; j
++) {
150 unsigned att_idx
= subpass
->input_attachments
[j
].attachment
;
151 if (att_idx
== VK_ATTACHMENT_UNUSED
)
153 struct tu_render_pass_attachment
*att
= &pass
->attachments
[att_idx
];
154 if (att
->initial_layout
!= subpass
->input_attachments
[j
].layout
&&
155 !att_used
[att_idx
]) {
156 src_implicit_dep
= true;
158 att_used
[att_idx
] = true;
161 for (unsigned j
= 0; j
< subpass
->color_count
; j
++) {
162 unsigned att_idx
= subpass
->color_attachments
[j
].attachment
;
163 if (att_idx
== VK_ATTACHMENT_UNUSED
)
165 struct tu_render_pass_attachment
*att
= &pass
->attachments
[att_idx
];
166 if (att
->initial_layout
!= subpass
->color_attachments
[j
].layout
&&
167 !att_used
[att_idx
]) {
168 src_implicit_dep
= true;
170 att_used
[att_idx
] = true;
173 if (subpass
->resolve_attachments
) {
174 for (unsigned j
= 0; j
< subpass
->color_count
; j
++) {
175 unsigned att_idx
= subpass
->resolve_attachments
[j
].attachment
;
176 if (att_idx
== VK_ATTACHMENT_UNUSED
)
178 struct tu_render_pass_attachment
*att
= &pass
->attachments
[att_idx
];
179 if (att
->initial_layout
!= subpass
->resolve_attachments
[j
].layout
&&
180 !att_used
[att_idx
]) {
181 src_implicit_dep
= true;
183 att_used
[att_idx
] = true;
187 if (src_implicit_dep
) {
188 tu_render_pass_add_subpass_dep(pass
, &(VkSubpassDependency2KHR
) {
189 .srcSubpass
= VK_SUBPASS_EXTERNAL
,
191 .srcStageMask
= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
,
192 .dstStageMask
= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
,
194 .dstAccessMask
= VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
|
195 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
196 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
197 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
198 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
,
199 .dependencyFlags
= 0,
204 memset(att_used
, 0, sizeof(att_used
));
206 for (int i
= pass
->subpass_count
- 1; i
>= 0; i
--) {
207 struct tu_subpass
*subpass
= &pass
->subpasses
[i
];
208 if (!subpass
->has_external_dst
)
211 bool dst_implicit_dep
= false;
213 for (unsigned j
= 0; j
< subpass
->input_count
; j
++) {
214 unsigned att_idx
= subpass
->input_attachments
[j
].attachment
;
215 if (att_idx
== VK_ATTACHMENT_UNUSED
)
217 struct tu_render_pass_attachment
*att
= &pass
->attachments
[att_idx
];
218 if (att
->final_layout
!= subpass
->input_attachments
[j
].layout
&&
219 !att_used
[att_idx
]) {
220 dst_implicit_dep
= true;
222 att_used
[att_idx
] = true;
225 for (unsigned j
= 0; j
< subpass
->color_count
; j
++) {
226 unsigned att_idx
= subpass
->color_attachments
[j
].attachment
;
227 if (att_idx
== VK_ATTACHMENT_UNUSED
)
229 struct tu_render_pass_attachment
*att
= &pass
->attachments
[att_idx
];
230 if (att
->final_layout
!= subpass
->color_attachments
[j
].layout
&&
231 !att_used
[att_idx
]) {
232 dst_implicit_dep
= true;
234 att_used
[att_idx
] = true;
237 if (subpass
->resolve_attachments
) {
238 for (unsigned j
= 0; j
< subpass
->color_count
; j
++) {
239 unsigned att_idx
= subpass
->resolve_attachments
[j
].attachment
;
240 if (att_idx
== VK_ATTACHMENT_UNUSED
)
242 struct tu_render_pass_attachment
*att
= &pass
->attachments
[att_idx
];
243 if (att
->final_layout
!= subpass
->resolve_attachments
[j
].layout
&&
244 !att_used
[att_idx
]) {
245 dst_implicit_dep
= true;
247 att_used
[att_idx
] = true;
251 if (dst_implicit_dep
) {
252 tu_render_pass_add_subpass_dep(pass
, &(VkSubpassDependency2KHR
) {
254 .dstSubpass
= VK_SUBPASS_EXTERNAL
,
255 .srcStageMask
= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
,
256 .dstStageMask
= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
,
257 .srcAccessMask
= VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
|
258 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
259 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
260 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
261 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
,
263 .dependencyFlags
= 0,
268 /* Handle UNDEFINED transitions, similar to the handling in tu_barrier().
269 * Assume that if an attachment has an initial layout of UNDEFINED, it gets
270 * transitioned eventually.
272 for (unsigned i
= 0; i
< pass
->attachment_count
; i
++) {
273 if (layout_undefined(pass
->attachments
[i
].initial_layout
)) {
274 if (vk_format_is_depth_or_stencil(pass
->attachments
[i
].format
)) {
275 pass
->subpasses
[0].start_barrier
.incoherent_ccu_depth
= true;
277 pass
->subpasses
[0].start_barrier
.incoherent_ccu_color
= true;
283 static void update_samples(struct tu_subpass
*subpass
,
284 VkSampleCountFlagBits samples
)
286 assert(subpass
->samples
== 0 || subpass
->samples
== samples
);
287 subpass
->samples
= samples
;
291 create_render_pass_common(struct tu_render_pass
*pass
,
292 const struct tu_physical_device
*phys_dev
)
294 uint32_t block_align_shift
= 4; /* log2(gmem_align/(tile_align_w*tile_align_h)) */
295 uint32_t tile_align_w
= phys_dev
->tile_align_w
;
296 uint32_t gmem_align
= (1 << block_align_shift
) * tile_align_w
* TILE_ALIGN_H
;
298 /* calculate total bytes per pixel */
299 uint32_t cpp_total
= 0;
300 for (uint32_t i
= 0; i
< pass
->attachment_count
; i
++) {
301 struct tu_render_pass_attachment
*att
= &pass
->attachments
[i
];
302 if (att
->gmem_offset
>= 0) {
303 cpp_total
+= att
->cpp
;
304 /* texture pitch must be aligned to 64, use a tile_align_w that is
305 * a multiple of 64 for cpp==1 attachment to work as input attachment
307 if (att
->cpp
== 1 && tile_align_w
% 64 != 0) {
309 block_align_shift
-= 1;
314 pass
->tile_align_w
= tile_align_w
;
316 /* no gmem attachments */
317 if (cpp_total
== 0) {
318 /* any value non-zero value so tiling config works with no attachments */
319 pass
->gmem_pixels
= 1024*1024;
323 /* TODO: using ccu_offset_gmem so that BLIT_OP_SCALE resolve path
324 * doesn't break things. maybe there is a better solution?
325 * TODO: this algorithm isn't optimal
326 * for example, two attachments with cpp = {1, 4}
327 * result: nblocks = {12, 52}, pixels = 196608
328 * optimal: nblocks = {13, 51}, pixels = 208896
330 uint32_t gmem_blocks
= phys_dev
->ccu_offset_gmem
/ gmem_align
;
331 uint32_t offset
= 0, pixels
= ~0u;
332 for (uint32_t i
= 0; i
< pass
->attachment_count
; i
++) {
333 struct tu_render_pass_attachment
*att
= &pass
->attachments
[i
];
334 if (att
->gmem_offset
< 0)
337 att
->gmem_offset
= offset
;
339 uint32_t align
= MAX2(1, att
->cpp
>> block_align_shift
);
340 uint32_t nblocks
= MAX2((gmem_blocks
* att
->cpp
/ cpp_total
) & ~(align
- 1), align
);
342 if (nblocks
> gmem_blocks
) {
347 gmem_blocks
-= nblocks
;
348 cpp_total
-= att
->cpp
;
349 offset
+= nblocks
* gmem_align
;
350 pixels
= MIN2(pixels
, nblocks
* gmem_align
/ att
->cpp
);
353 pass
->gmem_pixels
= pixels
;
355 for (uint32_t i
= 0; i
< pass
->subpass_count
; i
++) {
356 struct tu_subpass
*subpass
= &pass
->subpasses
[i
];
358 subpass
->srgb_cntl
= 0;
360 for (uint32_t i
= 0; i
< subpass
->color_count
; ++i
) {
361 uint32_t a
= subpass
->color_attachments
[i
].attachment
;
362 if (a
== VK_ATTACHMENT_UNUSED
)
365 if (vk_format_is_srgb(pass
->attachments
[a
].format
))
366 subpass
->srgb_cntl
|= 1 << i
;
370 /* disable unused attachments */
371 for (uint32_t i
= 0; i
< pass
->attachment_count
; i
++) {
372 struct tu_render_pass_attachment
*att
= &pass
->attachments
[i
];
373 if (att
->gmem_offset
< 0) {
379 tu_render_pass_add_implicit_deps(pass
);
383 attachment_set_ops(struct tu_render_pass_attachment
*att
,
384 VkAttachmentLoadOp load_op
,
385 VkAttachmentLoadOp stencil_load_op
,
386 VkAttachmentStoreOp store_op
,
387 VkAttachmentStoreOp stencil_store_op
)
391 (load_op
== VK_ATTACHMENT_LOAD_OP_CLEAR
) ? VK_IMAGE_ASPECT_COLOR_BIT
: 0;
392 att
->load
= (load_op
== VK_ATTACHMENT_LOAD_OP_LOAD
);
393 att
->store
= (store_op
== VK_ATTACHMENT_STORE_OP_STORE
);
395 bool stencil_clear
= (stencil_load_op
== VK_ATTACHMENT_LOAD_OP_CLEAR
);
396 bool stencil_load
= (stencil_load_op
== VK_ATTACHMENT_LOAD_OP_LOAD
);
397 bool stencil_store
= (stencil_store_op
== VK_ATTACHMENT_STORE_OP_STORE
);
399 switch (att
->format
) {
400 case VK_FORMAT_D24_UNORM_S8_UINT
: /* || stencil load/store */
402 att
->clear_mask
= VK_IMAGE_ASPECT_DEPTH_BIT
;
404 att
->clear_mask
|= VK_IMAGE_ASPECT_STENCIL_BIT
;
410 case VK_FORMAT_S8_UINT
: /* replace load/store with stencil load/store */
411 att
->clear_mask
= stencil_clear
? VK_IMAGE_ASPECT_COLOR_BIT
: 0;
412 att
->load
= stencil_load
;
413 att
->store
= stencil_store
;
421 translate_references(VkAttachmentReference2
**reference_ptr
,
422 const VkAttachmentReference
*reference
,
425 VkAttachmentReference2
*reference2
= *reference_ptr
;
426 *reference_ptr
+= count
;
427 for (uint32_t i
= 0; i
< count
; i
++) {
428 reference2
[i
] = (VkAttachmentReference2
) {
429 .sType
= VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2
,
431 .attachment
= reference
[i
].attachment
,
432 .layout
= reference
[i
].layout
,
433 .aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
| VK_IMAGE_ASPECT_DEPTH_BIT
| VK_IMAGE_ASPECT_STENCIL_BIT
,
439 tu_CreateRenderPass(VkDevice device
,
440 const VkRenderPassCreateInfo
*pCreateInfo
,
441 const VkAllocationCallbacks
*pAllocator
,
442 VkRenderPass
*pRenderPass
)
444 /* note: these counts shouldn't be excessively high, so allocating it all
445 * on the stack should be OK..
446 * also note preserve attachments aren't translated, currently unused
448 VkAttachmentDescription2 attachments
[pCreateInfo
->attachmentCount
];
449 VkSubpassDescription2 subpasses
[pCreateInfo
->subpassCount
];
450 VkSubpassDependency2 dependencies
[pCreateInfo
->dependencyCount
];
451 uint32_t reference_count
= 0;
452 for (uint32_t i
= 0; i
< pCreateInfo
->subpassCount
; i
++) {
453 reference_count
+= pCreateInfo
->pSubpasses
[i
].inputAttachmentCount
;
454 reference_count
+= pCreateInfo
->pSubpasses
[i
].colorAttachmentCount
;
455 if (pCreateInfo
->pSubpasses
[i
].pResolveAttachments
)
456 reference_count
+= pCreateInfo
->pSubpasses
[i
].colorAttachmentCount
;
457 if (pCreateInfo
->pSubpasses
[i
].pDepthStencilAttachment
)
458 reference_count
+= 1;
460 VkAttachmentReference2 reference
[reference_count
];
461 VkAttachmentReference2
*reference_ptr
= reference
;
463 for (uint32_t i
= 0; i
< pCreateInfo
->attachmentCount
; i
++) {
464 attachments
[i
] = (VkAttachmentDescription2
) {
465 .sType
= VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2
,
467 .flags
= pCreateInfo
->pAttachments
[i
].flags
,
468 .format
= pCreateInfo
->pAttachments
[i
].format
,
469 .samples
= pCreateInfo
->pAttachments
[i
].samples
,
470 .loadOp
= pCreateInfo
->pAttachments
[i
].loadOp
,
471 .storeOp
= pCreateInfo
->pAttachments
[i
].storeOp
,
472 .stencilLoadOp
= pCreateInfo
->pAttachments
[i
].stencilLoadOp
,
473 .stencilStoreOp
= pCreateInfo
->pAttachments
[i
].stencilStoreOp
,
474 .initialLayout
= pCreateInfo
->pAttachments
[i
].initialLayout
,
475 .finalLayout
= pCreateInfo
->pAttachments
[i
].finalLayout
,
479 for (uint32_t i
= 0; i
< pCreateInfo
->subpassCount
; i
++) {
480 subpasses
[i
] = (VkSubpassDescription2
) {
481 .sType
= VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2
,
483 .flags
= pCreateInfo
->pSubpasses
[i
].flags
,
484 .pipelineBindPoint
= pCreateInfo
->pSubpasses
[i
].pipelineBindPoint
,
486 .inputAttachmentCount
= pCreateInfo
->pSubpasses
[i
].inputAttachmentCount
,
487 .colorAttachmentCount
= pCreateInfo
->pSubpasses
[i
].colorAttachmentCount
,
490 subpasses
[i
].pInputAttachments
= reference_ptr
;
491 translate_references(&reference_ptr
,
492 pCreateInfo
->pSubpasses
[i
].pInputAttachments
,
493 subpasses
[i
].inputAttachmentCount
);
494 subpasses
[i
].pColorAttachments
= reference_ptr
;
495 translate_references(&reference_ptr
,
496 pCreateInfo
->pSubpasses
[i
].pColorAttachments
,
497 subpasses
[i
].colorAttachmentCount
);
498 subpasses
[i
].pResolveAttachments
= NULL
;
499 if (pCreateInfo
->pSubpasses
[i
].pResolveAttachments
) {
500 subpasses
[i
].pResolveAttachments
= reference_ptr
;
501 translate_references(&reference_ptr
,
502 pCreateInfo
->pSubpasses
[i
].pResolveAttachments
,
503 subpasses
[i
].colorAttachmentCount
);
505 subpasses
[i
].pDepthStencilAttachment
= NULL
;
506 if (pCreateInfo
->pSubpasses
[i
].pDepthStencilAttachment
) {
507 subpasses
[i
].pDepthStencilAttachment
= reference_ptr
;
508 translate_references(&reference_ptr
,
509 pCreateInfo
->pSubpasses
[i
].pDepthStencilAttachment
,
514 assert(reference_ptr
== reference
+ reference_count
);
516 for (uint32_t i
= 0; i
< pCreateInfo
->dependencyCount
; i
++) {
517 dependencies
[i
] = (VkSubpassDependency2
) {
518 .sType
= VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2
,
520 .srcSubpass
= pCreateInfo
->pDependencies
[i
].srcSubpass
,
521 .dstSubpass
= pCreateInfo
->pDependencies
[i
].dstSubpass
,
522 .srcStageMask
= pCreateInfo
->pDependencies
[i
].srcStageMask
,
523 .dstStageMask
= pCreateInfo
->pDependencies
[i
].dstStageMask
,
524 .srcAccessMask
= pCreateInfo
->pDependencies
[i
].srcAccessMask
,
525 .dstAccessMask
= pCreateInfo
->pDependencies
[i
].dstAccessMask
,
526 .dependencyFlags
= pCreateInfo
->pDependencies
[i
].dependencyFlags
,
531 VkRenderPassCreateInfo2 create_info
= {
532 .sType
= VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2
,
533 .pNext
= pCreateInfo
->pNext
,
534 .flags
= pCreateInfo
->flags
,
535 .attachmentCount
= pCreateInfo
->attachmentCount
,
536 .pAttachments
= attachments
,
537 .subpassCount
= pCreateInfo
->subpassCount
,
538 .pSubpasses
= subpasses
,
539 .dependencyCount
= pCreateInfo
->dependencyCount
,
540 .pDependencies
= dependencies
,
543 return tu_CreateRenderPass2(device
, &create_info
, pAllocator
, pRenderPass
);
547 tu_CreateRenderPass2(VkDevice _device
,
548 const VkRenderPassCreateInfo2KHR
*pCreateInfo
,
549 const VkAllocationCallbacks
*pAllocator
,
550 VkRenderPass
*pRenderPass
)
552 TU_FROM_HANDLE(tu_device
, device
, _device
);
553 struct tu_render_pass
*pass
;
555 size_t attachments_offset
;
557 assert(pCreateInfo
->sType
== VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR
);
559 size
= sizeof(*pass
);
560 size
+= pCreateInfo
->subpassCount
* sizeof(pass
->subpasses
[0]);
561 attachments_offset
= size
;
562 size
+= pCreateInfo
->attachmentCount
* sizeof(pass
->attachments
[0]);
564 pass
= vk_zalloc2(&device
->alloc
, pAllocator
, size
, 8,
565 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
567 return vk_error(device
->instance
, VK_ERROR_OUT_OF_HOST_MEMORY
);
569 pass
->attachment_count
= pCreateInfo
->attachmentCount
;
570 pass
->subpass_count
= pCreateInfo
->subpassCount
;
571 pass
->attachments
= (void *) pass
+ attachments_offset
;
573 for (uint32_t i
= 0; i
< pCreateInfo
->attachmentCount
; i
++) {
574 struct tu_render_pass_attachment
*att
= &pass
->attachments
[i
];
576 att
->format
= pCreateInfo
->pAttachments
[i
].format
;
577 att
->samples
= pCreateInfo
->pAttachments
[i
].samples
;
578 att
->cpp
= vk_format_get_blocksize(att
->format
) * att
->samples
;
579 att
->initial_layout
= pCreateInfo
->pAttachments
[i
].initialLayout
;
580 att
->final_layout
= pCreateInfo
->pAttachments
[i
].finalLayout
;
581 att
->gmem_offset
= -1;
583 attachment_set_ops(att
,
584 pCreateInfo
->pAttachments
[i
].loadOp
,
585 pCreateInfo
->pAttachments
[i
].stencilLoadOp
,
586 pCreateInfo
->pAttachments
[i
].storeOp
,
587 pCreateInfo
->pAttachments
[i
].stencilStoreOp
);
589 uint32_t subpass_attachment_count
= 0;
590 struct tu_subpass_attachment
*p
;
591 for (uint32_t i
= 0; i
< pCreateInfo
->subpassCount
; i
++) {
592 const VkSubpassDescription2KHR
*desc
= &pCreateInfo
->pSubpasses
[i
];
594 subpass_attachment_count
+=
595 desc
->inputAttachmentCount
+ desc
->colorAttachmentCount
+
596 (desc
->pResolveAttachments
? desc
->colorAttachmentCount
: 0);
599 if (subpass_attachment_count
) {
600 pass
->subpass_attachments
= vk_alloc2(
601 &device
->alloc
, pAllocator
,
602 subpass_attachment_count
* sizeof(struct tu_subpass_attachment
), 8,
603 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
604 if (pass
->subpass_attachments
== NULL
) {
605 vk_free2(&device
->alloc
, pAllocator
, pass
);
606 return vk_error(device
->instance
, VK_ERROR_OUT_OF_HOST_MEMORY
);
609 pass
->subpass_attachments
= NULL
;
611 p
= pass
->subpass_attachments
;
612 for (uint32_t i
= 0; i
< pCreateInfo
->subpassCount
; i
++) {
613 const VkSubpassDescription2KHR
*desc
= &pCreateInfo
->pSubpasses
[i
];
614 struct tu_subpass
*subpass
= &pass
->subpasses
[i
];
616 subpass
->input_count
= desc
->inputAttachmentCount
;
617 subpass
->color_count
= desc
->colorAttachmentCount
;
618 subpass
->samples
= 0;
620 if (desc
->inputAttachmentCount
> 0) {
621 subpass
->input_attachments
= p
;
622 p
+= desc
->inputAttachmentCount
;
624 for (uint32_t j
= 0; j
< desc
->inputAttachmentCount
; j
++) {
625 uint32_t a
= desc
->pInputAttachments
[j
].attachment
;
626 subpass
->input_attachments
[j
].attachment
= a
;
627 subpass
->input_attachments
[j
].layout
=
628 desc
->pInputAttachments
[j
].layout
;
629 if (a
!= VK_ATTACHMENT_UNUSED
)
630 pass
->attachments
[a
].gmem_offset
= 0;
634 if (desc
->colorAttachmentCount
> 0) {
635 subpass
->color_attachments
= p
;
636 p
+= desc
->colorAttachmentCount
;
638 for (uint32_t j
= 0; j
< desc
->colorAttachmentCount
; j
++) {
639 uint32_t a
= desc
->pColorAttachments
[j
].attachment
;
640 subpass
->color_attachments
[j
].attachment
= a
;
641 subpass
->color_attachments
[j
].layout
=
642 desc
->pColorAttachments
[j
].layout
;
644 if (a
!= VK_ATTACHMENT_UNUSED
) {
645 pass
->attachments
[a
].gmem_offset
= 0;
646 update_samples(subpass
, pCreateInfo
->pAttachments
[a
].samples
);
651 subpass
->resolve_attachments
= desc
->pResolveAttachments
? p
: NULL
;
652 if (desc
->pResolveAttachments
) {
653 p
+= desc
->colorAttachmentCount
;
654 for (uint32_t j
= 0; j
< desc
->colorAttachmentCount
; j
++) {
655 subpass
->resolve_attachments
[j
].attachment
=
656 desc
->pResolveAttachments
[j
].attachment
;
657 subpass
->resolve_attachments
[j
].layout
=
658 desc
->pResolveAttachments
[j
].layout
;
663 uint32_t a
= desc
->pDepthStencilAttachment
?
664 desc
->pDepthStencilAttachment
->attachment
: VK_ATTACHMENT_UNUSED
;
665 subpass
->depth_stencil_attachment
.attachment
= a
;
666 if (a
!= VK_ATTACHMENT_UNUSED
) {
667 pass
->attachments
[a
].gmem_offset
= 0;
668 subpass
->depth_stencil_attachment
.layout
=
669 desc
->pDepthStencilAttachment
->layout
;
670 update_samples(subpass
, pCreateInfo
->pAttachments
[a
].samples
);
673 subpass
->samples
= subpass
->samples
?: 1;
676 for (unsigned i
= 0; i
< pCreateInfo
->dependencyCount
; ++i
) {
677 tu_render_pass_add_subpass_dep(pass
, &pCreateInfo
->pDependencies
[i
]);
680 *pRenderPass
= tu_render_pass_to_handle(pass
);
682 create_render_pass_common(pass
, device
->physical_device
);
688 tu_DestroyRenderPass(VkDevice _device
,
690 const VkAllocationCallbacks
*pAllocator
)
692 TU_FROM_HANDLE(tu_device
, device
, _device
);
693 TU_FROM_HANDLE(tu_render_pass
, pass
, _pass
);
698 vk_free2(&device
->alloc
, pAllocator
, pass
->subpass_attachments
);
699 vk_free2(&device
->alloc
, pAllocator
, pass
);
703 tu_GetRenderAreaGranularity(VkDevice _device
,
704 VkRenderPass renderPass
,
705 VkExtent2D
*pGranularity
)
707 pGranularity
->width
= GMEM_ALIGN_W
;
708 pGranularity
->height
= GMEM_ALIGN_H
;