Path: blob/21.2-virgl/src/gallium/drivers/zink/zink_resource.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_resource.h"2425#include "zink_batch.h"26#include "zink_context.h"27#include "zink_fence.h"28#include "zink_program.h"29#include "zink_screen.h"3031#ifdef VK_USE_PLATFORM_METAL_EXT32#include "QuartzCore/CAMetalLayer.h"33#endif34#include "vulkan/wsi/wsi_common.h"3536#include "util/slab.h"37#include "util/u_blitter.h"38#include "util/u_debug.h"39#include "util/format/u_format.h"40#include "util/u_transfer_helper.h"41#include "util/u_inlines.h"42#include "util/u_memory.h"43#include "util/u_upload_mgr.h"4445#include "frontend/sw_winsys.h"4647#ifndef _WIN3248#define ZINK_USE_DMABUF49#endif5051#ifdef ZINK_USE_DMABUF52#include "drm-uapi/drm_fourcc.h"53#else54/* these won't actually be used */55#define DRM_FORMAT_MOD_INVALID 056#define DRM_FORMAT_MOD_LINEAR 057#endif5859static void60zink_transfer_flush_region(struct pipe_context *pctx,61struct pipe_transfer *ptrans,62const struct pipe_box *box);63static void *64zink_transfer_map(struct pipe_context *pctx,65struct pipe_resource *pres,66unsigned level,67unsigned usage,68const struct pipe_box *box,69struct pipe_transfer **transfer);70static void71zink_transfer_unmap(struct pipe_context *pctx,72struct pipe_transfer *ptrans);7374void75debug_describe_zink_resource_object(char *buf, const struct zink_resource_object *ptr)76{77sprintf(buf, "zink_resource_object");78}7980static uint32_t81get_resource_usage(struct zink_resource *res)82{83bool reads = zink_batch_usage_exists(res->obj->reads);84bool writes = zink_batch_usage_exists(res->obj->writes);85uint32_t batch_uses = 0;86if (reads)87batch_uses |= ZINK_RESOURCE_ACCESS_READ;88if (writes)89batch_uses |= ZINK_RESOURCE_ACCESS_WRITE;90return batch_uses;91}9293static uint32_t94mem_hash(const void *key)95{96const struct mem_key *mkey = key;97return _mesa_hash_data(&mkey->key, sizeof(mkey->key));98}99100static bool101mem_equals(const void *a, const void *b)102{103const struct mem_key *ma = a;104const struct mem_key *mb = b;105return !memcmp(&ma->key, &mb->key, sizeof(ma->key));106}107108static void109cache_or_free_mem(struct zink_screen *screen, struct zink_resource_object *obj)110{111if (obj->mkey.key.heap_index != UINT32_MAX) {112simple_mtx_lock(&screen->mem_cache_mtx);113struct hash_entry *he = _mesa_hash_table_search_pre_hashed(screen->resource_mem_cache, obj->mem_hash, &obj->mkey);114assert(he);115struct util_dynarray *array = he->data;116struct mem_key *mkey = (void*)he->key;117118unsigned seen = mkey->seen_count;119mkey->seen_count--;120if (util_dynarray_num_elements(array, struct mem_cache_entry) < seen) {121struct mem_cache_entry mc = { obj->mem, obj->map };122screen->mem_cache_size += obj->size;123if (sizeof(void*) == 4 && obj->map) {124vkUnmapMemory(screen->dev, obj->mem);125mc.map = NULL;126}127util_dynarray_append(array, struct mem_cache_entry, mc);128simple_mtx_unlock(&screen->mem_cache_mtx);129return;130}131simple_mtx_unlock(&screen->mem_cache_mtx);132}133vkFreeMemory(screen->dev, obj->mem, NULL);134}135136void137zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_object *obj)138{139if (obj->is_buffer) {140if (obj->sbuffer)141vkDestroyBuffer(screen->dev, obj->sbuffer, NULL);142vkDestroyBuffer(screen->dev, obj->buffer, NULL);143} else {144vkDestroyImage(screen->dev, obj->image, NULL);145}146147zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj);148cache_or_free_mem(screen, obj);149FREE(obj);150}151152static void153zink_resource_destroy(struct pipe_screen *pscreen,154struct pipe_resource *pres)155{156struct zink_screen *screen = zink_screen(pscreen);157struct zink_resource *res = zink_resource(pres);158if (pres->target == PIPE_BUFFER) {159util_range_destroy(&res->valid_buffer_range);160util_idalloc_mt_free(&screen->buffer_ids, res->base.buffer_id_unique);161}162163zink_resource_object_reference(screen, &res->obj, NULL);164zink_resource_object_reference(screen, &res->scanout_obj, NULL);165threaded_resource_deinit(pres);166FREE(res);167}168169static uint32_t170get_memory_type_index(struct zink_screen *screen,171const VkMemoryRequirements *reqs,172VkMemoryPropertyFlags props)173{174int32_t idx = -1;175for (uint32_t i = 0u; i < VK_MAX_MEMORY_TYPES; i++) {176if (((reqs->memoryTypeBits >> i) & 1) == 1) {177if ((screen->info.mem_props.memoryTypes[i].propertyFlags & props) == props) {178if (!(props & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) &&179screen->info.mem_props.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {180idx = i;181} else182return i;183}184}185}186if (idx >= 0)187return idx;188189if (props & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {190/* if no suitable cached memory can be found, fall back191* to non-cached memory instead.192*/193return get_memory_type_index(screen, reqs,194props & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT);195}196197unreachable("Unsupported memory-type");198return 0;199}200201static VkImageAspectFlags202aspect_from_format(enum pipe_format fmt)203{204if (util_format_is_depth_or_stencil(fmt)) {205VkImageAspectFlags aspect = 0;206const struct util_format_description *desc = util_format_description(fmt);207if (util_format_has_depth(desc))208aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;209if (util_format_has_stencil(desc))210aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;211return aspect;212} else213return VK_IMAGE_ASPECT_COLOR_BIT;214}215216static VkBufferCreateInfo217create_bci(struct zink_screen *screen, const struct pipe_resource *templ, unsigned bind)218{219VkBufferCreateInfo bci = {0};220bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;221bci.size = templ->width0;222assert(bci.size > 0);223224bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |225VK_BUFFER_USAGE_TRANSFER_DST_BIT |226VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;227228bci.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |229VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |230VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |231VK_BUFFER_USAGE_INDEX_BUFFER_BIT |232VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |233VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT |234VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;235236if (bind & PIPE_BIND_SHADER_IMAGE)237bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;238239if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE)240bci.flags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;241return bci;242}243244static bool245check_ici(struct zink_screen *screen, VkImageCreateInfo *ici, uint64_t modifier)246{247VkImageFormatProperties image_props;248VkResult ret;249assert(modifier == DRM_FORMAT_MOD_INVALID ||250(screen->vk.GetPhysicalDeviceImageFormatProperties2 && screen->info.have_EXT_image_drm_format_modifier));251if (screen->vk.GetPhysicalDeviceImageFormatProperties2) {252VkImageFormatProperties2 props2 = {0};253props2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;254VkPhysicalDeviceImageFormatInfo2 info = {0};255info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;256info.format = ici->format;257info.type = ici->imageType;258info.tiling = ici->tiling;259info.usage = ici->usage;260info.flags = ici->flags;261262VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info;263if (modifier != DRM_FORMAT_MOD_INVALID) {264mod_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;265mod_info.pNext = NULL;266mod_info.drmFormatModifier = modifier;267mod_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;268mod_info.queueFamilyIndexCount = 0;269info.pNext = &mod_info;270}271ret = screen->vk.GetPhysicalDeviceImageFormatProperties2(screen->pdev, &info, &props2);272image_props = props2.imageFormatProperties;273} else274ret = vkGetPhysicalDeviceImageFormatProperties(screen->pdev, ici->format, ici->imageType,275ici->tiling, ici->usage, ici->flags, &image_props);276return ret == VK_SUCCESS;277}278279static VkImageUsageFlags280get_image_usage_for_feats(struct zink_screen *screen, VkFormatFeatureFlags feats, const struct pipe_resource *templ, unsigned bind)281{282VkImageUsageFlags usage = 0;283/* sadly, gallium doesn't let us know if it'll ever need this, so we have to assume */284if (feats & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)285usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;286if (feats & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)287usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;288if (feats & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT && (bind & (PIPE_BIND_LINEAR | PIPE_BIND_SHARED)) != (PIPE_BIND_LINEAR | PIPE_BIND_SHARED))289usage |= VK_IMAGE_USAGE_SAMPLED_BIT;290291if ((templ->nr_samples <= 1 || screen->info.feats.features.shaderStorageImageMultisample) &&292(bind & PIPE_BIND_SHADER_IMAGE)) {293if (feats & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)294usage |= VK_IMAGE_USAGE_STORAGE_BIT;295}296297if (bind & PIPE_BIND_RENDER_TARGET) {298if (feats & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)299usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;300else301return 0;302}303304if (bind & PIPE_BIND_DEPTH_STENCIL) {305if (feats & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)306usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;307else308return 0;309/* this is unlikely to occur and has been included for completeness */310} else if (bind & PIPE_BIND_SAMPLER_VIEW && !(usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {311if (feats & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)312usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;313else314return 0;315}316317if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE)318usage |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;319320if (bind & PIPE_BIND_STREAM_OUTPUT)321usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;322return usage;323}324325static VkFormatFeatureFlags326find_modifier_feats(const struct zink_modifier_prop *prop, uint64_t modifier, uint64_t *mod)327{328for (unsigned j = 0; j < prop->drmFormatModifierCount; j++) {329if (prop->pDrmFormatModifierProperties[j].drmFormatModifier == modifier) {330*mod = modifier;331return prop->pDrmFormatModifierProperties[j].drmFormatModifierTilingFeatures;332}333}334return 0;335}336337static VkImageUsageFlags338get_image_usage(struct zink_screen *screen, VkImageCreateInfo *ici, const struct pipe_resource *templ, unsigned bind, unsigned modifiers_count, const uint64_t *modifiers, uint64_t *mod)339{340VkImageTiling tiling = ici->tiling;341*mod = DRM_FORMAT_MOD_INVALID;342if (modifiers_count) {343bool have_linear = false;344const struct zink_modifier_prop *prop = &screen->modifier_props[templ->format];345assert(tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);346for (unsigned i = 0; i < modifiers_count; i++) {347if (modifiers[i] == DRM_FORMAT_MOD_LINEAR) {348have_linear = true;349continue;350}351VkFormatFeatureFlags feats = find_modifier_feats(prop, modifiers[i], mod);352if (feats) {353VkImageUsageFlags usage = get_image_usage_for_feats(screen, feats, templ, bind);354if (usage) {355ici->usage = usage;356if (check_ici(screen, ici, *mod))357return usage;358}359}360}361/* only try linear if no other options available */362if (have_linear) {363VkFormatFeatureFlags feats = find_modifier_feats(prop, DRM_FORMAT_MOD_LINEAR, mod);364if (feats) {365VkImageUsageFlags usage = get_image_usage_for_feats(screen, feats, templ, bind);366if (usage) {367ici->usage = usage;368if (check_ici(screen, ici, *mod))369return usage;370}371}372}373} else374{375VkFormatProperties props = screen->format_props[templ->format];376VkFormatFeatureFlags feats = tiling == VK_IMAGE_TILING_LINEAR ? props.linearTilingFeatures : props.optimalTilingFeatures;377VkImageUsageFlags usage = get_image_usage_for_feats(screen, feats, templ, bind);378if (usage) {379ici->usage = usage;380if (check_ici(screen, ici, *mod))381return usage;382}383}384*mod = DRM_FORMAT_MOD_INVALID;385return 0;386}387388static uint64_t389create_ici(struct zink_screen *screen, VkImageCreateInfo *ici, const struct pipe_resource *templ, unsigned bind, unsigned modifiers_count, const uint64_t *modifiers, bool *success)390{391ici->sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;392ici->flags = bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DEPTH_STENCIL) ? 0 : VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;393394switch (templ->target) {395case PIPE_TEXTURE_1D:396case PIPE_TEXTURE_1D_ARRAY:397ici->imageType = VK_IMAGE_TYPE_1D;398break;399400case PIPE_TEXTURE_CUBE:401case PIPE_TEXTURE_CUBE_ARRAY:402ici->flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;403FALLTHROUGH;404case PIPE_TEXTURE_2D:405case PIPE_TEXTURE_2D_ARRAY:406case PIPE_TEXTURE_RECT:407ici->imageType = VK_IMAGE_TYPE_2D;408break;409410case PIPE_TEXTURE_3D:411ici->imageType = VK_IMAGE_TYPE_3D;412if (bind & PIPE_BIND_RENDER_TARGET)413ici->flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;414break;415416case PIPE_BUFFER:417unreachable("PIPE_BUFFER should already be handled");418419default:420unreachable("Unknown target");421}422423if (screen->info.have_EXT_sample_locations &&424bind & PIPE_BIND_DEPTH_STENCIL &&425util_format_has_depth(util_format_description(templ->format)))426ici->flags |= VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT;427428ici->format = zink_get_format(screen, templ->format);429ici->extent.width = templ->width0;430ici->extent.height = templ->height0;431ici->extent.depth = templ->depth0;432ici->mipLevels = templ->last_level + 1;433ici->arrayLayers = MAX2(templ->array_size, 1);434ici->samples = templ->nr_samples ? templ->nr_samples : VK_SAMPLE_COUNT_1_BIT;435ici->tiling = modifiers_count ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT : bind & PIPE_BIND_LINEAR ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;436ici->sharingMode = VK_SHARING_MODE_EXCLUSIVE;437ici->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;438439if (templ->target == PIPE_TEXTURE_CUBE ||440templ->target == PIPE_TEXTURE_CUBE_ARRAY ||441(templ->target == PIPE_TEXTURE_2D_ARRAY &&442ici->extent.width == ici->extent.height &&443ici->arrayLayers >= 6)) {444VkImageFormatProperties props;445if (vkGetPhysicalDeviceImageFormatProperties(screen->pdev, ici->format,446ici->imageType, ici->tiling,447ici->usage, ici->flags |448VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,449&props) == VK_SUCCESS) {450if (props.sampleCounts & ici->samples)451ici->flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;452}453}454455if (templ->target == PIPE_TEXTURE_CUBE)456ici->arrayLayers *= 6;457458if (templ->usage == PIPE_USAGE_STAGING &&459templ->format != PIPE_FORMAT_B4G4R4A4_UNORM &&460templ->format != PIPE_FORMAT_B4G4R4A4_UINT)461ici->tiling = VK_IMAGE_TILING_LINEAR;462463bool first = true;464bool tried[2] = {0};465uint64_t mod = DRM_FORMAT_MOD_INVALID;466while (!ici->usage) {467if (!first) {468switch (ici->tiling) {469case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT:470ici->tiling = VK_IMAGE_TILING_OPTIMAL;471modifiers_count = 0;472break;473case VK_IMAGE_TILING_OPTIMAL:474ici->tiling = VK_IMAGE_TILING_LINEAR;475break;476case VK_IMAGE_TILING_LINEAR:477if (bind & PIPE_BIND_LINEAR) {478*success = false;479return DRM_FORMAT_MOD_INVALID;480}481ici->tiling = VK_IMAGE_TILING_OPTIMAL;482break;483default:484unreachable("unhandled tiling mode");485}486if (tried[ici->tiling]) {487*success = false;488return DRM_FORMAT_MOD_INVALID;489}490}491ici->usage = get_image_usage(screen, ici, templ, bind, modifiers_count, modifiers, &mod);492first = false;493if (ici->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)494tried[ici->tiling] = true;495}496497*success = true;498return mod;499}500501static struct zink_resource_object *502resource_object_create(struct zink_screen *screen, const struct pipe_resource *templ, struct winsys_handle *whandle, bool *optimal_tiling,503const uint64_t *modifiers, int modifiers_count)504{505struct zink_resource_object *obj = CALLOC_STRUCT(zink_resource_object);506if (!obj)507return NULL;508509VkMemoryRequirements reqs = {0};510VkMemoryPropertyFlags flags;511/* TODO: remove linear for wsi */512bool scanout = (templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR)) == (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR);513bool shared = (templ->bind & (PIPE_BIND_SHARED | PIPE_BIND_LINEAR)) == (PIPE_BIND_SHARED | PIPE_BIND_LINEAR);514515pipe_reference_init(&obj->reference, 1);516util_dynarray_init(&obj->desc_set_refs.refs, NULL);517if (templ->target == PIPE_BUFFER) {518VkBufferCreateInfo bci = create_bci(screen, templ, templ->bind);519520if (vkCreateBuffer(screen->dev, &bci, NULL, &obj->buffer) != VK_SUCCESS) {521debug_printf("vkCreateBuffer failed\n");522goto fail1;523}524525vkGetBufferMemoryRequirements(screen->dev, obj->buffer, &reqs);526if (templ->usage == PIPE_USAGE_STAGING)527flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;528else if (templ->usage == PIPE_USAGE_STREAM)529flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;530else if (templ->usage == PIPE_USAGE_IMMUTABLE)531flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;532else533flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;534obj->is_buffer = true;535obj->transfer_dst = true;536} else {537bool winsys_modifier = shared && whandle && whandle->modifier != DRM_FORMAT_MOD_INVALID;538const uint64_t *ici_modifiers = winsys_modifier ? &whandle->modifier : modifiers;539unsigned ici_modifier_count = winsys_modifier ? 1 : modifiers_count;540bool success = false;541VkImageCreateInfo ici = {0};542uint64_t mod = create_ici(screen, &ici, templ, templ->bind, ici_modifier_count, ici_modifiers, &success);543VkExternalMemoryImageCreateInfo emici = {0};544VkImageDrmFormatModifierExplicitCreateInfoEXT idfmeci = {0};545VkImageDrmFormatModifierListCreateInfoEXT idfmlci;546if (!success)547goto fail1;548549if (shared) {550emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;551emici.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;552ici.pNext = &emici;553554assert(ici.tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT || mod != DRM_FORMAT_MOD_INVALID);555if (winsys_modifier && ici.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {556assert(mod == whandle->modifier);557idfmeci.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;558idfmeci.pNext = ici.pNext;559idfmeci.drmFormatModifier = mod;560561/* TODO: store these values from other planes in their562* respective zink_resource, and walk the next-pointers to563* build up the planar array here instead.564*/565assert(util_format_get_num_planes(templ->format) == 1);566idfmeci.drmFormatModifierPlaneCount = 1;567VkSubresourceLayout plane_layout = {568.offset = whandle->offset,569.size = 0,570.rowPitch = whandle->stride,571.arrayPitch = 0,572.depthPitch = 0,573};574idfmeci.pPlaneLayouts = &plane_layout;575576ici.pNext = &idfmeci;577} else if (ici.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {578idfmlci.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT;579idfmlci.pNext = ici.pNext;580idfmlci.drmFormatModifierCount = 1;581idfmlci.pDrmFormatModifiers = &mod;582ici.pNext = &idfmlci;583} else if (ici.tiling == VK_IMAGE_TILING_OPTIMAL) {584// TODO: remove for wsi585ici.pNext = NULL;586scanout = false;587shared = false;588}589}590591if (optimal_tiling)592*optimal_tiling = ici.tiling == VK_IMAGE_TILING_OPTIMAL;593594if (ici.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)595obj->transfer_dst = true;596597if (ici.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)598obj->modifier_aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;599600struct wsi_image_create_info image_wsi_info = {601VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,602NULL,603.scanout = true,604};605606if ((screen->needs_mesa_wsi || screen->needs_mesa_flush_wsi) && scanout) {607image_wsi_info.pNext = ici.pNext;608ici.pNext = &image_wsi_info;609}610611VkResult result = vkCreateImage(screen->dev, &ici, NULL, &obj->image);612if (result != VK_SUCCESS) {613debug_printf("vkCreateImage failed\n");614goto fail1;615}616617vkGetImageMemoryRequirements(screen->dev, obj->image, &reqs);618if (templ->usage == PIPE_USAGE_STAGING && ici.tiling == VK_IMAGE_TILING_LINEAR)619flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;620else621flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;622}623624if (templ->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT || templ->usage == PIPE_USAGE_DYNAMIC)625flags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;626else if (!(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&627templ->usage == PIPE_USAGE_STAGING)628flags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;629630VkMemoryAllocateInfo mai = {0};631mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;632mai.allocationSize = reqs.size;633mai.memoryTypeIndex = get_memory_type_index(screen, &reqs, flags);634635VkMemoryType mem_type = screen->info.mem_props.memoryTypes[mai.memoryTypeIndex];636obj->coherent = mem_type.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;637if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE))638obj->host_visible = mem_type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;639if (templ->target == PIPE_BUFFER && !obj->coherent && obj->host_visible) {640mai.allocationSize = reqs.size = align(reqs.size, screen->info.props.limits.nonCoherentAtomSize);641}642643VkExportMemoryAllocateInfo emai = {0};644if (templ->bind & PIPE_BIND_SHARED && shared) {645emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;646emai.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;647648emai.pNext = mai.pNext;649mai.pNext = &emai;650}651652VkImportMemoryFdInfoKHR imfi = {653VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,654NULL,655};656657if (whandle && whandle->type == WINSYS_HANDLE_TYPE_FD) {658imfi.pNext = NULL;659imfi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;660imfi.fd = whandle->handle;661662imfi.pNext = mai.pNext;663emai.pNext = &imfi;664}665666struct wsi_memory_allocate_info memory_wsi_info = {667VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,668NULL,669};670671if (screen->needs_mesa_wsi && scanout) {672memory_wsi_info.implicit_sync = true;673674memory_wsi_info.pNext = mai.pNext;675mai.pNext = &memory_wsi_info;676}677678if (!mai.pNext && !(templ->flags & (PIPE_RESOURCE_FLAG_MAP_COHERENT | PIPE_RESOURCE_FLAG_SPARSE))) {679obj->mkey.key.reqs = reqs;680obj->mkey.key.heap_index = mai.memoryTypeIndex;681obj->mem_hash = mem_hash(&obj->mkey);682simple_mtx_lock(&screen->mem_cache_mtx);683684struct hash_entry *he = _mesa_hash_table_search_pre_hashed(screen->resource_mem_cache, obj->mem_hash, &obj->mkey);685struct mem_key *mkey;686if (he) {687struct util_dynarray *array = he->data;688mkey = (void*)he->key;689if (array && util_dynarray_num_elements(array, struct mem_cache_entry)) {690struct mem_cache_entry mc = util_dynarray_pop(array, struct mem_cache_entry);691obj->mem = mc.mem;692obj->map = mc.map;693screen->mem_cache_size -= reqs.size;694screen->mem_cache_count--;695}696} else {697mkey = ralloc(screen->resource_mem_cache, struct mem_key);698memcpy(&mkey->key, &obj->mkey.key, sizeof(obj->mkey.key));699mkey->seen_count = 0;700struct util_dynarray *array = rzalloc(screen->resource_mem_cache, struct util_dynarray);701util_dynarray_init(array, screen->resource_mem_cache);702_mesa_hash_table_insert_pre_hashed(screen->resource_mem_cache, obj->mem_hash, mkey, array);703}704mkey->seen_count++;705simple_mtx_unlock(&screen->mem_cache_mtx);706} else707obj->mkey.key.heap_index = UINT32_MAX;708709/* TODO: sparse buffers should probably allocate multiple regions of memory instead of giant blobs? */710if (!obj->mem && vkAllocateMemory(screen->dev, &mai, NULL, &obj->mem) != VK_SUCCESS) {711debug_printf("vkAllocateMemory failed\n");712goto fail2;713}714715obj->offset = 0;716obj->size = reqs.size;717718if (templ->target == PIPE_BUFFER) {719if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE))720if (vkBindBufferMemory(screen->dev, obj->buffer, obj->mem, obj->offset) != VK_SUCCESS)721goto fail3;722} else {723if (vkBindImageMemory(screen->dev, obj->image, obj->mem, obj->offset) != VK_SUCCESS)724goto fail3;725}726return obj;727728fail3:729vkFreeMemory(screen->dev, obj->mem, NULL);730731fail2:732if (templ->target == PIPE_BUFFER)733vkDestroyBuffer(screen->dev, obj->buffer, NULL);734else735vkDestroyImage(screen->dev, obj->image, NULL);736fail1:737FREE(obj);738return NULL;739}740741static struct pipe_resource *742resource_create(struct pipe_screen *pscreen,743const struct pipe_resource *templ,744struct winsys_handle *whandle,745unsigned external_usage,746const uint64_t *modifiers, int modifiers_count)747{748struct zink_screen *screen = zink_screen(pscreen);749struct zink_resource *res = CALLOC_STRUCT(zink_resource);750751if (modifiers_count > 0) {752/* for rebinds */753res->modifiers_count = modifiers_count;754res->modifiers = mem_dup(modifiers, modifiers_count * sizeof(uint64_t));755if (!res->modifiers) {756FREE(res);757return NULL;758}759}760761res->base.b = *templ;762763threaded_resource_init(&res->base.b);764pipe_reference_init(&res->base.b.reference, 1);765res->base.b.screen = pscreen;766767bool optimal_tiling = false;768res->obj = resource_object_create(screen, templ, whandle, &optimal_tiling, modifiers, 0);769if (!res->obj) {770free(res->modifiers);771FREE(res);772return NULL;773}774775res->internal_format = templ->format;776if (templ->target == PIPE_BUFFER) {777util_range_init(&res->valid_buffer_range);778} else {779res->format = zink_get_format(screen, templ->format);780res->layout = VK_IMAGE_LAYOUT_UNDEFINED;781res->optimal_tiling = optimal_tiling;782res->aspect = aspect_from_format(templ->format);783if (res->base.b.bind & (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED) && optimal_tiling) {784// TODO: remove for wsi785struct pipe_resource templ2 = res->base.b;786templ2.bind = (res->base.b.bind & (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) | PIPE_BIND_LINEAR;787res->scanout_obj = resource_object_create(screen, &templ2, whandle, &optimal_tiling, modifiers, modifiers_count);788assert(!optimal_tiling);789}790}791792if (screen->winsys && (templ->bind & PIPE_BIND_DISPLAY_TARGET)) {793struct sw_winsys *winsys = screen->winsys;794res->dt = winsys->displaytarget_create(screen->winsys,795res->base.b.bind,796res->base.b.format,797templ->width0,798templ->height0,79964, NULL,800&res->dt_stride);801}802if (res->obj->is_buffer)803res->base.buffer_id_unique = util_idalloc_mt_alloc(&screen->buffer_ids);804805return &res->base.b;806}807808static struct pipe_resource *809zink_resource_create(struct pipe_screen *pscreen,810const struct pipe_resource *templ)811{812return resource_create(pscreen, templ, NULL, 0, NULL, 0);813}814815static struct pipe_resource *816zink_resource_create_with_modifiers(struct pipe_screen *pscreen, const struct pipe_resource *templ,817const uint64_t *modifiers, int modifiers_count)818{819return resource_create(pscreen, templ, NULL, 0, modifiers, modifiers_count);820}821822static bool823zink_resource_get_param(struct pipe_screen *pscreen, struct pipe_context *pctx,824struct pipe_resource *pres,825unsigned plane,826unsigned layer,827unsigned level,828enum pipe_resource_param param,829unsigned handle_usage,830uint64_t *value)831{832struct zink_screen *screen = zink_screen(pscreen);833struct zink_resource *res = zink_resource(pres);834//TODO: remove for wsi835struct zink_resource_object *obj = res->scanout_obj ? res->scanout_obj : res->obj;836VkImageAspectFlags aspect = obj->modifier_aspect ? obj->modifier_aspect : res->aspect;837struct winsys_handle whandle;838switch (param) {839case PIPE_RESOURCE_PARAM_NPLANES:840/* not yet implemented */841*value = 1;842break;843844case PIPE_RESOURCE_PARAM_STRIDE: {845VkImageSubresource sub_res = {0};846VkSubresourceLayout sub_res_layout = {0};847848sub_res.aspectMask = aspect;849850vkGetImageSubresourceLayout(screen->dev, obj->image, &sub_res, &sub_res_layout);851852*value = sub_res_layout.rowPitch;853break;854}855856case PIPE_RESOURCE_PARAM_OFFSET: {857VkImageSubresource isr = {858aspect,859level,860layer861};862VkSubresourceLayout srl;863vkGetImageSubresourceLayout(screen->dev, obj->image, &isr, &srl);864*value = srl.offset;865break;866}867868case PIPE_RESOURCE_PARAM_MODIFIER: {869*value = DRM_FORMAT_MOD_INVALID;870if (!screen->info.have_EXT_image_drm_format_modifier)871return false;872VkImageDrmFormatModifierPropertiesEXT prop;873prop.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT;874prop.pNext = NULL;875if (screen->vk.GetImageDrmFormatModifierPropertiesEXT(screen->dev, obj->image, &prop) == VK_SUCCESS)876*value = prop.drmFormatModifier;877break;878}879880case PIPE_RESOURCE_PARAM_LAYER_STRIDE: {881VkImageSubresource isr = {882aspect,883level,884layer885};886VkSubresourceLayout srl;887vkGetImageSubresourceLayout(screen->dev, obj->image, &isr, &srl);888if (res->base.b.target == PIPE_TEXTURE_3D)889*value = srl.depthPitch;890else891*value = srl.arrayPitch;892break;893}894895case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED:896case PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS:897case PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD: {898memset(&whandle, 0, sizeof(whandle));899if (param == PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED)900whandle.type = WINSYS_HANDLE_TYPE_SHARED;901else if (param == PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS)902whandle.type = WINSYS_HANDLE_TYPE_KMS;903else if (param == PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD)904whandle.type = WINSYS_HANDLE_TYPE_FD;905906if (!pscreen->resource_get_handle(pscreen, pctx, pres, &whandle, handle_usage))907return false;908909*value = whandle.handle;910break;911}912}913return true;914}915916static bool917zink_resource_get_handle(struct pipe_screen *pscreen,918struct pipe_context *context,919struct pipe_resource *tex,920struct winsys_handle *whandle,921unsigned usage)922{923if (whandle->type == WINSYS_HANDLE_TYPE_FD) {924#ifdef ZINK_USE_DMABUF925struct zink_resource *res = zink_resource(tex);926struct zink_screen *screen = zink_screen(pscreen);927//TODO: remove for wsi928struct zink_resource_object *obj = res->scanout_obj ? res->scanout_obj : res->obj;929930VkMemoryGetFdInfoKHR fd_info = {0};931int fd;932fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;933//TODO: remove for wsi934fd_info.memory = obj->mem;935fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;936VkResult result = (*screen->vk.GetMemoryFdKHR)(screen->dev, &fd_info, &fd);937if (result != VK_SUCCESS)938return false;939whandle->handle = fd;940uint64_t value;941zink_resource_get_param(pscreen, context, tex, 0, 0, 0, PIPE_RESOURCE_PARAM_MODIFIER, 0, &value);942whandle->modifier = value;943zink_resource_get_param(pscreen, context, tex, 0, 0, 0, PIPE_RESOURCE_PARAM_OFFSET, 0, &value);944whandle->offset = value;945zink_resource_get_param(pscreen, context, tex, 0, 0, 0, PIPE_RESOURCE_PARAM_STRIDE, 0, &value);946whandle->stride = value;947#else948return false;949#endif950}951return true;952}953954static struct pipe_resource *955zink_resource_from_handle(struct pipe_screen *pscreen,956const struct pipe_resource *templ,957struct winsys_handle *whandle,958unsigned usage)959{960#ifdef ZINK_USE_DMABUF961if (whandle->modifier != DRM_FORMAT_MOD_INVALID &&962!zink_screen(pscreen)->info.have_EXT_image_drm_format_modifier)963return NULL;964965/* ignore any AUX planes, as well as planar formats */966if (templ->format == PIPE_FORMAT_NONE ||967util_format_get_num_planes(templ->format) != 1)968return NULL;969970uint64_t modifier = DRM_FORMAT_MOD_INVALID;971int modifier_count = 0;972if (whandle->modifier != DRM_FORMAT_MOD_INVALID) {973modifier = whandle->modifier;974modifier_count = 1;975}976return resource_create(pscreen, templ, whandle, usage, &modifier, modifier_count);977#else978return NULL;979#endif980}981982static bool983invalidate_buffer(struct zink_context *ctx, struct zink_resource *res)984{985struct zink_screen *screen = zink_screen(ctx->base.screen);986987assert(res->base.b.target == PIPE_BUFFER);988989if (res->base.b.flags & PIPE_RESOURCE_FLAG_SPARSE)990return false;991992if (res->valid_buffer_range.start > res->valid_buffer_range.end)993return false;994995if (res->bind_history & ZINK_RESOURCE_USAGE_STREAMOUT)996ctx->dirty_so_targets = true;997/* force counter buffer reset */998res->bind_history &= ~ZINK_RESOURCE_USAGE_STREAMOUT;9991000util_range_set_empty(&res->valid_buffer_range);1001if (!get_resource_usage(res))1002return false;10031004struct zink_resource_object *old_obj = res->obj;1005struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, NULL, NULL, 0);1006if (!new_obj) {1007debug_printf("new backing resource alloc failed!");1008return false;1009}1010bool needs_unref = true;1011if (zink_batch_usage_exists(old_obj->reads) ||1012zink_batch_usage_exists(old_obj->writes)) {1013zink_batch_reference_resource_move(&ctx->batch, res);1014needs_unref = false;1015}1016res->obj = new_obj;1017res->access_stage = 0;1018res->access = 0;1019res->unordered_barrier = false;1020zink_resource_rebind(ctx, res);1021zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj);1022if (needs_unref)1023zink_resource_object_reference(screen, &old_obj, NULL);1024return true;1025}102610271028static void1029zink_resource_invalidate(struct pipe_context *pctx, struct pipe_resource *pres)1030{1031if (pres->target == PIPE_BUFFER)1032invalidate_buffer(zink_context(pctx), zink_resource(pres));1033}10341035static void1036zink_transfer_copy_bufimage(struct zink_context *ctx,1037struct zink_resource *dst,1038struct zink_resource *src,1039struct zink_transfer *trans)1040{1041assert((trans->base.b.usage & (PIPE_MAP_DEPTH_ONLY | PIPE_MAP_STENCIL_ONLY)) !=1042(PIPE_MAP_DEPTH_ONLY | PIPE_MAP_STENCIL_ONLY));10431044bool buf2img = src->base.b.target == PIPE_BUFFER;10451046struct pipe_box box = trans->base.b.box;1047int x = box.x;1048if (buf2img)1049box.x = trans->offset;10501051if (dst->obj->transfer_dst)1052zink_copy_image_buffer(ctx, NULL, dst, src, trans->base.b.level, buf2img ? x : 0,1053box.y, box.z, trans->base.b.level, &box, trans->base.b.usage);1054else1055util_blitter_copy_texture(ctx->blitter, &dst->base.b, trans->base.b.level,1056x, box.y, box.z, &src->base.b,10570, &box);1058}10591060bool1061zink_resource_has_usage(struct zink_resource *res, enum zink_resource_access usage)1062{1063uint32_t batch_uses = get_resource_usage(res);1064return batch_uses & usage;1065}10661067ALWAYS_INLINE static void1068align_offset_size(const VkDeviceSize alignment, VkDeviceSize *offset, VkDeviceSize *size, VkDeviceSize obj_size)1069{1070VkDeviceSize align = *offset % alignment;1071if (alignment - 1 > *offset)1072*offset = 0;1073else1074*offset -= align, *size += align;1075align = alignment - (*size % alignment);1076if (*offset + *size + align > obj_size)1077*size = obj_size - *offset;1078else1079*size += align;1080}10811082VkMappedMemoryRange1083zink_resource_init_mem_range(struct zink_screen *screen, struct zink_resource_object *obj, VkDeviceSize offset, VkDeviceSize size)1084{1085assert(obj->size);1086align_offset_size(screen->info.props.limits.nonCoherentAtomSize, &offset, &size, obj->size);1087VkMappedMemoryRange range = {1088VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,1089NULL,1090obj->mem,1091offset,1092size1093};1094assert(range.size);1095return range;1096}10971098static void *1099map_resource(struct zink_screen *screen, struct zink_resource *res)1100{1101VkResult result = VK_SUCCESS;1102if (res->obj->map)1103return res->obj->map;1104assert(res->obj->host_visible);1105result = vkMapMemory(screen->dev, res->obj->mem, res->obj->offset,1106res->obj->size, 0, &res->obj->map);1107if (zink_screen_handle_vkresult(screen, result))1108return res->obj->map;1109return NULL;1110}11111112static void1113unmap_resource(struct zink_screen *screen, struct zink_resource *res)1114{1115res->obj->map = NULL;1116vkUnmapMemory(screen->dev, res->obj->mem);1117}11181119static void *1120buffer_transfer_map(struct zink_context *ctx, struct zink_resource *res, unsigned usage,1121const struct pipe_box *box, struct zink_transfer *trans)1122{1123struct zink_screen *screen = zink_screen(ctx->base.screen);1124void *ptr = NULL;11251126if (res->base.is_user_ptr)1127usage |= PIPE_MAP_PERSISTENT;11281129/* See if the buffer range being mapped has never been initialized,1130* in which case it can be mapped unsynchronized. */1131if (!(usage & (PIPE_MAP_UNSYNCHRONIZED | TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED)) &&1132usage & PIPE_MAP_WRITE && !res->base.is_shared &&1133!util_ranges_intersect(&res->valid_buffer_range, box->x, box->x + box->width)) {1134usage |= PIPE_MAP_UNSYNCHRONIZED;1135}11361137/* If discarding the entire range, discard the whole resource instead. */1138if (usage & PIPE_MAP_DISCARD_RANGE && box->x == 0 && box->width == res->base.b.width0) {1139usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;1140}11411142if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE &&1143!(usage & (PIPE_MAP_UNSYNCHRONIZED | TC_TRANSFER_MAP_NO_INVALIDATE))) {1144assert(usage & PIPE_MAP_WRITE);11451146if (invalidate_buffer(ctx, res)) {1147/* At this point, the buffer is always idle. */1148usage |= PIPE_MAP_UNSYNCHRONIZED;1149} else {1150/* Fall back to a temporary buffer. */1151usage |= PIPE_MAP_DISCARD_RANGE;1152}1153}11541155if ((usage & PIPE_MAP_WRITE) &&1156(usage & PIPE_MAP_DISCARD_RANGE || (!(usage & PIPE_MAP_READ) && zink_resource_has_usage(res, ZINK_RESOURCE_ACCESS_RW))) &&1157((!res->obj->host_visible) || !(usage & (PIPE_MAP_UNSYNCHRONIZED | PIPE_MAP_PERSISTENT)))) {11581159/* Check if mapping this buffer would cause waiting for the GPU.1160*/11611162if (!res->obj->host_visible ||1163!zink_batch_usage_check_completion(ctx, res->obj->reads) ||1164!zink_batch_usage_check_completion(ctx, res->obj->writes)) {1165/* Do a wait-free write-only transfer using a temporary buffer. */1166unsigned offset;11671168/* If we are not called from the driver thread, we have1169* to use the uploader from u_threaded_context, which is1170* local to the calling thread.1171*/1172struct u_upload_mgr *mgr;1173if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC)1174mgr = ctx->tc->base.stream_uploader;1175else1176mgr = ctx->base.stream_uploader;1177u_upload_alloc(mgr, 0, box->width + box->x,1178screen->info.props.limits.minMemoryMapAlignment, &offset,1179(struct pipe_resource **)&trans->staging_res, (void **)&ptr);1180res = zink_resource(trans->staging_res);1181trans->offset = offset;1182} else {1183/* At this point, the buffer is always idle (we checked it above). */1184usage |= PIPE_MAP_UNSYNCHRONIZED;1185}1186} else if ((usage & PIPE_MAP_READ) && !(usage & PIPE_MAP_PERSISTENT)) {1187assert(!(usage & (TC_TRANSFER_MAP_THREADED_UNSYNC | PIPE_MAP_THREAD_SAFE)));1188if (usage & PIPE_MAP_DONTBLOCK) {1189/* sparse/device-local will always need to wait since it has to copy */1190if (!res->obj->host_visible)1191return NULL;1192if (!zink_batch_usage_check_completion(ctx, res->obj->writes))1193return NULL;1194} else if (!res->obj->host_visible) {1195trans->staging_res = pipe_buffer_create(&screen->base, PIPE_BIND_LINEAR, PIPE_USAGE_STAGING, box->x + box->width);1196if (!trans->staging_res)1197return NULL;1198struct zink_resource *staging_res = zink_resource(trans->staging_res);1199zink_copy_buffer(ctx, NULL, staging_res, res, box->x, box->x, box->width);1200res = staging_res;1201zink_fence_wait(&ctx->base);1202} else1203zink_batch_usage_wait(ctx, res->obj->writes);1204}12051206if (!ptr) {1207/* if writing to a streamout buffer, ensure synchronization next time it's used */1208if (usage & PIPE_MAP_WRITE && res->bind_history & ZINK_RESOURCE_USAGE_STREAMOUT) {1209ctx->dirty_so_targets = true;1210/* force counter buffer reset */1211res->bind_history &= ~ZINK_RESOURCE_USAGE_STREAMOUT;1212}1213ptr = map_resource(screen, res);1214if (!ptr)1215return NULL;1216}12171218if (!res->obj->coherent1219#if defined(MVK_VERSION)1220// Work around for MoltenVk limitation specifically on coherent memory1221// MoltenVk returns blank memory ranges when there should be data present1222// This is a known limitation of MoltenVK.1223// See https://github.com/KhronosGroup/MoltenVK/blob/master/Docs/MoltenVK_Runtime_UserGuide.md#known-moltenvk-limitations12241225|| screen->instance_info.have_MVK_moltenvk1226#endif1227) {1228VkDeviceSize size = box->width;1229VkDeviceSize offset = res->obj->offset + trans->offset + box->x;1230VkMappedMemoryRange range = zink_resource_init_mem_range(screen, res->obj, offset, size);1231if (vkInvalidateMappedMemoryRanges(screen->dev, 1, &range) != VK_SUCCESS) {1232vkUnmapMemory(screen->dev, res->obj->mem);1233return NULL;1234}1235}1236trans->base.b.usage = usage;1237if (usage & PIPE_MAP_WRITE)1238util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width);1239return ptr;1240}12411242static void *1243zink_transfer_map(struct pipe_context *pctx,1244struct pipe_resource *pres,1245unsigned level,1246unsigned usage,1247const struct pipe_box *box,1248struct pipe_transfer **transfer)1249{1250struct zink_context *ctx = zink_context(pctx);1251struct zink_screen *screen = zink_screen(pctx->screen);1252struct zink_resource *res = zink_resource(pres);12531254struct zink_transfer *trans;12551256if (usage & PIPE_MAP_THREAD_SAFE)1257trans = malloc(sizeof(*trans));1258else if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC)1259trans = slab_alloc(&ctx->transfer_pool_unsync);1260else1261trans = slab_alloc(&ctx->transfer_pool);1262if (!trans)1263return NULL;12641265memset(trans, 0, sizeof(*trans));1266pipe_resource_reference(&trans->base.b.resource, pres);12671268trans->base.b.resource = pres;1269trans->base.b.level = level;1270trans->base.b.usage = usage;1271trans->base.b.box = *box;12721273void *ptr, *base;1274if (pres->target == PIPE_BUFFER) {1275base = buffer_transfer_map(ctx, res, usage, box, trans);1276ptr = ((uint8_t *)base) + box->x;1277} else {1278if (usage & PIPE_MAP_WRITE && !(usage & PIPE_MAP_READ))1279/* this is like a blit, so we can potentially dump some clears or maybe we have to */1280zink_fb_clears_apply_or_discard(ctx, pres, zink_rect_from_box(box), false);1281else if (usage & PIPE_MAP_READ)1282/* if the map region intersects with any clears then we have to apply them */1283zink_fb_clears_apply_region(ctx, pres, zink_rect_from_box(box));1284if (res->optimal_tiling || !res->obj->host_visible) {1285enum pipe_format format = pres->format;1286if (usage & PIPE_MAP_DEPTH_ONLY)1287format = util_format_get_depth_only(pres->format);1288else if (usage & PIPE_MAP_STENCIL_ONLY)1289format = PIPE_FORMAT_S8_UINT;1290trans->base.b.stride = util_format_get_stride(format, box->width);1291trans->base.b.layer_stride = util_format_get_2d_size(format,1292trans->base.b.stride,1293box->height);12941295struct pipe_resource templ = *pres;1296templ.format = format;1297templ.usage = usage & PIPE_MAP_READ ? PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;1298templ.target = PIPE_BUFFER;1299templ.bind = PIPE_BIND_LINEAR;1300templ.width0 = trans->base.b.layer_stride * box->depth;1301templ.height0 = templ.depth0 = 0;1302templ.last_level = 0;1303templ.array_size = 1;1304templ.flags = 0;13051306trans->staging_res = zink_resource_create(pctx->screen, &templ);1307if (!trans->staging_res)1308return NULL;13091310struct zink_resource *staging_res = zink_resource(trans->staging_res);13111312if (usage & PIPE_MAP_READ) {1313/* force multi-context sync */1314if (zink_batch_usage_is_unflushed(res->obj->writes))1315zink_batch_usage_wait(ctx, res->obj->writes);1316zink_transfer_copy_bufimage(ctx, staging_res, res, trans);1317/* need to wait for rendering to finish */1318zink_fence_wait(pctx);1319}13201321ptr = base = map_resource(screen, staging_res);1322if (!base)1323return NULL;1324} else {1325assert(!res->optimal_tiling);1326base = map_resource(screen, res);1327if (!base)1328return NULL;1329if (zink_resource_has_usage(res, ZINK_RESOURCE_ACCESS_RW)) {1330if (usage & PIPE_MAP_WRITE)1331zink_fence_wait(pctx);1332else1333zink_batch_usage_wait(ctx, res->obj->writes);1334}1335VkImageSubresource isr = {1336res->obj->modifier_aspect ? res->obj->modifier_aspect : res->aspect,1337level,133801339};1340VkSubresourceLayout srl;1341vkGetImageSubresourceLayout(screen->dev, res->obj->image, &isr, &srl);1342trans->base.b.stride = srl.rowPitch;1343if (res->base.b.target == PIPE_TEXTURE_3D)1344trans->base.b.layer_stride = srl.depthPitch;1345else1346trans->base.b.layer_stride = srl.arrayPitch;1347trans->offset = srl.offset;1348trans->depthPitch = srl.depthPitch;1349const struct util_format_description *desc = util_format_description(res->base.b.format);1350unsigned offset = srl.offset +1351box->z * srl.depthPitch +1352(box->y / desc->block.height) * srl.rowPitch +1353(box->x / desc->block.width) * (desc->block.bits / 8);1354if (!res->obj->coherent) {1355VkDeviceSize size = box->width * box->height * desc->block.bits / 8;1356VkMappedMemoryRange range = zink_resource_init_mem_range(screen, res->obj, res->obj->offset + offset, size);1357vkFlushMappedMemoryRanges(screen->dev, 1, &range);1358}1359ptr = ((uint8_t *)base) + offset;1360if (sizeof(void*) == 4)1361trans->base.b.usage |= ZINK_MAP_TEMPORARY;1362}1363}1364if ((usage & PIPE_MAP_PERSISTENT) && !(usage & PIPE_MAP_COHERENT))1365res->obj->persistent_maps++;13661367if (trans->base.b.usage & (PIPE_MAP_ONCE | ZINK_MAP_TEMPORARY))1368p_atomic_inc(&res->obj->map_count);13691370*transfer = &trans->base.b;1371return ptr;1372}13731374static void1375zink_transfer_flush_region(struct pipe_context *pctx,1376struct pipe_transfer *ptrans,1377const struct pipe_box *box)1378{1379struct zink_context *ctx = zink_context(pctx);1380struct zink_resource *res = zink_resource(ptrans->resource);1381struct zink_transfer *trans = (struct zink_transfer *)ptrans;13821383if (trans->base.b.usage & PIPE_MAP_WRITE) {1384struct zink_screen *screen = zink_screen(pctx->screen);1385struct zink_resource *m = trans->staging_res ? zink_resource(trans->staging_res) :1386res;1387ASSERTED VkDeviceSize size, offset;1388if (m->obj->is_buffer) {1389size = box->width;1390offset = trans->offset + box->x;1391} else {1392size = box->width * box->height * util_format_get_blocksize(m->base.b.format);1393offset = trans->offset +1394box->z * trans->depthPitch +1395util_format_get_2d_size(m->base.b.format, trans->base.b.stride, box->y) +1396util_format_get_stride(m->base.b.format, box->x);1397assert(offset + size <= res->obj->size);1398}1399if (!m->obj->coherent) {1400VkMappedMemoryRange range = zink_resource_init_mem_range(screen, m->obj, m->obj->offset, m->obj->size);1401vkFlushMappedMemoryRanges(screen->dev, 1, &range);1402}1403if (trans->staging_res) {1404struct zink_resource *staging_res = zink_resource(trans->staging_res);14051406if (ptrans->resource->target == PIPE_BUFFER)1407zink_copy_buffer(ctx, NULL, res, staging_res, box->x, offset, box->width);1408else1409zink_transfer_copy_bufimage(ctx, res, staging_res, trans);1410}1411}1412}14131414static void1415zink_transfer_unmap(struct pipe_context *pctx,1416struct pipe_transfer *ptrans)1417{1418struct zink_context *ctx = zink_context(pctx);1419struct zink_screen *screen = zink_screen(pctx->screen);1420struct zink_resource *res = zink_resource(ptrans->resource);1421struct zink_transfer *trans = (struct zink_transfer *)ptrans;14221423if (!(trans->base.b.usage & (PIPE_MAP_FLUSH_EXPLICIT | PIPE_MAP_COHERENT))) {1424zink_transfer_flush_region(pctx, ptrans, &ptrans->box);1425}14261427if ((trans->base.b.usage & PIPE_MAP_ONCE && !trans->staging_res && !screen->threaded) ||1428(trans->base.b.usage & ZINK_MAP_TEMPORARY && !p_atomic_dec_return(&res->obj->map_count)))1429unmap_resource(screen, res);1430if ((trans->base.b.usage & PIPE_MAP_PERSISTENT) && !(trans->base.b.usage & PIPE_MAP_COHERENT))1431res->obj->persistent_maps--;14321433if (trans->staging_res)1434pipe_resource_reference(&trans->staging_res, NULL);1435pipe_resource_reference(&trans->base.b.resource, NULL);14361437if (trans->base.b.usage & PIPE_MAP_THREAD_SAFE) {1438free(trans);1439} else {1440/* Don't use pool_transfers_unsync. We are always in the driver1441* thread. Freeing an object into a different pool is allowed.1442*/1443slab_free(&ctx->transfer_pool, ptrans);1444}1445}14461447static void1448zink_buffer_subdata(struct pipe_context *ctx, struct pipe_resource *buffer,1449unsigned usage, unsigned offset, unsigned size, const void *data)1450{1451struct pipe_transfer *transfer = NULL;1452struct pipe_box box;1453uint8_t *map = NULL;14541455usage |= PIPE_MAP_WRITE | PIPE_MAP_ONCE;14561457if (!(usage & PIPE_MAP_DIRECTLY))1458usage |= PIPE_MAP_DISCARD_RANGE;14591460u_box_1d(offset, size, &box);1461map = zink_transfer_map(ctx, buffer, 0, usage, &box, &transfer);1462if (!map)1463return;14641465memcpy(map, data, size);1466zink_transfer_unmap(ctx, transfer);1467}14681469static struct pipe_resource *1470zink_resource_get_separate_stencil(struct pipe_resource *pres)1471{1472/* For packed depth-stencil, we treat depth as the primary resource1473* and store S8 as the "second plane" resource.1474*/1475if (pres->next && pres->next->format == PIPE_FORMAT_S8_UINT)1476return pres->next;14771478return NULL;14791480}14811482bool1483zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res)1484{1485struct zink_screen *screen = zink_screen(ctx->base.screen);1486/* base resource already has the cap */1487if (res->base.b.bind & PIPE_BIND_SHADER_IMAGE)1488return true;1489if (res->obj->is_buffer) {1490if (res->obj->sbuffer)1491return true;1492VkBufferCreateInfo bci = create_bci(screen, &res->base.b, res->base.b.bind | PIPE_BIND_SHADER_IMAGE);1493bci.size = res->obj->size;14941495VkBuffer buffer;1496if (vkCreateBuffer(screen->dev, &bci, NULL, &buffer) != VK_SUCCESS)1497return false;1498vkBindBufferMemory(screen->dev, buffer, res->obj->mem, res->obj->offset);1499res->obj->sbuffer = res->obj->buffer;1500res->obj->buffer = buffer;1501} else {1502zink_fb_clears_apply_region(ctx, &res->base.b, (struct u_rect){0, res->base.b.width0, 0, res->base.b.height0});1503zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0);1504res->base.b.bind |= PIPE_BIND_SHADER_IMAGE;1505struct zink_resource_object *old_obj = res->obj;1506struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, &res->optimal_tiling, res->modifiers, res->modifiers_count);1507if (!new_obj) {1508debug_printf("new backing resource alloc failed!");1509res->base.b.bind &= ~PIPE_BIND_SHADER_IMAGE;1510return false;1511}1512struct zink_resource staging = *res;1513staging.obj = old_obj;1514bool needs_unref = true;1515if (get_resource_usage(res)) {1516zink_batch_reference_resource_move(&ctx->batch, res);1517needs_unref = false;1518}1519res->obj = new_obj;1520zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj);1521for (unsigned i = 0; i <= res->base.b.last_level; i++) {1522struct pipe_box box = {0, 0, 0,1523u_minify(res->base.b.width0, i),1524u_minify(res->base.b.height0, i), res->base.b.array_size};1525box.depth = util_num_layers(&res->base.b, i);1526ctx->base.resource_copy_region(&ctx->base, &res->base.b, i, 0, 0, 0, &staging.base.b, i, &box);1527}1528if (needs_unref)1529zink_resource_object_reference(screen, &old_obj, NULL);1530}15311532zink_resource_rebind(ctx, res);15331534return true;1535}15361537void1538zink_resource_setup_transfer_layouts(struct zink_context *ctx, struct zink_resource *src, struct zink_resource *dst)1539{1540if (src == dst) {1541/* The Vulkan 1.1 specification says the following about valid usage1542* of vkCmdBlitImage:1543*1544* "srcImageLayout must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,1545* VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL"1546*1547* and:1548*1549* "dstImageLayout must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,1550* VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL"1551*1552* Since we cant have the same image in two states at the same time,1553* we're effectively left with VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or1554* VK_IMAGE_LAYOUT_GENERAL. And since this isn't a present-related1555* operation, VK_IMAGE_LAYOUT_GENERAL seems most appropriate.1556*/1557zink_resource_image_barrier(ctx, NULL, src,1558VK_IMAGE_LAYOUT_GENERAL,1559VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,1560VK_PIPELINE_STAGE_TRANSFER_BIT);1561} else {1562zink_resource_image_barrier(ctx, NULL, src,1563VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,1564VK_ACCESS_TRANSFER_READ_BIT,1565VK_PIPELINE_STAGE_TRANSFER_BIT);15661567zink_resource_image_barrier(ctx, NULL, dst,1568VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,1569VK_ACCESS_TRANSFER_WRITE_BIT,1570VK_PIPELINE_STAGE_TRANSFER_BIT);1571}1572}15731574void1575zink_get_depth_stencil_resources(struct pipe_resource *res,1576struct zink_resource **out_z,1577struct zink_resource **out_s)1578{1579if (!res) {1580if (out_z) *out_z = NULL;1581if (out_s) *out_s = NULL;1582return;1583}15841585if (res->format != PIPE_FORMAT_S8_UINT) {1586if (out_z) *out_z = zink_resource(res);1587if (out_s) *out_s = zink_resource(zink_resource_get_separate_stencil(res));1588} else {1589if (out_z) *out_z = NULL;1590if (out_s) *out_s = zink_resource(res);1591}1592}15931594static void1595zink_resource_set_separate_stencil(struct pipe_resource *pres,1596struct pipe_resource *stencil)1597{1598assert(util_format_has_depth(util_format_description(pres->format)));1599pipe_resource_reference(&pres->next, stencil);1600}16011602static enum pipe_format1603zink_resource_get_internal_format(struct pipe_resource *pres)1604{1605struct zink_resource *res = zink_resource(pres);1606return res->internal_format;1607}16081609static const struct u_transfer_vtbl transfer_vtbl = {1610.resource_create = zink_resource_create,1611.resource_destroy = zink_resource_destroy,1612.transfer_map = zink_transfer_map,1613.transfer_unmap = zink_transfer_unmap,1614.transfer_flush_region = zink_transfer_flush_region,1615.get_internal_format = zink_resource_get_internal_format,1616.set_stencil = zink_resource_set_separate_stencil,1617.get_stencil = zink_resource_get_separate_stencil,1618};16191620bool1621zink_screen_resource_init(struct pipe_screen *pscreen)1622{1623struct zink_screen *screen = zink_screen(pscreen);1624pscreen->resource_create = zink_resource_create;1625pscreen->resource_create_with_modifiers = zink_resource_create_with_modifiers;1626pscreen->resource_destroy = zink_resource_destroy;1627pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, true, true, false, false);16281629if (screen->info.have_KHR_external_memory_fd) {1630pscreen->resource_get_handle = zink_resource_get_handle;1631pscreen->resource_from_handle = zink_resource_from_handle;1632}1633pscreen->resource_get_param = zink_resource_get_param;1634simple_mtx_init(&screen->mem_cache_mtx, mtx_plain);1635screen->resource_mem_cache = _mesa_hash_table_create(NULL, mem_hash, mem_equals);1636return !!screen->resource_mem_cache;1637}16381639void1640zink_context_resource_init(struct pipe_context *pctx)1641{1642pctx->buffer_map = u_transfer_helper_deinterleave_transfer_map;1643pctx->buffer_unmap = u_transfer_helper_deinterleave_transfer_unmap;1644pctx->texture_map = u_transfer_helper_deinterleave_transfer_map;1645pctx->texture_unmap = u_transfer_helper_deinterleave_transfer_unmap;16461647pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;1648pctx->buffer_subdata = zink_buffer_subdata;1649pctx->texture_subdata = u_default_texture_subdata;1650pctx->invalidate_resource = zink_resource_invalidate;1651}165216531654