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