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 VK_USE_64_BIT_PTR_DEFINES
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(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 VK_USE_64_BIT_PTR_DEFINES
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 VK_USE_64_BIT_PTR_DEFINES
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 + !!info->format[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
140bool
141zink_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
146struct zink_framebuffer *
147zink_get_framebuffer(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(zink_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
205void
206debug_describe_zink_framebuffer(char* buf, const struct zink_framebuffer *ptr)
207{
208   sprintf(buf, "zink_framebuffer");
209}
210
211void
212zink_update_framebuffer_state(struct zink_context *ctx)
213{
214   /* get_framebuffer adds a ref if the fb is reused or created;
215    * always do get_framebuffer first to avoid deleting the same fb
216    * we're about to use
217    */
218   struct zink_framebuffer *fb = zink_get_framebuffer(ctx);
219   ctx->fb_changed |= ctx->framebuffer != fb;
220   ctx->framebuffer = fb;
221}
222
223/* same as u_framebuffer_get_num_layers, but clamp to lowest layer count */
224unsigned
225zink_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
226{
227   unsigned i, num_layers = UINT32_MAX;
228   if (!(fb->nr_cbufs || fb->zsbuf))
229      return MAX2(fb->layers, 1);
230
231   for (i = 0; i < fb->nr_cbufs; i++) {
232      if (fb->cbufs[i]) {
233         unsigned num = fb->cbufs[i]->u.tex.last_layer -
234         fb->cbufs[i]->u.tex.first_layer + 1;
235         num_layers = MIN2(num_layers, num);
236      }
237   }
238   if (fb->zsbuf) {
239      unsigned num = fb->zsbuf->u.tex.last_layer -
240      fb->zsbuf->u.tex.first_layer + 1;
241      num_layers = MIN2(num_layers, num);
242   }
243   return MAX2(num_layers, 1);
244}
245