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_context.h"
25 #include "zink_framebuffer.h"
26
27 #include "zink_render_pass.h"
28 #include "zink_screen.h"
29 #include "zink_surface.h"
30
31 #include "util/u_framebuffer.h"
32 #include "util/u_memory.h"
33 #include "util/u_string.h"
34
35 void
zink_destroy_framebuffer(struct zink_screen * screen,struct zink_framebuffer * fb)36 zink_destroy_framebuffer(struct zink_screen *screen,
37 struct zink_framebuffer *fb)
38 {
39 hash_table_foreach(&fb->objects, he) {
40 #if defined(_WIN64) || defined(__x86_64__)
41 VKSCR(DestroyFramebuffer)(screen->dev, he->data, NULL);
42 #else
43 VkFramebuffer *ptr = he->data;
44 VKSCR(DestroyFramebuffer)(screen->dev, *ptr, NULL);
45 #endif
46 }
47
48 ralloc_free(fb);
49 }
50
51 void
zink_init_framebuffer_imageless(struct zink_screen * screen,struct zink_framebuffer * fb,struct zink_render_pass * rp)52 zink_init_framebuffer_imageless(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp)
53 {
54 VkFramebuffer ret;
55
56 if (fb->rp == rp)
57 return;
58
59 uint32_t hash = _mesa_hash_pointer(rp);
60
61 struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&fb->objects, hash, rp);
62 if (he) {
63 #if defined(_WIN64) || defined(__x86_64__)
64 ret = (VkFramebuffer)he->data;
65 #else
66 VkFramebuffer *ptr = he->data;
67 ret = *ptr;
68 #endif
69 goto out;
70 }
71
72 assert(rp->state.num_cbufs + rp->state.have_zsbuf + rp->state.num_cresolves + rp->state.num_zsresolves == fb->state.num_attachments);
73
74 VkFramebufferCreateInfo fci;
75 fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
76 fci.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT;
77 fci.renderPass = rp->render_pass;
78 fci.attachmentCount = fb->state.num_attachments;
79 fci.pAttachments = NULL;
80 fci.width = fb->state.width;
81 fci.height = fb->state.height;
82 fci.layers = fb->state.layers + 1;
83
84 VkFramebufferAttachmentsCreateInfo attachments;
85 attachments.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO;
86 attachments.pNext = NULL;
87 attachments.attachmentImageInfoCount = fb->state.num_attachments;
88 attachments.pAttachmentImageInfos = fb->infos;
89 fci.pNext = &attachments;
90
91 if (VKSCR(CreateFramebuffer)(screen->dev, &fci, NULL, &ret) != VK_SUCCESS)
92 return;
93 #if defined(_WIN64) || defined(__x86_64__)
94 _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ret);
95 #else
96 VkFramebuffer *ptr = ralloc(fb, VkFramebuffer);
97 if (!ptr) {
98 VKSCR(DestroyFramebuffer)(screen->dev, ret, NULL);
99 return;
100 }
101 *ptr = ret;
102 _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ptr);
103 #endif
104 out:
105 fb->rp = rp;
106 fb->fb = ret;
107 }
108
109 static void
populate_attachment_info(VkFramebufferAttachmentImageInfo * att,struct zink_surface_info * info)110 populate_attachment_info(VkFramebufferAttachmentImageInfo *att, struct zink_surface_info *info)
111 {
112 att->sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO;
113 att->pNext = NULL;
114 memcpy(&att->flags, &info->flags, offsetof(struct zink_surface_info, format));
115 att->viewFormatCount = 1;
116 att->pViewFormats = &info->format;
117 }
118
119 static struct zink_framebuffer *
create_framebuffer_imageless(struct zink_context * ctx,struct zink_framebuffer_state * state)120 create_framebuffer_imageless(struct zink_context *ctx, struct zink_framebuffer_state *state)
121 {
122 struct zink_screen *screen = zink_screen(ctx->base.screen);
123 struct zink_framebuffer *fb = rzalloc(ctx, struct zink_framebuffer);
124 if (!fb)
125 return NULL;
126 pipe_reference_init(&fb->reference, 1);
127
128 if (!_mesa_hash_table_init(&fb->objects, fb, _mesa_hash_pointer, _mesa_key_pointer_equal))
129 goto fail;
130 memcpy(&fb->state, state, sizeof(struct zink_framebuffer_state));
131 for (int i = 0; i < state->num_attachments; i++)
132 populate_attachment_info(&fb->infos[i], &fb->state.infos[i]);
133
134 return fb;
135 fail:
136 zink_destroy_framebuffer(screen, fb);
137 return NULL;
138 }
139
140 struct zink_framebuffer *
zink_get_framebuffer_imageless(struct zink_context * ctx)141 zink_get_framebuffer_imageless(struct zink_context *ctx)
142 {
143 assert(zink_screen(ctx->base.screen)->info.have_KHR_imageless_framebuffer);
144
145 struct zink_framebuffer_state state;
146 const unsigned cresolve_offset = ctx->fb_state.nr_cbufs + !!ctx->fb_state.zsbuf;
147 unsigned num_resolves = 0;
148 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
149 struct pipe_surface *psurf = ctx->fb_state.cbufs[i];
150 if (!psurf)
151 psurf = ctx->dummy_surface[util_logbase2_ceil(ctx->gfx_pipeline_state.rast_samples+1)];
152 struct zink_surface *surface = zink_csurface(psurf);
153 struct zink_surface *transient = zink_transient_surface(psurf);
154 if (transient) {
155 memcpy(&state.infos[i], &transient->info, sizeof(transient->info));
156 memcpy(&state.infos[cresolve_offset + i], &surface->info, sizeof(surface->info));
157 num_resolves++;
158 } else {
159 memcpy(&state.infos[i], &surface->info, sizeof(surface->info));
160 }
161 }
162
163 state.num_attachments = ctx->fb_state.nr_cbufs;
164 const unsigned zsresolve_offset = cresolve_offset + num_resolves;
165 if (ctx->fb_state.zsbuf) {
166 struct pipe_surface *psurf = ctx->fb_state.zsbuf;
167 struct zink_surface *surface = zink_csurface(psurf);
168 struct zink_surface *transient = zink_transient_surface(psurf);
169 if (transient) {
170 memcpy(&state.infos[state.num_attachments], &transient->info, sizeof(transient->info));
171 memcpy(&state.infos[zsresolve_offset], &surface->info, sizeof(surface->info));
172 num_resolves++;
173 } else {
174 memcpy(&state.infos[state.num_attachments], &surface->info, sizeof(surface->info));
175 }
176 state.num_attachments++;
177 }
178
179 /* avoid bitfield explosion */
180 assert(state.num_attachments + num_resolves < 16);
181 state.num_attachments += num_resolves;
182 state.width = MAX2(ctx->fb_state.width, 1);
183 state.height = MAX2(ctx->fb_state.height, 1);
184 state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1;
185 state.samples = ctx->fb_state.samples - 1;
186
187 struct zink_framebuffer *fb;
188 struct hash_entry *entry = _mesa_hash_table_search(&ctx->framebuffer_cache, &state);
189 if (entry)
190 return entry->data;
191
192 fb = create_framebuffer_imageless(ctx, &state);
193 _mesa_hash_table_insert(&ctx->framebuffer_cache, &fb->state, fb);
194
195 return fb;
196 }
197
198 void
zink_init_framebuffer(struct zink_screen * screen,struct zink_framebuffer * fb,struct zink_render_pass * rp)199 zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp)
200 {
201 VkFramebuffer ret;
202
203 if (fb->rp == rp)
204 return;
205
206 uint32_t hash = _mesa_hash_pointer(rp);
207
208 struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&fb->objects, hash, rp);
209 if (he) {
210 #if defined(_WIN64) || defined(__x86_64__)
211 ret = (VkFramebuffer)he->data;
212 #else
213 VkFramebuffer *ptr = he->data;
214 ret = *ptr;
215 #endif
216 goto out;
217 }
218
219 assert(rp->state.num_cbufs + rp->state.have_zsbuf + rp->state.num_cresolves + rp->state.num_zsresolves == fb->state.num_attachments);
220
221 VkFramebufferCreateInfo fci = {0};
222 fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
223 fci.renderPass = rp->render_pass;
224 fci.attachmentCount = fb->state.num_attachments;
225 fci.pAttachments = fb->state.attachments;
226 fci.width = fb->state.width;
227 fci.height = fb->state.height;
228 fci.layers = fb->state.layers + 1;
229
230 if (VKSCR(CreateFramebuffer)(screen->dev, &fci, NULL, &ret) != VK_SUCCESS)
231 return;
232 #if defined(_WIN64) || defined(__x86_64__)
233 _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ret);
234 #else
235 VkFramebuffer *ptr = ralloc(fb, VkFramebuffer);
236 if (!ptr) {
237 VKSCR(DestroyFramebuffer)(screen->dev, ret, NULL);
238 return;
239 }
240 *ptr = ret;
241 _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ptr);
242 #endif
243 out:
244 fb->rp = rp;
245 fb->fb = ret;
246 }
247
248 static struct zink_framebuffer *
create_framebuffer(struct zink_context * ctx,struct zink_framebuffer_state * state,struct pipe_surface ** attachments)249 create_framebuffer(struct zink_context *ctx,
250 struct zink_framebuffer_state *state,
251 struct pipe_surface **attachments)
252 {
253 struct zink_screen *screen = zink_screen(ctx->base.screen);
254 struct zink_framebuffer *fb = rzalloc(NULL, struct zink_framebuffer);
255 if (!fb)
256 return NULL;
257
258 unsigned num_attachments = 0;
259 for (int i = 0; i < state->num_attachments; i++) {
260 struct zink_surface *surf;
261 if (state->attachments[i]) {
262 surf = zink_csurface(attachments[i]);
263 /* no ref! */
264 fb->surfaces[i] = attachments[i];
265 num_attachments++;
266 util_dynarray_append(&surf->framebuffer_refs, struct zink_framebuffer*, fb);
267 } else {
268 surf = zink_csurface(ctx->dummy_surface[util_logbase2_ceil(state->samples+1)]);
269 state->attachments[i] = surf->image_view;
270 }
271 }
272 pipe_reference_init(&fb->reference, 1 + num_attachments);
273
274 if (!_mesa_hash_table_init(&fb->objects, fb, _mesa_hash_pointer, _mesa_key_pointer_equal))
275 goto fail;
276 memcpy(&fb->state, state, sizeof(struct zink_framebuffer_state));
277
278 return fb;
279 fail:
280 zink_destroy_framebuffer(screen, fb);
281 return NULL;
282 }
283
284 void
debug_describe_zink_framebuffer(char * buf,const struct zink_framebuffer * ptr)285 debug_describe_zink_framebuffer(char* buf, const struct zink_framebuffer *ptr)
286 {
287 sprintf(buf, "zink_framebuffer");
288 }
289
290 struct zink_framebuffer *
zink_get_framebuffer(struct zink_context * ctx)291 zink_get_framebuffer(struct zink_context *ctx)
292 {
293 struct zink_screen *screen = zink_screen(ctx->base.screen);
294
295 assert(!screen->info.have_KHR_imageless_framebuffer);
296
297 struct pipe_surface *attachments[2 * (PIPE_MAX_COLOR_BUFS + 1)] = {0};
298 const unsigned cresolve_offset = ctx->fb_state.nr_cbufs + !!ctx->fb_state.zsbuf;
299 unsigned num_resolves = 0;
300
301 struct zink_framebuffer_state state = {0};
302 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
303 struct pipe_surface *psurf = ctx->fb_state.cbufs[i];
304 if (psurf) {
305 struct zink_surface *surf = zink_csurface(psurf);
306 struct zink_surface *transient = zink_transient_surface(psurf);
307 if (transient) {
308 state.attachments[i] = transient->image_view;
309 state.attachments[cresolve_offset + i] = surf->image_view;
310 attachments[cresolve_offset + i] = psurf;
311 psurf = &transient->base;
312 num_resolves++;
313 } else {
314 state.attachments[i] = surf->image_view;
315 }
316 } else {
317 state.attachments[i] = VK_NULL_HANDLE;
318 }
319 attachments[i] = psurf;
320 }
321
322 state.num_attachments = ctx->fb_state.nr_cbufs;
323 const unsigned zsresolve_offset = cresolve_offset + num_resolves;
324 if (ctx->fb_state.zsbuf) {
325 struct pipe_surface *psurf = ctx->fb_state.zsbuf;
326 if (psurf) {
327 struct zink_surface *surf = zink_csurface(psurf);
328 struct zink_surface *transient = zink_transient_surface(psurf);
329 if (transient) {
330 state.attachments[state.num_attachments] = transient->image_view;
331 state.attachments[zsresolve_offset] = surf->image_view;
332 attachments[zsresolve_offset] = psurf;
333 psurf = &transient->base;
334 num_resolves++;
335 } else {
336 state.attachments[state.num_attachments] = surf->image_view;
337 }
338 } else {
339 state.attachments[state.num_attachments] = VK_NULL_HANDLE;
340 }
341 attachments[state.num_attachments++] = psurf;
342 }
343
344 /* avoid bitfield explosion */
345 assert(state.num_attachments + num_resolves < 16);
346 state.num_attachments += num_resolves;
347 state.width = MAX2(ctx->fb_state.width, 1);
348 state.height = MAX2(ctx->fb_state.height, 1);
349 state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1;
350 state.samples = ctx->fb_state.samples - 1;
351
352 struct zink_framebuffer *fb;
353 simple_mtx_lock(&screen->framebuffer_mtx);
354 struct hash_entry *entry = _mesa_hash_table_search(&screen->framebuffer_cache, &state);
355 if (entry) {
356 fb = (void*)entry->data;
357 struct zink_framebuffer *fb_ref = NULL;
358 /* this gains 1 ref every time we reuse it */
359 zink_framebuffer_reference(screen, &fb_ref, fb);
360 } else {
361 /* this adds 1 extra ref on creation because all newly-created framebuffers are
362 * going to be bound; necessary to handle framebuffers which have no "real" attachments
363 * and are only using null surfaces since the only ref they get is the extra one here
364 */
365 fb = create_framebuffer(ctx, &state, attachments);
366 _mesa_hash_table_insert(&screen->framebuffer_cache, &fb->state, fb);
367 }
368 simple_mtx_unlock(&screen->framebuffer_mtx);
369
370 return fb;
371 }
372