zink_framebuffer.c revision 7ec681f3
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
35void
36zink_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
51void
52zink_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
104out:
105   fb->rp = rp;
106   fb->fb = ret;
107}
108
109static void
110populate_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
119static struct zink_framebuffer *
120create_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;
135fail:
136   zink_destroy_framebuffer(screen, fb);
137   return NULL;
138}
139
140struct zink_framebuffer *
141zink_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
198void
199zink_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
243out:
244   fb->rp = rp;
245   fb->fb = ret;
246}
247
248static struct zink_framebuffer *
249create_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;
279fail:
280   zink_destroy_framebuffer(screen, fb);
281   return NULL;
282}
283
284void
285debug_describe_zink_framebuffer(char* buf, const struct zink_framebuffer *ptr)
286{
287   sprintf(buf, "zink_framebuffer");
288}
289
290struct zink_framebuffer *
291zink_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