Path: blob/21.2-virgl/src/gallium/drivers/zink/zink_surface.c
4570 views
/*1* Copyright 2018 Collabora Ltd.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE.21*/2223#include "zink_context.h"24#include "zink_framebuffer.h"25#include "zink_resource.h"26#include "zink_screen.h"27#include "zink_surface.h"2829#include "util/format/u_format.h"30#include "util/u_inlines.h"31#include "util/u_memory.h"3233VkImageViewCreateInfo34create_ivci(struct zink_screen *screen,35struct zink_resource *res,36const struct pipe_surface *templ,37enum pipe_texture_target target)38{39VkImageViewCreateInfo ivci = {0};40ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;41ivci.image = res->obj->image;4243switch (target) {44case PIPE_TEXTURE_1D:45ivci.viewType = VK_IMAGE_VIEW_TYPE_1D;46break;4748case PIPE_TEXTURE_1D_ARRAY:49ivci.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;50break;5152case PIPE_TEXTURE_2D:53case PIPE_TEXTURE_RECT:54ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;55break;5657case PIPE_TEXTURE_2D_ARRAY:58ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;59break;6061case PIPE_TEXTURE_CUBE:62ivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE;63break;6465case PIPE_TEXTURE_CUBE_ARRAY:66ivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;67break;6869case PIPE_TEXTURE_3D:70ivci.viewType = VK_IMAGE_VIEW_TYPE_3D;71break;7273default:74unreachable("unsupported target");75}7677ivci.format = zink_get_format(screen, templ->format);78assert(ivci.format != VK_FORMAT_UNDEFINED);7980// TODO: format swizzles81ivci.components.r = VK_COMPONENT_SWIZZLE_R;82ivci.components.g = VK_COMPONENT_SWIZZLE_G;83ivci.components.b = VK_COMPONENT_SWIZZLE_B;84ivci.components.a = VK_COMPONENT_SWIZZLE_A;8586ivci.subresourceRange.aspectMask = res->aspect;87ivci.subresourceRange.baseMipLevel = templ->u.tex.level;88ivci.subresourceRange.levelCount = 1;89ivci.subresourceRange.baseArrayLayer = templ->u.tex.first_layer;90ivci.subresourceRange.layerCount = 1 + templ->u.tex.last_layer - templ->u.tex.first_layer;91ivci.viewType = zink_surface_clamp_viewtype(ivci.viewType, templ->u.tex.first_layer, templ->u.tex.last_layer, res->base.b.array_size);9293return ivci;94}9596static struct zink_surface *97create_surface(struct pipe_context *pctx,98struct pipe_resource *pres,99const struct pipe_surface *templ,100VkImageViewCreateInfo *ivci)101{102struct zink_screen *screen = zink_screen(pctx->screen);103unsigned int level = templ->u.tex.level;104105struct zink_surface *surface = CALLOC_STRUCT(zink_surface);106if (!surface)107return NULL;108109pipe_resource_reference(&surface->base.texture, pres);110pipe_reference_init(&surface->base.reference, 1);111surface->base.context = pctx;112surface->base.format = templ->format;113surface->base.width = u_minify(pres->width0, level);114surface->base.height = u_minify(pres->height0, level);115surface->base.nr_samples = templ->nr_samples;116surface->base.u.tex.level = level;117surface->base.u.tex.first_layer = templ->u.tex.first_layer;118surface->base.u.tex.last_layer = templ->u.tex.last_layer;119surface->obj = zink_resource(pres)->obj;120util_dynarray_init(&surface->framebuffer_refs, NULL);121util_dynarray_init(&surface->desc_set_refs.refs, NULL);122123if (vkCreateImageView(screen->dev, ivci, NULL,124&surface->image_view) != VK_SUCCESS) {125FREE(surface);126return NULL;127}128129return surface;130}131132static uint32_t133hash_ivci(const void *key)134{135return _mesa_hash_data((char*)key + offsetof(VkImageViewCreateInfo, flags), sizeof(VkImageViewCreateInfo) - offsetof(VkImageViewCreateInfo, flags));136}137138struct pipe_surface *139zink_get_surface(struct zink_context *ctx,140struct pipe_resource *pres,141const struct pipe_surface *templ,142VkImageViewCreateInfo *ivci)143{144struct zink_screen *screen = zink_screen(ctx->base.screen);145struct zink_surface *surface = NULL;146uint32_t hash = hash_ivci(ivci);147148simple_mtx_lock(&screen->surface_mtx);149struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, ivci);150151if (!entry) {152/* create a new surface */153surface = create_surface(&ctx->base, pres, templ, ivci);154surface->hash = hash;155surface->ivci = *ivci;156entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, hash, &surface->ivci, surface);157if (!entry) {158simple_mtx_unlock(&screen->surface_mtx);159return NULL;160}161162surface = entry->data;163} else {164surface = entry->data;165p_atomic_inc(&surface->base.reference.count);166}167simple_mtx_unlock(&screen->surface_mtx);168169return &surface->base;170}171172static struct pipe_surface *173zink_create_surface(struct pipe_context *pctx,174struct pipe_resource *pres,175const struct pipe_surface *templ)176{177178VkImageViewCreateInfo ivci = create_ivci(zink_screen(pctx->screen),179zink_resource(pres), templ, pres->target);180if (pres->target == PIPE_TEXTURE_3D)181ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;182183return zink_get_surface(zink_context(pctx), pres, templ, &ivci);184}185186/* framebuffers are owned by their surfaces, so each time a surface that's part of a cached fb187* is destroyed, it has to unref all the framebuffers it's attached to in order to avoid leaking188* all the framebuffers189*190* surfaces are always batch-tracked, so it is impossible for a framebuffer to be destroyed191* while it is in use192*/193static void194surface_clear_fb_refs(struct zink_screen *screen, struct pipe_surface *psurface)195{196struct zink_surface *surface = zink_surface(psurface);197util_dynarray_foreach(&surface->framebuffer_refs, struct zink_framebuffer*, fb_ref) {198struct zink_framebuffer *fb = *fb_ref;199for (unsigned i = 0; i < fb->state.num_attachments; i++) {200if (fb->surfaces[i] == psurface) {201simple_mtx_lock(&screen->framebuffer_mtx);202fb->surfaces[i] = NULL;203_mesa_hash_table_remove_key(&screen->framebuffer_cache, &fb->state);204zink_framebuffer_reference(screen, &fb, NULL);205simple_mtx_unlock(&screen->framebuffer_mtx);206break;207}208/* null surface doesn't get a ref but it will double-free209* if the pointer isn't unset210*/211if (fb->null_surface == psurface)212fb->null_surface = NULL;213}214}215util_dynarray_fini(&surface->framebuffer_refs);216}217218void219zink_destroy_surface(struct zink_screen *screen, struct pipe_surface *psurface)220{221struct zink_surface *surface = zink_surface(psurface);222simple_mtx_lock(&screen->surface_mtx);223struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);224assert(he);225assert(he->data == surface);226_mesa_hash_table_remove(&screen->surface_cache, he);227simple_mtx_unlock(&screen->surface_mtx);228surface_clear_fb_refs(screen, psurface);229zink_descriptor_set_refs_clear(&surface->desc_set_refs, surface);230util_dynarray_fini(&surface->framebuffer_refs);231pipe_resource_reference(&psurface->texture, NULL);232if (surface->simage_view)233vkDestroyImageView(screen->dev, surface->simage_view, NULL);234vkDestroyImageView(screen->dev, surface->image_view, NULL);235FREE(surface);236}237238static void239zink_surface_destroy(struct pipe_context *pctx,240struct pipe_surface *psurface)241{242zink_destroy_surface(zink_screen(pctx->screen), psurface);243}244245bool246zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface)247{248struct zink_surface *surface = zink_surface(*psurface);249struct zink_screen *screen = zink_screen(ctx->base.screen);250if (surface->simage_view)251return false;252VkImageViewCreateInfo ivci = create_ivci(screen,253zink_resource((*psurface)->texture), (*psurface), surface->base.texture->target);254uint32_t hash = hash_ivci(&ivci);255256simple_mtx_lock(&screen->surface_mtx);257struct hash_entry *new_entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, &ivci);258if (zink_batch_usage_exists(surface->batch_uses))259zink_batch_reference_surface(&ctx->batch, surface);260surface_clear_fb_refs(screen, *psurface);261zink_descriptor_set_refs_clear(&surface->desc_set_refs, surface);262if (new_entry) {263/* reuse existing surface; old one will be cleaned up naturally */264struct zink_surface *new_surface = new_entry->data;265simple_mtx_unlock(&screen->surface_mtx);266zink_batch_usage_set(&new_surface->batch_uses, ctx->batch.state);267zink_surface_reference(screen, (struct zink_surface**)psurface, new_surface);268return true;269}270struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);271assert(entry);272_mesa_hash_table_remove(&screen->surface_cache, entry);273VkImageView image_view;274if (vkCreateImageView(screen->dev, &ivci, NULL, &image_view) != VK_SUCCESS) {275debug_printf("zink: failed to create new imageview");276simple_mtx_unlock(&screen->surface_mtx);277return false;278}279surface->hash = hash;280surface->ivci = ivci;281entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci, surface);282assert(entry);283surface->simage_view = surface->image_view;284surface->image_view = image_view;285surface->obj = zink_resource(surface->base.texture)->obj;286zink_batch_usage_set(&surface->batch_uses, ctx->batch.state);287simple_mtx_unlock(&screen->surface_mtx);288return true;289}290291struct pipe_surface *292zink_surface_create_null(struct zink_context *ctx, enum pipe_texture_target target, unsigned width, unsigned height, unsigned samples)293{294struct pipe_surface surf_templ = {0};295296struct pipe_resource *pres;297struct pipe_resource templ = {0};298templ.width0 = width;299templ.height0 = height;300templ.depth0 = 1;301templ.format = PIPE_FORMAT_R8_UINT;302templ.target = target;303templ.bind = PIPE_BIND_RENDER_TARGET;304templ.nr_samples = samples;305306pres = ctx->base.screen->resource_create(ctx->base.screen, &templ);307if (!pres)308return NULL;309310surf_templ.format = PIPE_FORMAT_R8_UINT;311surf_templ.nr_samples = samples;312struct pipe_surface *psurf = ctx->base.create_surface(&ctx->base, pres, &surf_templ);313pipe_resource_reference(&pres, NULL);314return psurf;315}316317void318zink_context_surface_init(struct pipe_context *context)319{320context->create_surface = zink_create_surface;321context->surface_destroy = zink_surface_destroy;322}323324325