1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2018 Collabora Ltd.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub
8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom
9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "zink_context.h"
25bf215546Sopenharmony_ci#include "zink_framebuffer.h"
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "zink_render_pass.h"
28bf215546Sopenharmony_ci#include "zink_screen.h"
29bf215546Sopenharmony_ci#include "zink_surface.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "util/u_framebuffer.h"
32bf215546Sopenharmony_ci#include "util/u_memory.h"
33bf215546Sopenharmony_ci#include "util/u_string.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_civoid
36bf215546Sopenharmony_cizink_destroy_framebuffer(struct zink_screen *screen,
37bf215546Sopenharmony_ci                         struct zink_framebuffer *fb)
38bf215546Sopenharmony_ci{
39bf215546Sopenharmony_ci   hash_table_foreach(&fb->objects, he) {
40bf215546Sopenharmony_ci#if VK_USE_64_BIT_PTR_DEFINES
41bf215546Sopenharmony_ci      VKSCR(DestroyFramebuffer)(screen->dev, he->data, NULL);
42bf215546Sopenharmony_ci#else
43bf215546Sopenharmony_ci      VkFramebuffer *ptr = he->data;
44bf215546Sopenharmony_ci      VKSCR(DestroyFramebuffer)(screen->dev, *ptr, NULL);
45bf215546Sopenharmony_ci#endif
46bf215546Sopenharmony_ci   }
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci   ralloc_free(fb);
49bf215546Sopenharmony_ci}
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_civoid
52bf215546Sopenharmony_cizink_init_framebuffer(struct zink_screen *screen, struct zink_framebuffer *fb, struct zink_render_pass *rp)
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci   VkFramebuffer ret;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   if (fb->rp == rp)
57bf215546Sopenharmony_ci      return;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   uint32_t hash = _mesa_hash_pointer(rp);
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&fb->objects, hash, rp);
62bf215546Sopenharmony_ci   if (he) {
63bf215546Sopenharmony_ci#if VK_USE_64_BIT_PTR_DEFINES
64bf215546Sopenharmony_ci      ret = (VkFramebuffer)he->data;
65bf215546Sopenharmony_ci#else
66bf215546Sopenharmony_ci      VkFramebuffer *ptr = he->data;
67bf215546Sopenharmony_ci      ret = *ptr;
68bf215546Sopenharmony_ci#endif
69bf215546Sopenharmony_ci      goto out;
70bf215546Sopenharmony_ci   }
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   assert(rp->state.num_cbufs + rp->state.have_zsbuf + rp->state.num_cresolves + rp->state.num_zsresolves == fb->state.num_attachments);
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   VkFramebufferCreateInfo fci;
75bf215546Sopenharmony_ci   fci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
76bf215546Sopenharmony_ci   fci.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT;
77bf215546Sopenharmony_ci   fci.renderPass = rp->render_pass;
78bf215546Sopenharmony_ci   fci.attachmentCount = fb->state.num_attachments;
79bf215546Sopenharmony_ci   fci.pAttachments = NULL;
80bf215546Sopenharmony_ci   fci.width = fb->state.width;
81bf215546Sopenharmony_ci   fci.height = fb->state.height;
82bf215546Sopenharmony_ci   fci.layers = fb->state.layers + 1;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   VkFramebufferAttachmentsCreateInfo attachments;
85bf215546Sopenharmony_ci   attachments.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO;
86bf215546Sopenharmony_ci   attachments.pNext = NULL;
87bf215546Sopenharmony_ci   attachments.attachmentImageInfoCount = fb->state.num_attachments;
88bf215546Sopenharmony_ci   attachments.pAttachmentImageInfos = fb->infos;
89bf215546Sopenharmony_ci   fci.pNext = &attachments;
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   if (VKSCR(CreateFramebuffer)(screen->dev, &fci, NULL, &ret) != VK_SUCCESS)
92bf215546Sopenharmony_ci      return;
93bf215546Sopenharmony_ci#if VK_USE_64_BIT_PTR_DEFINES
94bf215546Sopenharmony_ci   _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ret);
95bf215546Sopenharmony_ci#else
96bf215546Sopenharmony_ci   VkFramebuffer *ptr = ralloc(fb, VkFramebuffer);
97bf215546Sopenharmony_ci   if (!ptr) {
98bf215546Sopenharmony_ci      VKSCR(DestroyFramebuffer)(screen->dev, ret, NULL);
99bf215546Sopenharmony_ci      return;
100bf215546Sopenharmony_ci   }
101bf215546Sopenharmony_ci   *ptr = ret;
102bf215546Sopenharmony_ci   _mesa_hash_table_insert_pre_hashed(&fb->objects, hash, rp, ptr);
103bf215546Sopenharmony_ci#endif
104bf215546Sopenharmony_ciout:
105bf215546Sopenharmony_ci   fb->rp = rp;
106bf215546Sopenharmony_ci   fb->fb = ret;
107bf215546Sopenharmony_ci}
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_cistatic void
110bf215546Sopenharmony_cipopulate_attachment_info(VkFramebufferAttachmentImageInfo *att, struct zink_surface_info *info)
111bf215546Sopenharmony_ci{
112bf215546Sopenharmony_ci   att->sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO;
113bf215546Sopenharmony_ci   att->pNext = NULL;
114bf215546Sopenharmony_ci   memcpy(&att->flags, &info->flags, offsetof(struct zink_surface_info, format));
115bf215546Sopenharmony_ci   att->viewFormatCount = 1 + !!info->format[1];
116bf215546Sopenharmony_ci   att->pViewFormats = info->format;
117bf215546Sopenharmony_ci}
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_cistatic struct zink_framebuffer *
120bf215546Sopenharmony_cicreate_framebuffer_imageless(struct zink_context *ctx, struct zink_framebuffer_state *state)
121bf215546Sopenharmony_ci{
122bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(ctx->base.screen);
123bf215546Sopenharmony_ci   struct zink_framebuffer *fb = rzalloc(ctx, struct zink_framebuffer);
124bf215546Sopenharmony_ci   if (!fb)
125bf215546Sopenharmony_ci      return NULL;
126bf215546Sopenharmony_ci   pipe_reference_init(&fb->reference, 1);
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   if (!_mesa_hash_table_init(&fb->objects, fb, _mesa_hash_pointer, _mesa_key_pointer_equal))
129bf215546Sopenharmony_ci      goto fail;
130bf215546Sopenharmony_ci   memcpy(&fb->state, state, sizeof(struct zink_framebuffer_state));
131bf215546Sopenharmony_ci   for (int i = 0; i < state->num_attachments; i++)
132bf215546Sopenharmony_ci      populate_attachment_info(&fb->infos[i], &fb->state.infos[i]);
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   return fb;
135bf215546Sopenharmony_cifail:
136bf215546Sopenharmony_ci   zink_destroy_framebuffer(screen, fb);
137bf215546Sopenharmony_ci   return NULL;
138bf215546Sopenharmony_ci}
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_cibool
141bf215546Sopenharmony_cizink_use_dummy_attachments(const struct zink_context *ctx)
142bf215546Sopenharmony_ci{
143bf215546Sopenharmony_ci   return ctx->disable_color_writes && zink_screen(ctx->base.screen)->driver_workarounds.color_write_missing;
144bf215546Sopenharmony_ci}
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_cistruct zink_framebuffer *
147bf215546Sopenharmony_cizink_get_framebuffer(struct zink_context *ctx)
148bf215546Sopenharmony_ci{
149bf215546Sopenharmony_ci   assert(zink_screen(ctx->base.screen)->info.have_KHR_imageless_framebuffer);
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci   struct zink_framebuffer_state state;
152bf215546Sopenharmony_ci   state.num_attachments = ctx->fb_state.nr_cbufs;
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   const unsigned cresolve_offset = ctx->fb_state.nr_cbufs + !!ctx->fb_state.zsbuf;
155bf215546Sopenharmony_ci   unsigned num_resolves = 0;
156bf215546Sopenharmony_ci   for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
157bf215546Sopenharmony_ci      struct pipe_surface *psurf = ctx->fb_state.cbufs[i];
158bf215546Sopenharmony_ci      if (!psurf || zink_use_dummy_attachments(ctx))
159bf215546Sopenharmony_ci         psurf = ctx->dummy_surface[util_logbase2_ceil(ctx->gfx_pipeline_state.rast_samples+1)];
160bf215546Sopenharmony_ci      struct zink_surface *surface = zink_csurface(psurf);
161bf215546Sopenharmony_ci      struct zink_surface *transient = zink_transient_surface(psurf);
162bf215546Sopenharmony_ci      if (transient) {
163bf215546Sopenharmony_ci         memcpy(&state.infos[i], &transient->info, sizeof(transient->info));
164bf215546Sopenharmony_ci         memcpy(&state.infos[cresolve_offset + i], &surface->info, sizeof(surface->info));
165bf215546Sopenharmony_ci         num_resolves++;
166bf215546Sopenharmony_ci      } else {
167bf215546Sopenharmony_ci         memcpy(&state.infos[i], &surface->info, sizeof(surface->info));
168bf215546Sopenharmony_ci      }
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   const unsigned zsresolve_offset = cresolve_offset + num_resolves;
172bf215546Sopenharmony_ci   if (ctx->fb_state.zsbuf) {
173bf215546Sopenharmony_ci      struct pipe_surface *psurf = ctx->fb_state.zsbuf;
174bf215546Sopenharmony_ci      struct zink_surface *surface = zink_csurface(psurf);
175bf215546Sopenharmony_ci      struct zink_surface *transient = zink_transient_surface(psurf);
176bf215546Sopenharmony_ci      if (transient) {
177bf215546Sopenharmony_ci         memcpy(&state.infos[state.num_attachments], &transient->info, sizeof(transient->info));
178bf215546Sopenharmony_ci         memcpy(&state.infos[zsresolve_offset], &surface->info, sizeof(surface->info));
179bf215546Sopenharmony_ci         num_resolves++;
180bf215546Sopenharmony_ci      } else {
181bf215546Sopenharmony_ci         memcpy(&state.infos[state.num_attachments], &surface->info, sizeof(surface->info));
182bf215546Sopenharmony_ci      }
183bf215546Sopenharmony_ci      state.num_attachments++;
184bf215546Sopenharmony_ci   }
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   /* avoid bitfield explosion */
187bf215546Sopenharmony_ci   assert(state.num_attachments + num_resolves < 16);
188bf215546Sopenharmony_ci   state.num_attachments += num_resolves;
189bf215546Sopenharmony_ci   state.width = MAX2(ctx->fb_state.width, 1);
190bf215546Sopenharmony_ci   state.height = MAX2(ctx->fb_state.height, 1);
191bf215546Sopenharmony_ci   state.layers = MAX2(zink_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1;
192bf215546Sopenharmony_ci   state.samples = ctx->fb_state.samples - 1;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   struct zink_framebuffer *fb;
195bf215546Sopenharmony_ci   struct hash_entry *entry = _mesa_hash_table_search(&ctx->framebuffer_cache, &state);
196bf215546Sopenharmony_ci   if (entry)
197bf215546Sopenharmony_ci      return entry->data;
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   fb = create_framebuffer_imageless(ctx, &state);
200bf215546Sopenharmony_ci   _mesa_hash_table_insert(&ctx->framebuffer_cache, &fb->state, fb);
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   return fb;
203bf215546Sopenharmony_ci}
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_civoid
206bf215546Sopenharmony_cidebug_describe_zink_framebuffer(char* buf, const struct zink_framebuffer *ptr)
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci   sprintf(buf, "zink_framebuffer");
209bf215546Sopenharmony_ci}
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_civoid
212bf215546Sopenharmony_cizink_update_framebuffer_state(struct zink_context *ctx)
213bf215546Sopenharmony_ci{
214bf215546Sopenharmony_ci   /* get_framebuffer adds a ref if the fb is reused or created;
215bf215546Sopenharmony_ci    * always do get_framebuffer first to avoid deleting the same fb
216bf215546Sopenharmony_ci    * we're about to use
217bf215546Sopenharmony_ci    */
218bf215546Sopenharmony_ci   struct zink_framebuffer *fb = zink_get_framebuffer(ctx);
219bf215546Sopenharmony_ci   ctx->fb_changed |= ctx->framebuffer != fb;
220bf215546Sopenharmony_ci   ctx->framebuffer = fb;
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci/* same as u_framebuffer_get_num_layers, but clamp to lowest layer count */
224bf215546Sopenharmony_ciunsigned
225bf215546Sopenharmony_cizink_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
226bf215546Sopenharmony_ci{
227bf215546Sopenharmony_ci   unsigned i, num_layers = UINT32_MAX;
228bf215546Sopenharmony_ci   if (!(fb->nr_cbufs || fb->zsbuf))
229bf215546Sopenharmony_ci      return MAX2(fb->layers, 1);
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   for (i = 0; i < fb->nr_cbufs; i++) {
232bf215546Sopenharmony_ci      if (fb->cbufs[i]) {
233bf215546Sopenharmony_ci         unsigned num = fb->cbufs[i]->u.tex.last_layer -
234bf215546Sopenharmony_ci         fb->cbufs[i]->u.tex.first_layer + 1;
235bf215546Sopenharmony_ci         num_layers = MIN2(num_layers, num);
236bf215546Sopenharmony_ci      }
237bf215546Sopenharmony_ci   }
238bf215546Sopenharmony_ci   if (fb->zsbuf) {
239bf215546Sopenharmony_ci      unsigned num = fb->zsbuf->u.tex.last_layer -
240bf215546Sopenharmony_ci      fb->zsbuf->u.tex.first_layer + 1;
241bf215546Sopenharmony_ci      num_layers = MIN2(num_layers, num);
242bf215546Sopenharmony_ci   }
243bf215546Sopenharmony_ci   return MAX2(num_layers, 1);
244bf215546Sopenharmony_ci}
245