1 /*
2  * Copyright 2018 Collabora Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "zink_render_pass.h"
25 
26 #include "zink_screen.h"
27 
28 #include "util/u_memory.h"
29 #include "util/u_string.h"
30 
31 static VkRenderPass
create_render_pass(struct zink_screen * screen,struct zink_render_pass_state * state,struct zink_render_pass_pipeline_state * pstate)32 create_render_pass(struct zink_screen *screen, struct zink_render_pass_state *state, struct zink_render_pass_pipeline_state *pstate)
33 {
34 
35    VkAttachmentReference color_refs[PIPE_MAX_COLOR_BUFS], zs_ref;
36    VkAttachmentReference input_attachments[PIPE_MAX_COLOR_BUFS];
37    VkAttachmentDescription attachments[PIPE_MAX_COLOR_BUFS + 1];
38    VkPipelineStageFlags dep_pipeline = 0;
39    VkAccessFlags dep_access = 0;
40    unsigned input_count = 0;
41 
42    pstate->num_attachments = state->num_cbufs;
43    for (int i = 0; i < state->num_cbufs; i++) {
44       struct zink_rt_attrib *rt = state->rts + i;
45       attachments[i].flags = 0;
46       pstate->attachments[i].format = attachments[i].format = rt->format;
47       pstate->attachments[i].samples = attachments[i].samples = rt->samples;
48       attachments[i].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR :
49                                                 state->swapchain_init && rt->swapchain ?
50                                                 VK_ATTACHMENT_LOAD_OP_DONT_CARE :
51                                                 VK_ATTACHMENT_LOAD_OP_LOAD;
52       attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
53       attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
54       attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
55       /* if layout changes are ever handled here, need VkAttachmentSampleLocationsEXT */
56       VkImageLayout layout = rt->fbfetch ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
57       attachments[i].initialLayout = layout;
58       attachments[i].finalLayout = layout;
59       color_refs[i].attachment = i;
60       color_refs[i].layout = layout;
61       dep_pipeline |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
62       if (rt->fbfetch)
63          memcpy(&input_attachments[input_count++], &color_refs[i], sizeof(VkAttachmentReference));
64       dep_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
65       if (attachments[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
66          dep_access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
67    }
68 
69    int num_attachments = state->num_cbufs;
70    if (state->have_zsbuf)  {
71       struct zink_rt_attrib *rt = state->rts + state->num_cbufs;
72       bool has_clear = rt->clear_color || rt->clear_stencil;
73       VkImageLayout layout = rt->needs_write || has_clear ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
74       attachments[num_attachments].flags = 0;
75       pstate->attachments[num_attachments].format = attachments[num_attachments].format = rt->format;
76       pstate->attachments[num_attachments].samples = attachments[num_attachments].samples = rt->samples;
77       attachments[num_attachments].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
78       attachments[num_attachments].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
79       attachments[num_attachments].stencilLoadOp = rt->clear_stencil ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
80       attachments[num_attachments].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
81       /* if layout changes are ever handled here, need VkAttachmentSampleLocationsEXT */
82       attachments[num_attachments].initialLayout = layout;
83       attachments[num_attachments].finalLayout = layout;
84 
85       dep_pipeline |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
86       if (layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
87          dep_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
88       if (attachments[num_attachments].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ||
89           attachments[num_attachments].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
90          dep_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
91 
92       zs_ref.attachment = num_attachments++;
93       zs_ref.layout = layout;
94       pstate->num_attachments++;
95    }
96 
97    VkSubpassDependency deps[] = {
98       [0] = {VK_SUBPASS_EXTERNAL, 0, dep_pipeline, dep_pipeline, 0, dep_access, VK_DEPENDENCY_BY_REGION_BIT},
99       [1] = {0, VK_SUBPASS_EXTERNAL, dep_pipeline, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, dep_access, 0, VK_DEPENDENCY_BY_REGION_BIT}
100    };
101 
102    VkSubpassDescription subpass = {0};
103    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
104    subpass.colorAttachmentCount = state->num_cbufs;
105    subpass.pColorAttachments = color_refs;
106    subpass.pDepthStencilAttachment = state->have_zsbuf ? &zs_ref : NULL;
107    subpass.inputAttachmentCount = input_count;
108    subpass.pInputAttachments = input_attachments;
109 
110    VkRenderPassCreateInfo rpci = {0};
111    rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
112    rpci.attachmentCount = num_attachments;
113    rpci.pAttachments = attachments;
114    rpci.subpassCount = 1;
115    rpci.pSubpasses = &subpass;
116    rpci.dependencyCount = 2;
117    rpci.pDependencies = deps;
118 
119    VkRenderPass render_pass;
120    if (VKSCR(CreateRenderPass)(screen->dev, &rpci, NULL, &render_pass) != VK_SUCCESS) {
121       debug_printf("vkCreateRenderPass failed\n");
122       return VK_NULL_HANDLE;
123    }
124 
125    return render_pass;
126 }
127 
128 static VkRenderPass
create_render_pass2(struct zink_screen * screen,struct zink_render_pass_state * state,struct zink_render_pass_pipeline_state * pstate)129 create_render_pass2(struct zink_screen *screen, struct zink_render_pass_state *state, struct zink_render_pass_pipeline_state *pstate)
130 {
131 
132    VkAttachmentReference2 color_refs[PIPE_MAX_COLOR_BUFS], color_resolves[PIPE_MAX_COLOR_BUFS], zs_ref, zs_resolve;
133    VkAttachmentReference2 input_attachments[PIPE_MAX_COLOR_BUFS];
134    VkAttachmentDescription2 attachments[2 * (PIPE_MAX_COLOR_BUFS + 1)];
135    VkPipelineStageFlags dep_pipeline = 0;
136    VkAccessFlags dep_access = 0;
137    unsigned input_count = 0;
138    const unsigned cresolve_offset = state->num_cbufs + state->have_zsbuf;
139    const unsigned zsresolve_offset = cresolve_offset + state->num_cresolves;
140 
141    pstate->num_attachments = state->num_cbufs;
142    pstate->num_cresolves = state->num_cresolves;
143    pstate->num_zsresolves = state->num_zsresolves;
144    for (int i = 0; i < state->num_cbufs; i++) {
145       struct zink_rt_attrib *rt = state->rts + i;
146       attachments[i].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
147       attachments[i].pNext = NULL;
148       attachments[i].flags = 0;
149       pstate->attachments[i].format = attachments[i].format = rt->format;
150       pstate->attachments[i].samples = attachments[i].samples = rt->samples;
151       attachments[i].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR :
152                                                 /* TODO: need replicate EXT */
153                                                 //rt->resolve || (state->swapchain_init && rt->swapchain) ?
154                                                 state->swapchain_init && rt->swapchain ?
155                                                 VK_ATTACHMENT_LOAD_OP_DONT_CARE :
156                                                 VK_ATTACHMENT_LOAD_OP_LOAD;
157 
158       /* TODO: need replicate EXT */
159       //attachments[i].storeOp = rt->resolve ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
160       attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
161       attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
162       attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
163       /* if layout changes are ever handled here, need VkAttachmentSampleLocationsEXT */
164       VkImageLayout layout = rt->fbfetch ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
165       attachments[i].initialLayout = layout;
166       attachments[i].finalLayout = layout;
167       color_refs[i].sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
168       color_refs[i].pNext = NULL;
169       color_refs[i].attachment = i;
170       color_refs[i].layout = layout;
171       color_refs[i].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
172       dep_pipeline |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
173       if (rt->fbfetch)
174          memcpy(&input_attachments[input_count++], &color_refs[i], sizeof(VkAttachmentReference2));
175       dep_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
176       if (attachments[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
177          dep_access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
178 
179       if (rt->resolve) {
180          memcpy(&attachments[cresolve_offset + i], &attachments[i], sizeof(VkAttachmentDescription2));
181          attachments[cresolve_offset + i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
182          attachments[cresolve_offset + i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
183          attachments[cresolve_offset + i].samples = 1;
184          memcpy(&color_resolves[i], &color_refs[i], sizeof(VkAttachmentReference2));
185          color_resolves[i].attachment = cresolve_offset + i;
186          if (attachments[cresolve_offset + i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
187             dep_access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
188       }
189    }
190 
191    int num_attachments = state->num_cbufs;
192    if (state->have_zsbuf)  {
193       struct zink_rt_attrib *rt = state->rts + state->num_cbufs;
194       bool has_clear = rt->clear_color || rt->clear_stencil;
195       VkImageLayout layout = rt->needs_write || has_clear ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
196       attachments[num_attachments].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
197       attachments[num_attachments].pNext = NULL;
198       attachments[num_attachments].flags = 0;
199       pstate->attachments[num_attachments].format = attachments[num_attachments].format = rt->format;
200       pstate->attachments[num_attachments].samples = attachments[num_attachments].samples = rt->samples;
201       attachments[num_attachments].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
202       attachments[num_attachments].stencilLoadOp = rt->clear_stencil ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
203       /* TODO: need replicate EXT */
204       //attachments[num_attachments].storeOp = rt->resolve ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
205       //attachments[num_attachments].stencilStoreOp = rt->resolve ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
206       attachments[num_attachments].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
207       attachments[num_attachments].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
208       /* if layout changes are ever handled here, need VkAttachmentSampleLocationsEXT */
209       attachments[num_attachments].initialLayout = layout;
210       attachments[num_attachments].finalLayout = layout;
211 
212       dep_pipeline |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
213       if (layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
214          dep_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
215       if (attachments[num_attachments].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ||
216           attachments[num_attachments].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
217          dep_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
218 
219       zs_ref.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
220       zs_ref.pNext = NULL;
221       zs_ref.attachment = num_attachments++;
222       zs_ref.layout = layout;
223       if (rt->resolve) {
224          memcpy(&attachments[zsresolve_offset], &attachments[num_attachments], sizeof(VkAttachmentDescription2));
225          attachments[zsresolve_offset].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
226          attachments[zsresolve_offset].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
227          attachments[zsresolve_offset].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
228          attachments[zsresolve_offset].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
229          attachments[zsresolve_offset].samples = 1;
230          memcpy(&zs_resolve, &zs_ref, sizeof(VkAttachmentReference2));
231          zs_ref.attachment = zsresolve_offset;
232          if (attachments[zsresolve_offset].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ||
233              attachments[zsresolve_offset].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
234             dep_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
235       }
236       pstate->num_attachments++;
237    }
238 
239    VkSubpassDependency2 deps[] = {
240       [0] = {VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, NULL, VK_SUBPASS_EXTERNAL, 0, dep_pipeline, dep_pipeline, 0, dep_access, VK_DEPENDENCY_BY_REGION_BIT, 0},
241       [1] = {VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, NULL, 0, VK_SUBPASS_EXTERNAL, dep_pipeline, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, dep_access, 0, VK_DEPENDENCY_BY_REGION_BIT, 0}
242    };
243 
244    VkSubpassDescription2 subpass = {0};
245    VkSubpassDescriptionDepthStencilResolve zsresolve;
246    subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
247    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
248    subpass.colorAttachmentCount = state->num_cbufs;
249    subpass.pColorAttachments = color_refs;
250    subpass.pDepthStencilAttachment = state->have_zsbuf ? &zs_ref : NULL;
251    subpass.inputAttachmentCount = input_count;
252    subpass.pInputAttachments = input_attachments;
253    if (state->num_cresolves)
254       subpass.pResolveAttachments = color_resolves;
255    if (state->num_zsresolves) {
256       subpass.pNext = &zsresolve;
257       zsresolve.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
258       zsresolve.pNext = NULL;
259       zsresolve.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
260       zsresolve.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
261       zsresolve.pDepthStencilResolveAttachment = &zs_resolve;
262    } else
263       subpass.pNext = NULL;
264 
265    VkRenderPassCreateInfo2 rpci = {0};
266    rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2;
267    rpci.attachmentCount = num_attachments + state->num_cresolves + state->num_zsresolves;
268    rpci.pAttachments = attachments;
269    rpci.subpassCount = 1;
270    rpci.pSubpasses = &subpass;
271    rpci.dependencyCount = 2;
272    rpci.pDependencies = deps;
273 
274    VkRenderPass render_pass;
275    if (VKSCR(CreateRenderPass2)(screen->dev, &rpci, NULL, &render_pass) != VK_SUCCESS) {
276       debug_printf("vkCreateRenderPass2 failed\n");
277       return VK_NULL_HANDLE;
278    }
279 
280    return render_pass;
281 }
282 
283 struct zink_render_pass *
zink_create_render_pass(struct zink_screen * screen,struct zink_render_pass_state * state,struct zink_render_pass_pipeline_state * pstate)284 zink_create_render_pass(struct zink_screen *screen,
285                         struct zink_render_pass_state *state,
286                         struct zink_render_pass_pipeline_state *pstate)
287 {
288    struct zink_render_pass *rp = CALLOC_STRUCT(zink_render_pass);
289    if (!rp)
290       goto fail;
291 
292    rp->render_pass = screen->vk_version >= VK_MAKE_VERSION(1,2,0) ?
293                      create_render_pass2(screen, state, pstate) : create_render_pass(screen, state, pstate);
294    if (!rp->render_pass)
295       goto fail;
296    memcpy(&rp->state, state, sizeof(struct zink_render_pass_state));
297    return rp;
298 
299 fail:
300    if (rp)
301       zink_destroy_render_pass(screen, rp);
302    return NULL;
303 }
304 
305 void
zink_destroy_render_pass(struct zink_screen * screen,struct zink_render_pass * rp)306 zink_destroy_render_pass(struct zink_screen *screen,
307                          struct zink_render_pass *rp)
308 {
309    VKSCR(DestroyRenderPass)(screen->dev, rp->render_pass, NULL);
310    FREE(rp);
311 }
312 
313 VkImageLayout
zink_render_pass_attachment_get_barrier_info(const struct zink_render_pass * rp,unsigned idx,VkPipelineStageFlags * pipeline,VkAccessFlags * access)314 zink_render_pass_attachment_get_barrier_info(const struct zink_render_pass *rp, unsigned idx,
315                                              VkPipelineStageFlags *pipeline, VkAccessFlags *access)
316 {
317    *access = 0;
318    assert(idx < rp->state.num_rts);
319    const struct zink_rt_attrib *rt = &rp->state.rts[idx];
320    if (idx < rp->state.num_cbufs) {
321       *pipeline = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
322       *access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
323       if (!rt->clear_color && (!rp->state.swapchain_init || !rt->swapchain))
324          *access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
325       return rt->fbfetch ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
326    }
327 
328    assert(rp->state.have_zsbuf);
329    *pipeline = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
330    if (!rp->state.rts[idx].clear_color && !rp->state.rts[idx].clear_stencil)
331       *access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
332    if (!rp->state.rts[idx].clear_color && !rp->state.rts[idx].clear_stencil && !rp->state.rts[idx].needs_write)
333       return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
334    *access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
335    return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
336 }
337