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