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 bool
zink_use_dummy_attachments(const struct zink_context * ctx)141 zink_use_dummy_attachments(const struct zink_context *ctx)
142 {
143    return ctx->disable_color_writes && zink_screen(ctx->base.screen)->driver_workarounds.color_write_missing;
144 }
145 
146 struct zink_framebuffer *
zink_get_framebuffer_imageless(struct zink_context * ctx)147 zink_get_framebuffer_imageless(struct zink_context *ctx)
148 {
149    assert(zink_screen(ctx->base.screen)->info.have_KHR_imageless_framebuffer);
150 
151    struct zink_framebuffer_state state;
152    state.num_attachments = ctx->fb_state.nr_cbufs;
153 
154    const unsigned cresolve_offset = ctx->fb_state.nr_cbufs + !!ctx->fb_state.zsbuf;
155    unsigned num_resolves = 0;
156    for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
157       struct pipe_surface *psurf = ctx->fb_state.cbufs[i];
158       if (!psurf || zink_use_dummy_attachments(ctx))
159          psurf = ctx->dummy_surface[util_logbase2_ceil(ctx->gfx_pipeline_state.rast_samples+1)];
160       struct zink_surface *surface = zink_csurface(psurf);
161       struct zink_surface *transient = zink_transient_surface(psurf);
162       if (transient) {
163          memcpy(&state.infos[i], &transient->info, sizeof(transient->info));
164          memcpy(&state.infos[cresolve_offset + i], &surface->info, sizeof(surface->info));
165          num_resolves++;
166       } else {
167          memcpy(&state.infos[i], &surface->info, sizeof(surface->info));
168       }
169    }
170 
171    const unsigned zsresolve_offset = cresolve_offset + num_resolves;
172    if (ctx->fb_state.zsbuf) {
173       struct pipe_surface *psurf = ctx->fb_state.zsbuf;
174       struct zink_surface *surface = zink_csurface(psurf);
175       struct zink_surface *transient = zink_transient_surface(psurf);
176       if (transient) {
177          memcpy(&state.infos[state.num_attachments], &transient->info, sizeof(transient->info));
178          memcpy(&state.infos[zsresolve_offset], &surface->info, sizeof(surface->info));
179          num_resolves++;
180       } else {
181          memcpy(&state.infos[state.num_attachments], &surface->info, sizeof(surface->info));
182       }
183       state.num_attachments++;
184    }
185 
186    /* avoid bitfield explosion */
187    assert(state.num_attachments + num_resolves < 16);
188    state.num_attachments += num_resolves;
189    state.width = MAX2(ctx->fb_state.width, 1);
190    state.height = MAX2(ctx->fb_state.height, 1);
191    state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1;
192    state.samples = ctx->fb_state.samples - 1;
193 
194    struct zink_framebuffer *fb;
195    struct hash_entry *entry = _mesa_hash_table_search(&ctx->framebuffer_cache, &state);
196    if (entry)
197       return entry->data;
198 
199    fb = create_framebuffer_imageless(ctx, &state);
200    _mesa_hash_table_insert(&ctx->framebuffer_cache, &fb->state, fb);
201 
202    return fb;
203 }
204 
205 void
zink_init_framebuffer(struct zink_screen * screen,struct zink_framebuffer * fb,struct zink_render_pass * rp)206 zink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp)
207 {
208    VkFramebuffer ret;
209 
210    if (fb->rp == rp)
211       return;
212 
213    uint32_t hash = _mesa_hash_pointer(rp);
214 
215    struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&fb->objects, hash, rp);
216    if (he) {
217 #if defined(_WIN64) || defined(__x86_64__)
218       ret = (VkFramebuffer)he->data;
219 #else
220       VkFramebuffer *ptr = he->data;
221       ret = *ptr;
222 #endif
223       goto out;
224    }
225 
226    assert(rp->state.num_cbufs + rp->state.have_zsbuf + rp->state.num_cresolves + rp->state.num_zsresolves == fb->state.num_attachments);
227 
228    VkFramebufferCreateInfo fci = {0};
229    fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
230    fci.renderPass = rp->render_pass;
231    fci.attachmentCount = fb->state.num_attachments;
232    fci.pAttachments = fb->state.attachments;
233    fci.width = fb->state.width;
234    fci.height = fb->state.height;
235    fci.layers = fb->state.layers + 1;
236 
237    if (VKSCR(CreateFramebuffer)(screen->dev, &fci, NULL, &ret) != VK_SUCCESS)
238       return;
239 #if defined(_WIN64) || defined(__x86_64__)
240    _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ret);
241 #else
242    VkFramebuffer *ptr = ralloc(fb, VkFramebuffer);
243    if (!ptr) {
244       VKSCR(DestroyFramebuffer)(screen->dev, ret, NULL);
245       return;
246    }
247    *ptr = ret;
248    _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ptr);
249 #endif
250 out:
251    fb->rp = rp;
252    fb->fb = ret;
253 }
254 
255 static struct zink_framebuffer *
create_framebuffer(struct zink_context * ctx,struct zink_framebuffer_state * state,struct pipe_surface ** attachments)256 create_framebuffer(struct zink_context *ctx,
257                    struct zink_framebuffer_state *state,
258                    struct pipe_surface **attachments)
259 {
260    struct zink_screen *screen = zink_screen(ctx->base.screen);
261    struct zink_framebuffer *fb = rzalloc(NULL, struct zink_framebuffer);
262    if (!fb)
263       return NULL;
264 
265    unsigned num_attachments = 0;
266    for (int i = 0; i < state->num_attachments; i++) {
267       struct zink_surface *surf;
268       if (state->attachments[i]) {
269          surf = zink_csurface(attachments[i]);
270          /* no ref! */
271          fb->surfaces[i] = attachments[i];
272          num_attachments++;
273          util_dynarray_append(&surf->framebuffer_refs, struct zink_framebuffer*, fb);
274       } else {
275          surf = zink_csurface(ctx->dummy_surface[util_logbase2_ceil(state->samples+1)]);
276          state->attachments[i] = surf->image_view;
277       }
278    }
279    pipe_reference_init(&fb->reference, 1 + num_attachments);
280 
281    if (!_mesa_hash_table_init(&fb->objects, fb, _mesa_hash_pointer, _mesa_key_pointer_equal))
282       goto fail;
283    memcpy(&fb->state, state, sizeof(struct zink_framebuffer_state));
284 
285    return fb;
286 fail:
287    zink_destroy_framebuffer(screen, fb);
288    return NULL;
289 }
290 
291 void
debug_describe_zink_framebuffer(char * buf,const struct zink_framebuffer * ptr)292 debug_describe_zink_framebuffer(char* buf, const struct zink_framebuffer *ptr)
293 {
294    sprintf(buf, "zink_framebuffer");
295 }
296 
297 struct zink_framebuffer *
zink_get_framebuffer(struct zink_context * ctx)298 zink_get_framebuffer(struct zink_context *ctx)
299 {
300    struct zink_screen *screen = zink_screen(ctx->base.screen);
301 
302    assert(!screen->info.have_KHR_imageless_framebuffer);
303 
304    struct pipe_surface *attachments[2 * (PIPE_MAX_COLOR_BUFS + 1)] = {0};
305    const unsigned cresolve_offset = ctx->fb_state.nr_cbufs + !!ctx->fb_state.zsbuf;
306    unsigned num_resolves = 0;
307 
308    struct zink_framebuffer_state state = {0};
309    if (!zink_use_dummy_attachments(ctx)) {
310       for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
311          struct pipe_surface *psurf = ctx->fb_state.cbufs[i];
312          if (psurf) {
313             struct zink_surface *surf = zink_csurface(psurf);
314             struct zink_surface *transient = zink_transient_surface(psurf);
315             if (transient) {
316                state.attachments[i] = transient->image_view;
317                state.attachments[cresolve_offset + i] = surf->image_view;
318                attachments[cresolve_offset + i] = psurf;
319                psurf = &transient->base;
320                num_resolves++;
321             } else {
322                state.attachments[i] = surf->image_view;
323             }
324          } else {
325             state.attachments[i] = VK_NULL_HANDLE;
326          }
327          attachments[i] = psurf;
328       }
329    }
330 
331    state.num_attachments = ctx->fb_state.nr_cbufs;
332    const unsigned zsresolve_offset = cresolve_offset + num_resolves;
333    if (ctx->fb_state.zsbuf) {
334       struct pipe_surface *psurf = ctx->fb_state.zsbuf;
335       if (psurf) {
336          struct zink_surface *surf = zink_csurface(psurf);
337          struct zink_surface *transient = zink_transient_surface(psurf);
338          if (transient) {
339             state.attachments[state.num_attachments] = transient->image_view;
340             state.attachments[zsresolve_offset] = surf->image_view;
341             attachments[zsresolve_offset] = psurf;
342             psurf = &transient->base;
343             num_resolves++;
344          } else {
345             state.attachments[state.num_attachments] = surf->image_view;
346          }
347       } else {
348          state.attachments[state.num_attachments] = VK_NULL_HANDLE;
349       }
350       attachments[state.num_attachments++] = psurf;
351    }
352 
353    /* avoid bitfield explosion */
354    assert(state.num_attachments + num_resolves < 16);
355    state.num_attachments += num_resolves;
356    state.width = MAX2(ctx->fb_state.width, 1);
357    state.height = MAX2(ctx->fb_state.height, 1);
358    state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1;
359    state.samples = ctx->fb_state.samples - 1;
360 
361    struct zink_framebuffer *fb;
362    simple_mtx_lock(&screen->framebuffer_mtx);
363    struct hash_entry *entry = _mesa_hash_table_search(&screen->framebuffer_cache, &state);
364    if (entry) {
365       fb = (void*)entry->data;
366       struct zink_framebuffer *fb_ref = NULL;
367       /* this gains 1 ref every time we reuse it */
368       zink_framebuffer_reference(screen, &fb_ref, fb);
369    } else {
370       /* this adds 1 extra ref on creation because all newly-created framebuffers are
371        * going to be bound; necessary to handle framebuffers which have no "real" attachments
372        * and are only using null surfaces since the only ref they get is the extra one here
373        */
374       fb = create_framebuffer(ctx, &state, attachments);
375       _mesa_hash_table_insert(&screen->framebuffer_cache, &fb->state, fb);
376    }
377    simple_mtx_unlock(&screen->framebuffer_mtx);
378 
379    return fb;
380 }
381