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_resource.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "zink_batch.h"
27bf215546Sopenharmony_ci#include "zink_context.h"
28bf215546Sopenharmony_ci#include "zink_fence.h"
29bf215546Sopenharmony_ci#include "zink_program.h"
30bf215546Sopenharmony_ci#include "zink_screen.h"
31bf215546Sopenharmony_ci#include "zink_kopper.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#ifdef VK_USE_PLATFORM_METAL_EXT
34bf215546Sopenharmony_ci#include "QuartzCore/CAMetalLayer.h"
35bf215546Sopenharmony_ci#endif
36bf215546Sopenharmony_ci#include "vulkan/wsi/wsi_common.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#include "vk_format.h"
39bf215546Sopenharmony_ci#include "util/slab.h"
40bf215546Sopenharmony_ci#include "util/u_blitter.h"
41bf215546Sopenharmony_ci#include "util/u_debug.h"
42bf215546Sopenharmony_ci#include "util/format/u_format.h"
43bf215546Sopenharmony_ci#include "util/u_transfer_helper.h"
44bf215546Sopenharmony_ci#include "util/u_inlines.h"
45bf215546Sopenharmony_ci#include "util/u_memory.h"
46bf215546Sopenharmony_ci#include "util/u_upload_mgr.h"
47bf215546Sopenharmony_ci#include "util/os_file.h"
48bf215546Sopenharmony_ci#include "frontend/winsys_handle.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci#if !defined(__APPLE__)
51bf215546Sopenharmony_ci#define ZINK_USE_DMABUF
52bf215546Sopenharmony_ci#endif
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci#if defined(ZINK_USE_DMABUF) && !defined(_WIN32)
55bf215546Sopenharmony_ci#include "drm-uapi/drm_fourcc.h"
56bf215546Sopenharmony_ci#else
57bf215546Sopenharmony_ci/* these won't actually be used */
58bf215546Sopenharmony_ci#define DRM_FORMAT_MOD_INVALID 0
59bf215546Sopenharmony_ci#define DRM_FORMAT_MOD_LINEAR 0
60bf215546Sopenharmony_ci#endif
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci#if defined(__APPLE__)
63bf215546Sopenharmony_ci// Source of MVK_VERSION
64bf215546Sopenharmony_ci#include "MoltenVK/vk_mvk_moltenvk.h"
65bf215546Sopenharmony_ci#endif
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci#define ZINK_EXTERNAL_MEMORY_HANDLE 999
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_cistatic bool
70bf215546Sopenharmony_ciequals_ivci(const void *a, const void *b)
71bf215546Sopenharmony_ci{
72bf215546Sopenharmony_ci   const uint8_t *pa = a;
73bf215546Sopenharmony_ci   const uint8_t *pb = b;
74bf215546Sopenharmony_ci   size_t offset = offsetof(VkImageViewCreateInfo, flags);
75bf215546Sopenharmony_ci   return memcmp(pa + offset, pb + offset, sizeof(VkImageViewCreateInfo) - offset) == 0;
76bf215546Sopenharmony_ci}
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_cistatic bool
79bf215546Sopenharmony_ciequals_bvci(const void *a, const void *b)
80bf215546Sopenharmony_ci{
81bf215546Sopenharmony_ci   const uint8_t *pa = a;
82bf215546Sopenharmony_ci   const uint8_t *pb = b;
83bf215546Sopenharmony_ci   size_t offset = offsetof(VkBufferViewCreateInfo, flags);
84bf215546Sopenharmony_ci   return memcmp(pa + offset, pb + offset, sizeof(VkBufferViewCreateInfo) - offset) == 0;
85bf215546Sopenharmony_ci}
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_cistatic void
88bf215546Sopenharmony_cizink_transfer_flush_region(struct pipe_context *pctx,
89bf215546Sopenharmony_ci                           struct pipe_transfer *ptrans,
90bf215546Sopenharmony_ci                           const struct pipe_box *box);
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_civoid
93bf215546Sopenharmony_cidebug_describe_zink_resource_object(char *buf, const struct zink_resource_object *ptr)
94bf215546Sopenharmony_ci{
95bf215546Sopenharmony_ci   sprintf(buf, "zink_resource_object");
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_civoid
99bf215546Sopenharmony_cizink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_object *obj)
100bf215546Sopenharmony_ci{
101bf215546Sopenharmony_ci   if (obj->is_buffer) {
102bf215546Sopenharmony_ci      VKSCR(DestroyBuffer)(screen->dev, obj->buffer, NULL);
103bf215546Sopenharmony_ci      VKSCR(DestroyBuffer)(screen->dev, obj->storage_buffer, NULL);
104bf215546Sopenharmony_ci   } else if (obj->dt) {
105bf215546Sopenharmony_ci      zink_kopper_displaytarget_destroy(screen, obj->dt);
106bf215546Sopenharmony_ci   } else if (!obj->is_aux) {
107bf215546Sopenharmony_ci      VKSCR(DestroyImage)(screen->dev, obj->image, NULL);
108bf215546Sopenharmony_ci   } else {
109bf215546Sopenharmony_ci#if defined(ZINK_USE_DMABUF) && !defined(_WIN32)
110bf215546Sopenharmony_ci      close(obj->handle);
111bf215546Sopenharmony_ci#endif
112bf215546Sopenharmony_ci   }
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj);
115bf215546Sopenharmony_ci   if (obj->dt) {
116bf215546Sopenharmony_ci      FREE(obj->bo); //this is a dummy struct
117bf215546Sopenharmony_ci   } else
118bf215546Sopenharmony_ci      zink_bo_unref(screen, obj->bo);
119bf215546Sopenharmony_ci   FREE(obj);
120bf215546Sopenharmony_ci}
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_cistatic void
123bf215546Sopenharmony_cizink_resource_destroy(struct pipe_screen *pscreen,
124bf215546Sopenharmony_ci                      struct pipe_resource *pres)
125bf215546Sopenharmony_ci{
126bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pscreen);
127bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(pres);
128bf215546Sopenharmony_ci   if (pres->target == PIPE_BUFFER) {
129bf215546Sopenharmony_ci      util_range_destroy(&res->valid_buffer_range);
130bf215546Sopenharmony_ci      util_idalloc_mt_free(&screen->buffer_ids, res->base.buffer_id_unique);
131bf215546Sopenharmony_ci      assert(!_mesa_hash_table_num_entries(&res->bufferview_cache));
132bf215546Sopenharmony_ci      simple_mtx_destroy(&res->bufferview_mtx);
133bf215546Sopenharmony_ci      ralloc_free(res->bufferview_cache.table);
134bf215546Sopenharmony_ci   } else {
135bf215546Sopenharmony_ci      assert(!_mesa_hash_table_num_entries(&res->surface_cache));
136bf215546Sopenharmony_ci      simple_mtx_destroy(&res->surface_mtx);
137bf215546Sopenharmony_ci      ralloc_free(res->surface_cache.table);
138bf215546Sopenharmony_ci   }
139bf215546Sopenharmony_ci   /* no need to do anything for the caches, these objects own the resource lifetimes */
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   zink_resource_object_reference(screen, &res->obj, NULL);
142bf215546Sopenharmony_ci   threaded_resource_deinit(pres);
143bf215546Sopenharmony_ci   FREE_CL(res);
144bf215546Sopenharmony_ci}
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_cistatic VkImageAspectFlags
147bf215546Sopenharmony_ciaspect_from_format(enum pipe_format fmt)
148bf215546Sopenharmony_ci{
149bf215546Sopenharmony_ci   if (util_format_is_depth_or_stencil(fmt)) {
150bf215546Sopenharmony_ci      VkImageAspectFlags aspect = 0;
151bf215546Sopenharmony_ci      const struct util_format_description *desc = util_format_description(fmt);
152bf215546Sopenharmony_ci      if (util_format_has_depth(desc))
153bf215546Sopenharmony_ci         aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
154bf215546Sopenharmony_ci      if (util_format_has_stencil(desc))
155bf215546Sopenharmony_ci         aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
156bf215546Sopenharmony_ci      return aspect;
157bf215546Sopenharmony_ci   } else
158bf215546Sopenharmony_ci     return VK_IMAGE_ASPECT_COLOR_BIT;
159bf215546Sopenharmony_ci}
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_cistatic VkBufferCreateInfo
162bf215546Sopenharmony_cicreate_bci(struct zink_screen *screen, const struct pipe_resource *templ, unsigned bind)
163bf215546Sopenharmony_ci{
164bf215546Sopenharmony_ci   VkBufferCreateInfo bci;
165bf215546Sopenharmony_ci   bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
166bf215546Sopenharmony_ci   bci.pNext = NULL;
167bf215546Sopenharmony_ci   bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
168bf215546Sopenharmony_ci   bci.queueFamilyIndexCount = 0;
169bf215546Sopenharmony_ci   bci.pQueueFamilyIndices = NULL;
170bf215546Sopenharmony_ci   bci.size = templ->width0;
171bf215546Sopenharmony_ci   bci.flags = 0;
172bf215546Sopenharmony_ci   assert(bci.size > 0);
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
175bf215546Sopenharmony_ci               VK_BUFFER_USAGE_TRANSFER_DST_BIT |
176bf215546Sopenharmony_ci               VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   bci.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
179bf215546Sopenharmony_ci                VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |
180bf215546Sopenharmony_ci                VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
181bf215546Sopenharmony_ci                VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
182bf215546Sopenharmony_ci                VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
183bf215546Sopenharmony_ci                VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT |
184bf215546Sopenharmony_ci                VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   if (bind & PIPE_BIND_SHADER_IMAGE)
187bf215546Sopenharmony_ci      bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   if (bind & PIPE_BIND_QUERY_BUFFER)
190bf215546Sopenharmony_ci      bci.usage |= VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE)
193bf215546Sopenharmony_ci      bci.flags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
194bf215546Sopenharmony_ci   return bci;
195bf215546Sopenharmony_ci}
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_cistatic bool
198bf215546Sopenharmony_cicheck_ici(struct zink_screen *screen, VkImageCreateInfo *ici, uint64_t modifier)
199bf215546Sopenharmony_ci{
200bf215546Sopenharmony_ci   VkImageFormatProperties image_props;
201bf215546Sopenharmony_ci   VkResult ret;
202bf215546Sopenharmony_ci   assert(modifier == DRM_FORMAT_MOD_INVALID ||
203bf215546Sopenharmony_ci          (VKSCR(GetPhysicalDeviceImageFormatProperties2) && screen->info.have_EXT_image_drm_format_modifier));
204bf215546Sopenharmony_ci   if (VKSCR(GetPhysicalDeviceImageFormatProperties2)) {
205bf215546Sopenharmony_ci      VkImageFormatProperties2 props2;
206bf215546Sopenharmony_ci      props2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
207bf215546Sopenharmony_ci      props2.pNext = NULL;
208bf215546Sopenharmony_ci      VkSamplerYcbcrConversionImageFormatProperties ycbcr_props;
209bf215546Sopenharmony_ci      ycbcr_props.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
210bf215546Sopenharmony_ci      ycbcr_props.pNext = NULL;
211bf215546Sopenharmony_ci      if (screen->info.have_KHR_sampler_ycbcr_conversion)
212bf215546Sopenharmony_ci         props2.pNext = &ycbcr_props;
213bf215546Sopenharmony_ci      VkPhysicalDeviceImageFormatInfo2 info;
214bf215546Sopenharmony_ci      info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
215bf215546Sopenharmony_ci      /* possibly VkImageFormatListCreateInfo */
216bf215546Sopenharmony_ci      info.pNext = ici->pNext;
217bf215546Sopenharmony_ci      info.format = ici->format;
218bf215546Sopenharmony_ci      info.type = ici->imageType;
219bf215546Sopenharmony_ci      info.tiling = ici->tiling;
220bf215546Sopenharmony_ci      info.usage = ici->usage;
221bf215546Sopenharmony_ci      info.flags = ici->flags;
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci      VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info;
224bf215546Sopenharmony_ci      if (modifier != DRM_FORMAT_MOD_INVALID) {
225bf215546Sopenharmony_ci         mod_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
226bf215546Sopenharmony_ci         mod_info.pNext = info.pNext;
227bf215546Sopenharmony_ci         mod_info.drmFormatModifier = modifier;
228bf215546Sopenharmony_ci         mod_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
229bf215546Sopenharmony_ci         mod_info.queueFamilyIndexCount = 0;
230bf215546Sopenharmony_ci         info.pNext = &mod_info;
231bf215546Sopenharmony_ci      }
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci      ret = VKSCR(GetPhysicalDeviceImageFormatProperties2)(screen->pdev, &info, &props2);
234bf215546Sopenharmony_ci      /* this is using VK_IMAGE_CREATE_EXTENDED_USAGE_BIT and can't be validated */
235bf215546Sopenharmony_ci      if (vk_format_aspects(ici->format) & VK_IMAGE_ASPECT_PLANE_1_BIT)
236bf215546Sopenharmony_ci         ret = VK_SUCCESS;
237bf215546Sopenharmony_ci      image_props = props2.imageFormatProperties;
238bf215546Sopenharmony_ci   } else
239bf215546Sopenharmony_ci      ret = VKSCR(GetPhysicalDeviceImageFormatProperties)(screen->pdev, ici->format, ici->imageType,
240bf215546Sopenharmony_ci                                                   ici->tiling, ici->usage, ici->flags, &image_props);
241bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
242bf215546Sopenharmony_ci      return false;
243bf215546Sopenharmony_ci   if (ici->extent.depth > image_props.maxExtent.depth ||
244bf215546Sopenharmony_ci       ici->extent.height > image_props.maxExtent.height ||
245bf215546Sopenharmony_ci       ici->extent.width > image_props.maxExtent.width)
246bf215546Sopenharmony_ci      return false;
247bf215546Sopenharmony_ci   if (ici->mipLevels > image_props.maxMipLevels)
248bf215546Sopenharmony_ci      return false;
249bf215546Sopenharmony_ci   if (ici->arrayLayers > image_props.maxArrayLayers)
250bf215546Sopenharmony_ci      return false;
251bf215546Sopenharmony_ci   return true;
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_cistatic VkImageUsageFlags
255bf215546Sopenharmony_ciget_image_usage_for_feats(struct zink_screen *screen, VkFormatFeatureFlags feats, const struct pipe_resource *templ, unsigned bind, bool *need_extended)
256bf215546Sopenharmony_ci{
257bf215546Sopenharmony_ci   VkImageUsageFlags usage = 0;
258bf215546Sopenharmony_ci   bool is_planar = util_format_get_num_planes(templ->format) > 1;
259bf215546Sopenharmony_ci   *need_extended = false;
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   if (bind & ZINK_BIND_TRANSIENT)
262bf215546Sopenharmony_ci      usage |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
263bf215546Sopenharmony_ci   else {
264bf215546Sopenharmony_ci      /* sadly, gallium doesn't let us know if it'll ever need this, so we have to assume */
265bf215546Sopenharmony_ci      if (is_planar || (feats & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT))
266bf215546Sopenharmony_ci         usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
267bf215546Sopenharmony_ci      if (is_planar || (feats & VK_FORMAT_FEATURE_TRANSFER_DST_BIT))
268bf215546Sopenharmony_ci         usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
269bf215546Sopenharmony_ci      if (feats & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
270bf215546Sopenharmony_ci         usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci      if ((is_planar || (feats & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) && (bind & PIPE_BIND_SHADER_IMAGE)) {
273bf215546Sopenharmony_ci         assert(templ->nr_samples <= 1 || screen->info.feats.features.shaderStorageImageMultisample);
274bf215546Sopenharmony_ci         usage |= VK_IMAGE_USAGE_STORAGE_BIT;
275bf215546Sopenharmony_ci      }
276bf215546Sopenharmony_ci   }
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   if (bind & PIPE_BIND_RENDER_TARGET) {
279bf215546Sopenharmony_ci      if (feats & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
280bf215546Sopenharmony_ci         usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
281bf215546Sopenharmony_ci         if ((bind & (PIPE_BIND_LINEAR | PIPE_BIND_SHARED)) != (PIPE_BIND_LINEAR | PIPE_BIND_SHARED))
282bf215546Sopenharmony_ci            usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
283bf215546Sopenharmony_ci      } else {
284bf215546Sopenharmony_ci         /* trust that gallium isn't going to give us anything wild */
285bf215546Sopenharmony_ci         *need_extended = true;
286bf215546Sopenharmony_ci         return 0;
287bf215546Sopenharmony_ci      }
288bf215546Sopenharmony_ci   } else if ((bind & PIPE_BIND_SAMPLER_VIEW) && !util_format_is_depth_or_stencil(templ->format)) {
289bf215546Sopenharmony_ci      if (!(feats & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
290bf215546Sopenharmony_ci         /* ensure we can u_blitter this later */
291bf215546Sopenharmony_ci         *need_extended = true;
292bf215546Sopenharmony_ci         return 0;
293bf215546Sopenharmony_ci      }
294bf215546Sopenharmony_ci      usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
295bf215546Sopenharmony_ci   }
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   if (bind & PIPE_BIND_DEPTH_STENCIL) {
298bf215546Sopenharmony_ci      if (feats & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
299bf215546Sopenharmony_ci         usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
300bf215546Sopenharmony_ci      else
301bf215546Sopenharmony_ci         return 0;
302bf215546Sopenharmony_ci   /* this is unlikely to occur and has been included for completeness */
303bf215546Sopenharmony_ci   } else if (bind & PIPE_BIND_SAMPLER_VIEW && !(usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
304bf215546Sopenharmony_ci      if (feats & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
305bf215546Sopenharmony_ci         usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
306bf215546Sopenharmony_ci      else
307bf215546Sopenharmony_ci         return 0;
308bf215546Sopenharmony_ci   }
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   if (bind & PIPE_BIND_STREAM_OUTPUT)
311bf215546Sopenharmony_ci      usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   return usage;
314bf215546Sopenharmony_ci}
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_cistatic VkFormatFeatureFlags
317bf215546Sopenharmony_cifind_modifier_feats(const struct zink_modifier_prop *prop, uint64_t modifier, uint64_t *mod)
318bf215546Sopenharmony_ci{
319bf215546Sopenharmony_ci   for (unsigned j = 0; j < prop->drmFormatModifierCount; j++) {
320bf215546Sopenharmony_ci      if (prop->pDrmFormatModifierProperties[j].drmFormatModifier == modifier) {
321bf215546Sopenharmony_ci         *mod = modifier;
322bf215546Sopenharmony_ci         return prop->pDrmFormatModifierProperties[j].drmFormatModifierTilingFeatures;
323bf215546Sopenharmony_ci      }
324bf215546Sopenharmony_ci   }
325bf215546Sopenharmony_ci   return 0;
326bf215546Sopenharmony_ci}
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci/* If the driver can't do mutable with this ICI, then try again after removing mutable (and
329bf215546Sopenharmony_ci * thus also the list of formats we might might mutate to)
330bf215546Sopenharmony_ci */
331bf215546Sopenharmony_cistatic bool
332bf215546Sopenharmony_cidouble_check_ici(struct zink_screen *screen, VkImageCreateInfo *ici, VkImageUsageFlags usage, uint64_t *mod)
333bf215546Sopenharmony_ci{
334bf215546Sopenharmony_ci    if (!usage)
335bf215546Sopenharmony_ci       return false;
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci    const void *pNext = ici->pNext;
338bf215546Sopenharmony_ci    ici->usage = usage;
339bf215546Sopenharmony_ci    if (check_ici(screen, ici, *mod))
340bf215546Sopenharmony_ci       return true;
341bf215546Sopenharmony_ci    if (pNext) {
342bf215546Sopenharmony_ci       ici->pNext = NULL;
343bf215546Sopenharmony_ci       ici->flags &= ~VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
344bf215546Sopenharmony_ci       if (check_ici(screen, ici, *mod))
345bf215546Sopenharmony_ci          return true;
346bf215546Sopenharmony_ci       ici->pNext = pNext;
347bf215546Sopenharmony_ci       ici->flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
348bf215546Sopenharmony_ci    }
349bf215546Sopenharmony_ci    return false;
350bf215546Sopenharmony_ci}
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_cistatic VkImageUsageFlags
353bf215546Sopenharmony_ciget_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)
354bf215546Sopenharmony_ci{
355bf215546Sopenharmony_ci   VkImageTiling tiling = ici->tiling;
356bf215546Sopenharmony_ci   bool need_extended = false;
357bf215546Sopenharmony_ci   *mod = DRM_FORMAT_MOD_INVALID;
358bf215546Sopenharmony_ci   if (modifiers_count) {
359bf215546Sopenharmony_ci      bool have_linear = false;
360bf215546Sopenharmony_ci      const struct zink_modifier_prop *prop = &screen->modifier_props[templ->format];
361bf215546Sopenharmony_ci      assert(tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);
362bf215546Sopenharmony_ci      for (unsigned i = 0; i < modifiers_count; i++) {
363bf215546Sopenharmony_ci         if (modifiers[i] == DRM_FORMAT_MOD_LINEAR) {
364bf215546Sopenharmony_ci            have_linear = true;
365bf215546Sopenharmony_ci            if (!screen->info.have_EXT_image_drm_format_modifier)
366bf215546Sopenharmony_ci               break;
367bf215546Sopenharmony_ci            continue;
368bf215546Sopenharmony_ci         }
369bf215546Sopenharmony_ci         VkFormatFeatureFlags feats = find_modifier_feats(prop, modifiers[i], mod);
370bf215546Sopenharmony_ci         if (feats) {
371bf215546Sopenharmony_ci            VkImageUsageFlags usage = get_image_usage_for_feats(screen, feats, templ, bind, &need_extended);
372bf215546Sopenharmony_ci            assert(!need_extended);
373bf215546Sopenharmony_ci            if (double_check_ici(screen, ici, usage, mod))
374bf215546Sopenharmony_ci               return usage;
375bf215546Sopenharmony_ci         }
376bf215546Sopenharmony_ci      }
377bf215546Sopenharmony_ci      /* only try linear if no other options available */
378bf215546Sopenharmony_ci      if (have_linear) {
379bf215546Sopenharmony_ci         VkFormatFeatureFlags feats = find_modifier_feats(prop, DRM_FORMAT_MOD_LINEAR, mod);
380bf215546Sopenharmony_ci         if (feats) {
381bf215546Sopenharmony_ci            VkImageUsageFlags usage = get_image_usage_for_feats(screen, feats, templ, bind, &need_extended);
382bf215546Sopenharmony_ci            assert(!need_extended);
383bf215546Sopenharmony_ci            if (double_check_ici(screen, ici, usage, mod))
384bf215546Sopenharmony_ci               return usage;
385bf215546Sopenharmony_ci         }
386bf215546Sopenharmony_ci      }
387bf215546Sopenharmony_ci   } else
388bf215546Sopenharmony_ci   {
389bf215546Sopenharmony_ci      VkFormatProperties props = screen->format_props[templ->format];
390bf215546Sopenharmony_ci      VkFormatFeatureFlags feats = tiling == VK_IMAGE_TILING_LINEAR ? props.linearTilingFeatures : props.optimalTilingFeatures;
391bf215546Sopenharmony_ci      if (ici->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)
392bf215546Sopenharmony_ci         feats = UINT32_MAX;
393bf215546Sopenharmony_ci      VkImageUsageFlags usage = get_image_usage_for_feats(screen, feats, templ, bind, &need_extended);
394bf215546Sopenharmony_ci      if (need_extended) {
395bf215546Sopenharmony_ci         ici->flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
396bf215546Sopenharmony_ci         feats = UINT32_MAX;
397bf215546Sopenharmony_ci         usage = get_image_usage_for_feats(screen, feats, templ, bind, &need_extended);
398bf215546Sopenharmony_ci      }
399bf215546Sopenharmony_ci      if (double_check_ici(screen, ici, usage, mod))
400bf215546Sopenharmony_ci         return usage;
401bf215546Sopenharmony_ci   }
402bf215546Sopenharmony_ci   *mod = DRM_FORMAT_MOD_INVALID;
403bf215546Sopenharmony_ci   return 0;
404bf215546Sopenharmony_ci}
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_cistatic uint64_t
407bf215546Sopenharmony_cicreate_ici(struct zink_screen *screen, VkImageCreateInfo *ici, const struct pipe_resource *templ, bool dmabuf, unsigned bind, unsigned modifiers_count, const uint64_t *modifiers, bool *success)
408bf215546Sopenharmony_ci{
409bf215546Sopenharmony_ci   ici->sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
410bf215546Sopenharmony_ci   /* pNext may already be set */
411bf215546Sopenharmony_ci   if (util_format_get_num_planes(templ->format) > 1)
412bf215546Sopenharmony_ci      ici->flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
413bf215546Sopenharmony_ci   else
414bf215546Sopenharmony_ci      ici->flags = modifiers_count || dmabuf || bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DEPTH_STENCIL) ? 0 : VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
415bf215546Sopenharmony_ci   if (ici->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)
416bf215546Sopenharmony_ci      /* unset VkImageFormatListCreateInfo if mutable */
417bf215546Sopenharmony_ci      ici->pNext = NULL;
418bf215546Sopenharmony_ci   else if (ici->pNext)
419bf215546Sopenharmony_ci      /* add mutable if VkImageFormatListCreateInfo */
420bf215546Sopenharmony_ci      ici->flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
421bf215546Sopenharmony_ci   ici->usage = 0;
422bf215546Sopenharmony_ci   ici->queueFamilyIndexCount = 0;
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci   if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE)
425bf215546Sopenharmony_ci      ici->flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT;
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   bool need_2D = false;
428bf215546Sopenharmony_ci   switch (templ->target) {
429bf215546Sopenharmony_ci   case PIPE_TEXTURE_1D:
430bf215546Sopenharmony_ci   case PIPE_TEXTURE_1D_ARRAY:
431bf215546Sopenharmony_ci      if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE)
432bf215546Sopenharmony_ci         need_2D |= screen->need_2D_sparse;
433bf215546Sopenharmony_ci      if (util_format_is_depth_or_stencil(templ->format))
434bf215546Sopenharmony_ci         need_2D |= screen->need_2D_zs;
435bf215546Sopenharmony_ci      ici->imageType = need_2D ? VK_IMAGE_TYPE_2D : VK_IMAGE_TYPE_1D;
436bf215546Sopenharmony_ci      break;
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   case PIPE_TEXTURE_CUBE:
439bf215546Sopenharmony_ci   case PIPE_TEXTURE_CUBE_ARRAY:
440bf215546Sopenharmony_ci   case PIPE_TEXTURE_2D:
441bf215546Sopenharmony_ci   case PIPE_TEXTURE_2D_ARRAY:
442bf215546Sopenharmony_ci   case PIPE_TEXTURE_RECT:
443bf215546Sopenharmony_ci      ici->imageType = VK_IMAGE_TYPE_2D;
444bf215546Sopenharmony_ci      break;
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   case PIPE_TEXTURE_3D:
447bf215546Sopenharmony_ci      ici->imageType = VK_IMAGE_TYPE_3D;
448bf215546Sopenharmony_ci      ici->flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
449bf215546Sopenharmony_ci      if (screen->info.have_EXT_image_2d_view_of_3d)
450bf215546Sopenharmony_ci         ici->flags |= VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
451bf215546Sopenharmony_ci      break;
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   case PIPE_BUFFER:
454bf215546Sopenharmony_ci      unreachable("PIPE_BUFFER should already be handled");
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   default:
457bf215546Sopenharmony_ci      unreachable("Unknown target");
458bf215546Sopenharmony_ci   }
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   if (screen->info.have_EXT_sample_locations &&
461bf215546Sopenharmony_ci       bind & PIPE_BIND_DEPTH_STENCIL &&
462bf215546Sopenharmony_ci       util_format_has_depth(util_format_description(templ->format)))
463bf215546Sopenharmony_ci      ici->flags |= VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT;
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   ici->format = zink_get_format(screen, templ->format);
466bf215546Sopenharmony_ci   ici->extent.width = templ->width0;
467bf215546Sopenharmony_ci   ici->extent.height = templ->height0;
468bf215546Sopenharmony_ci   ici->extent.depth = templ->depth0;
469bf215546Sopenharmony_ci   ici->mipLevels = templ->last_level + 1;
470bf215546Sopenharmony_ci   ici->arrayLayers = MAX2(templ->array_size, 1);
471bf215546Sopenharmony_ci   ici->samples = templ->nr_samples ? templ->nr_samples : VK_SAMPLE_COUNT_1_BIT;
472bf215546Sopenharmony_ci   ici->tiling = screen->info.have_EXT_image_drm_format_modifier && modifiers_count ?
473bf215546Sopenharmony_ci                 VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT :
474bf215546Sopenharmony_ci                 bind & (PIPE_BIND_LINEAR | ZINK_BIND_DMABUF) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
475bf215546Sopenharmony_ci   ici->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
476bf215546Sopenharmony_ci   ici->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   /* sampleCounts will be set to VK_SAMPLE_COUNT_1_BIT if at least one of the following conditions is true:
479bf215546Sopenharmony_ci    * - flags contains VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
480bf215546Sopenharmony_ci    *
481bf215546Sopenharmony_ci    * 44.1.1. Supported Sample Counts
482bf215546Sopenharmony_ci    */
483bf215546Sopenharmony_ci   bool want_cube = ici->samples == 1 &&
484bf215546Sopenharmony_ci                    (templ->target == PIPE_TEXTURE_CUBE ||
485bf215546Sopenharmony_ci                    templ->target == PIPE_TEXTURE_CUBE_ARRAY ||
486bf215546Sopenharmony_ci                    (templ->target == PIPE_TEXTURE_2D_ARRAY && ici->extent.width == ici->extent.height && ici->arrayLayers >= 6));
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci   if (templ->target == PIPE_TEXTURE_CUBE)
489bf215546Sopenharmony_ci      ici->arrayLayers *= 6;
490bf215546Sopenharmony_ci
491bf215546Sopenharmony_ci   if (templ->usage == PIPE_USAGE_STAGING &&
492bf215546Sopenharmony_ci       templ->format != PIPE_FORMAT_B4G4R4A4_UNORM &&
493bf215546Sopenharmony_ci       templ->format != PIPE_FORMAT_B4G4R4A4_UINT)
494bf215546Sopenharmony_ci      ici->tiling = VK_IMAGE_TILING_LINEAR;
495bf215546Sopenharmony_ci   if (ici->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
496bf215546Sopenharmony_ci      modifiers_count = 0;
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_ci   bool first = true;
499bf215546Sopenharmony_ci   bool tried[2] = {0};
500bf215546Sopenharmony_ci   uint64_t mod = DRM_FORMAT_MOD_INVALID;
501bf215546Sopenharmony_ciretry:
502bf215546Sopenharmony_ci   while (!ici->usage) {
503bf215546Sopenharmony_ci      if (!first) {
504bf215546Sopenharmony_ci         switch (ici->tiling) {
505bf215546Sopenharmony_ci         case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT:
506bf215546Sopenharmony_ci            ici->tiling = VK_IMAGE_TILING_OPTIMAL;
507bf215546Sopenharmony_ci            modifiers_count = 0;
508bf215546Sopenharmony_ci            break;
509bf215546Sopenharmony_ci         case VK_IMAGE_TILING_OPTIMAL:
510bf215546Sopenharmony_ci            ici->tiling = VK_IMAGE_TILING_LINEAR;
511bf215546Sopenharmony_ci            break;
512bf215546Sopenharmony_ci         case VK_IMAGE_TILING_LINEAR:
513bf215546Sopenharmony_ci            if (bind & PIPE_BIND_LINEAR) {
514bf215546Sopenharmony_ci               *success = false;
515bf215546Sopenharmony_ci               return DRM_FORMAT_MOD_INVALID;
516bf215546Sopenharmony_ci            }
517bf215546Sopenharmony_ci            ici->tiling = VK_IMAGE_TILING_OPTIMAL;
518bf215546Sopenharmony_ci            break;
519bf215546Sopenharmony_ci         default:
520bf215546Sopenharmony_ci            unreachable("unhandled tiling mode");
521bf215546Sopenharmony_ci         }
522bf215546Sopenharmony_ci         if (tried[ici->tiling]) {
523bf215546Sopenharmony_ci            if (ici->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT) {
524bf215546Sopenharmony_ci               *success = false;
525bf215546Sopenharmony_ci               return DRM_FORMAT_MOD_INVALID;
526bf215546Sopenharmony_ci            }
527bf215546Sopenharmony_ci            ici->flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
528bf215546Sopenharmony_ci            tried[0] = false;
529bf215546Sopenharmony_ci            tried[1] = false;
530bf215546Sopenharmony_ci            first = true;
531bf215546Sopenharmony_ci            goto retry;
532bf215546Sopenharmony_ci         }
533bf215546Sopenharmony_ci      }
534bf215546Sopenharmony_ci      ici->usage = get_image_usage(screen, ici, templ, bind, modifiers_count, modifiers, &mod);
535bf215546Sopenharmony_ci      first = false;
536bf215546Sopenharmony_ci      if (ici->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
537bf215546Sopenharmony_ci         tried[ici->tiling] = true;
538bf215546Sopenharmony_ci   }
539bf215546Sopenharmony_ci   if (want_cube) {
540bf215546Sopenharmony_ci      ici->flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
541bf215546Sopenharmony_ci      if (get_image_usage(screen, ici, templ, bind, modifiers_count, modifiers, &mod) != ici->usage)
542bf215546Sopenharmony_ci         ici->flags &= ~VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
543bf215546Sopenharmony_ci   }
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_ci   *success = true;
546bf215546Sopenharmony_ci   return mod;
547bf215546Sopenharmony_ci}
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_cistatic struct zink_resource_object *
550bf215546Sopenharmony_ciresource_object_create(struct zink_screen *screen, const struct pipe_resource *templ, struct winsys_handle *whandle, bool *optimal_tiling,
551bf215546Sopenharmony_ci                       const uint64_t *modifiers, int modifiers_count, const void *loader_private)
552bf215546Sopenharmony_ci{
553bf215546Sopenharmony_ci   struct zink_resource_object *obj = CALLOC_STRUCT(zink_resource_object);
554bf215546Sopenharmony_ci   if (!obj)
555bf215546Sopenharmony_ci      return NULL;
556bf215546Sopenharmony_ci   obj->last_dt_idx = obj->dt_idx = UINT32_MAX; //TODO: unionize
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   VkMemoryRequirements reqs = {0};
559bf215546Sopenharmony_ci   VkMemoryPropertyFlags flags;
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   /* figure out aux plane count */
562bf215546Sopenharmony_ci   if (whandle && whandle->plane >= util_format_get_num_planes(whandle->format))
563bf215546Sopenharmony_ci      obj->is_aux = true;
564bf215546Sopenharmony_ci   struct pipe_resource *pnext = templ->next;
565bf215546Sopenharmony_ci   for (obj->plane_count = 1; pnext; obj->plane_count++, pnext = pnext->next) {
566bf215546Sopenharmony_ci      struct zink_resource *next = zink_resource(pnext);
567bf215546Sopenharmony_ci      if (!next->obj->is_aux)
568bf215546Sopenharmony_ci         break;
569bf215546Sopenharmony_ci   }
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci   bool need_dedicated = false;
572bf215546Sopenharmony_ci   bool shared = templ->bind & PIPE_BIND_SHARED;
573bf215546Sopenharmony_ci#if !defined(_WIN32)
574bf215546Sopenharmony_ci   VkExternalMemoryHandleTypeFlags export_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
575bf215546Sopenharmony_ci#else
576bf215546Sopenharmony_ci   VkExternalMemoryHandleTypeFlags export_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
577bf215546Sopenharmony_ci#endif
578bf215546Sopenharmony_ci   unsigned num_planes = util_format_get_num_planes(templ->format);
579bf215546Sopenharmony_ci   VkImageAspectFlags plane_aspects[] = {
580bf215546Sopenharmony_ci      VK_IMAGE_ASPECT_PLANE_0_BIT,
581bf215546Sopenharmony_ci      VK_IMAGE_ASPECT_PLANE_1_BIT,
582bf215546Sopenharmony_ci      VK_IMAGE_ASPECT_PLANE_2_BIT,
583bf215546Sopenharmony_ci   };
584bf215546Sopenharmony_ci   VkExternalMemoryHandleTypeFlags external = 0;
585bf215546Sopenharmony_ci   bool needs_export = (templ->bind & (ZINK_BIND_VIDEO | ZINK_BIND_DMABUF)) != 0;
586bf215546Sopenharmony_ci   if (whandle) {
587bf215546Sopenharmony_ci      if (whandle->type == WINSYS_HANDLE_TYPE_FD || whandle->type == ZINK_EXTERNAL_MEMORY_HANDLE)
588bf215546Sopenharmony_ci         needs_export |= true;
589bf215546Sopenharmony_ci      else
590bf215546Sopenharmony_ci         unreachable("unknown handle type");
591bf215546Sopenharmony_ci   }
592bf215546Sopenharmony_ci   if (needs_export) {
593bf215546Sopenharmony_ci      if (whandle && whandle->type == ZINK_EXTERNAL_MEMORY_HANDLE) {
594bf215546Sopenharmony_ci#if !defined(_WIN32)
595bf215546Sopenharmony_ci         external = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
596bf215546Sopenharmony_ci#else
597bf215546Sopenharmony_ci         external = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
598bf215546Sopenharmony_ci#endif
599bf215546Sopenharmony_ci      } else {
600bf215546Sopenharmony_ci         external = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
601bf215546Sopenharmony_ci         export_types |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
602bf215546Sopenharmony_ci      }
603bf215546Sopenharmony_ci   }
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci   /* we may export WINSYS_HANDLE_TYPE_FD handle which is dma-buf */
606bf215546Sopenharmony_ci   if (shared && screen->info.have_EXT_external_memory_dma_buf)
607bf215546Sopenharmony_ci      export_types |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
608bf215546Sopenharmony_ci
609bf215546Sopenharmony_ci   pipe_reference_init(&obj->reference, 1);
610bf215546Sopenharmony_ci   util_dynarray_init(&obj->desc_set_refs.refs, NULL);
611bf215546Sopenharmony_ci   if (loader_private) {
612bf215546Sopenharmony_ci      obj->bo = CALLOC_STRUCT(zink_bo);
613bf215546Sopenharmony_ci      obj->transfer_dst = true;
614bf215546Sopenharmony_ci      return obj;
615bf215546Sopenharmony_ci   } else if (templ->target == PIPE_BUFFER) {
616bf215546Sopenharmony_ci      VkBufferCreateInfo bci = create_bci(screen, templ, templ->bind);
617bf215546Sopenharmony_ci
618bf215546Sopenharmony_ci      if (VKSCR(CreateBuffer)(screen->dev, &bci, NULL, &obj->buffer) != VK_SUCCESS) {
619bf215546Sopenharmony_ci         mesa_loge("ZINK: vkCreateBuffer failed");
620bf215546Sopenharmony_ci         goto fail1;
621bf215546Sopenharmony_ci      }
622bf215546Sopenharmony_ci
623bf215546Sopenharmony_ci      if (!(templ->bind & PIPE_BIND_SHADER_IMAGE)) {
624bf215546Sopenharmony_ci         bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
625bf215546Sopenharmony_ci         if (VKSCR(CreateBuffer)(screen->dev, &bci, NULL, &obj->storage_buffer) != VK_SUCCESS) {
626bf215546Sopenharmony_ci            mesa_loge("ZINK: vkCreateBuffer failed");
627bf215546Sopenharmony_ci            goto fail2;
628bf215546Sopenharmony_ci         }
629bf215546Sopenharmony_ci      }
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_ci      VKSCR(GetBufferMemoryRequirements)(screen->dev, obj->buffer, &reqs);
632bf215546Sopenharmony_ci      if (templ->usage == PIPE_USAGE_STAGING)
633bf215546Sopenharmony_ci         flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
634bf215546Sopenharmony_ci      else if (templ->usage == PIPE_USAGE_STREAM)
635bf215546Sopenharmony_ci         flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
636bf215546Sopenharmony_ci      else if (templ->usage == PIPE_USAGE_IMMUTABLE)
637bf215546Sopenharmony_ci         flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
638bf215546Sopenharmony_ci      else
639bf215546Sopenharmony_ci         flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
640bf215546Sopenharmony_ci      obj->is_buffer = true;
641bf215546Sopenharmony_ci      obj->transfer_dst = true;
642bf215546Sopenharmony_ci   } else {
643bf215546Sopenharmony_ci      bool winsys_modifier = (export_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) && whandle && whandle->modifier != DRM_FORMAT_MOD_INVALID;
644bf215546Sopenharmony_ci      uint64_t mods[10];
645bf215546Sopenharmony_ci      bool try_modifiers = false;
646bf215546Sopenharmony_ci      if ((export_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) &&
647bf215546Sopenharmony_ci          whandle && whandle->modifier == DRM_FORMAT_MOD_INVALID && whandle->stride) {
648bf215546Sopenharmony_ci         modifiers = mods;
649bf215546Sopenharmony_ci         modifiers_count = screen->modifier_props[templ->format].drmFormatModifierCount;
650bf215546Sopenharmony_ci         for (unsigned j = 0; j < modifiers_count; j++)
651bf215546Sopenharmony_ci            mods[j] = screen->modifier_props[templ->format].pDrmFormatModifierProperties[j].drmFormatModifier;
652bf215546Sopenharmony_ci         if (modifiers_count > 1)
653bf215546Sopenharmony_ci            try_modifiers = true;
654bf215546Sopenharmony_ci      }
655bf215546Sopenharmony_ci      const uint64_t *ici_modifiers = winsys_modifier ? &whandle->modifier : modifiers;
656bf215546Sopenharmony_ci      unsigned ici_modifier_count = winsys_modifier ? 1 : modifiers_count;
657bf215546Sopenharmony_ci      bool success = false;
658bf215546Sopenharmony_ci      VkImageCreateInfo ici;
659bf215546Sopenharmony_ci      enum pipe_format srgb = PIPE_FORMAT_NONE;
660bf215546Sopenharmony_ci      /* We use modifiers as a proxy for "this surface is used as a window system render target".
661bf215546Sopenharmony_ci       * For winsys, we need to be able to mutate between srgb and linear, but we don't need general
662bf215546Sopenharmony_ci       * image view/shader image format compatibility (that path means losing fast clears or compression on some hardware).
663bf215546Sopenharmony_ci       */
664bf215546Sopenharmony_ci      if (ici_modifier_count) {
665bf215546Sopenharmony_ci         srgb = util_format_is_srgb(templ->format) ? util_format_linear(templ->format) : util_format_srgb(templ->format);
666bf215546Sopenharmony_ci         /* why do these helpers have different default return values? */
667bf215546Sopenharmony_ci         if (srgb == templ->format)
668bf215546Sopenharmony_ci            srgb = PIPE_FORMAT_NONE;
669bf215546Sopenharmony_ci      }
670bf215546Sopenharmony_ci      VkFormat formats[2];
671bf215546Sopenharmony_ci      VkImageFormatListCreateInfo format_list;
672bf215546Sopenharmony_ci      if (srgb) {
673bf215546Sopenharmony_ci         format_list.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO;
674bf215546Sopenharmony_ci         format_list.pNext = NULL;
675bf215546Sopenharmony_ci         format_list.viewFormatCount = 2;
676bf215546Sopenharmony_ci         format_list.pViewFormats = formats;
677bf215546Sopenharmony_ci
678bf215546Sopenharmony_ci         formats[0] = zink_get_format(screen, templ->format);
679bf215546Sopenharmony_ci         formats[1] = zink_get_format(screen, srgb);
680bf215546Sopenharmony_ci         ici.pNext = &format_list;
681bf215546Sopenharmony_ci      } else {
682bf215546Sopenharmony_ci         ici.pNext = NULL;
683bf215546Sopenharmony_ci      }
684bf215546Sopenharmony_ci      uint64_t mod = create_ici(screen, &ici, templ, external == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
685bf215546Sopenharmony_ci                                templ->bind, ici_modifier_count, ici_modifiers, &success);
686bf215546Sopenharmony_ci      VkExternalMemoryImageCreateInfo emici;
687bf215546Sopenharmony_ci      VkImageDrmFormatModifierExplicitCreateInfoEXT idfmeci;
688bf215546Sopenharmony_ci      VkImageDrmFormatModifierListCreateInfoEXT idfmlci;
689bf215546Sopenharmony_ci      VkSubresourceLayout plane_layouts[4];
690bf215546Sopenharmony_ci      VkSubresourceLayout plane_layout = {
691bf215546Sopenharmony_ci         .offset = whandle ? whandle->offset : 0,
692bf215546Sopenharmony_ci         .size = 0,
693bf215546Sopenharmony_ci         .rowPitch = whandle ? whandle->stride : 0,
694bf215546Sopenharmony_ci         .arrayPitch = 0,
695bf215546Sopenharmony_ci         .depthPitch = 0,
696bf215546Sopenharmony_ci      };
697bf215546Sopenharmony_ci      if (!success)
698bf215546Sopenharmony_ci         goto fail1;
699bf215546Sopenharmony_ci
700bf215546Sopenharmony_ci      obj->render_target = (ici.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0;
701bf215546Sopenharmony_ci
702bf215546Sopenharmony_ci      if (shared || external) {
703bf215546Sopenharmony_ci         emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
704bf215546Sopenharmony_ci         emici.pNext = ici.pNext;
705bf215546Sopenharmony_ci         emici.handleTypes = export_types;
706bf215546Sopenharmony_ci         ici.pNext = &emici;
707bf215546Sopenharmony_ci
708bf215546Sopenharmony_ci         assert(ici.tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT || mod != DRM_FORMAT_MOD_INVALID);
709bf215546Sopenharmony_ci         if (whandle && ici.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
710bf215546Sopenharmony_ci            assert(mod == whandle->modifier || !winsys_modifier);
711bf215546Sopenharmony_ci            idfmeci.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
712bf215546Sopenharmony_ci            idfmeci.pNext = ici.pNext;
713bf215546Sopenharmony_ci            idfmeci.drmFormatModifier = mod;
714bf215546Sopenharmony_ci
715bf215546Sopenharmony_ci            idfmeci.drmFormatModifierPlaneCount = obj->plane_count;
716bf215546Sopenharmony_ci            plane_layouts[0] = plane_layout;
717bf215546Sopenharmony_ci            pnext = templ->next;
718bf215546Sopenharmony_ci            for (unsigned i = 1; i < obj->plane_count; i++, pnext = pnext->next) {
719bf215546Sopenharmony_ci               struct zink_resource *next = zink_resource(pnext);
720bf215546Sopenharmony_ci               obj->plane_offsets[i] = plane_layouts[i].offset = next->obj->plane_offsets[i];
721bf215546Sopenharmony_ci               obj->plane_strides[i] = plane_layouts[i].rowPitch = next->obj->plane_strides[i];
722bf215546Sopenharmony_ci               plane_layouts[i].size = 0;
723bf215546Sopenharmony_ci               plane_layouts[i].arrayPitch = 0;
724bf215546Sopenharmony_ci               plane_layouts[i].depthPitch = 0;
725bf215546Sopenharmony_ci            }
726bf215546Sopenharmony_ci            idfmeci.pPlaneLayouts = plane_layouts;
727bf215546Sopenharmony_ci
728bf215546Sopenharmony_ci            ici.pNext = &idfmeci;
729bf215546Sopenharmony_ci         } else if (ici.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
730bf215546Sopenharmony_ci            idfmlci.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT;
731bf215546Sopenharmony_ci            idfmlci.pNext = ici.pNext;
732bf215546Sopenharmony_ci            idfmlci.drmFormatModifierCount = modifiers_count;
733bf215546Sopenharmony_ci            idfmlci.pDrmFormatModifiers = modifiers;
734bf215546Sopenharmony_ci            ici.pNext = &idfmlci;
735bf215546Sopenharmony_ci         } else if (ici.tiling == VK_IMAGE_TILING_OPTIMAL) {
736bf215546Sopenharmony_ci            shared = false;
737bf215546Sopenharmony_ci         }
738bf215546Sopenharmony_ci      }
739bf215546Sopenharmony_ci
740bf215546Sopenharmony_ci      if (optimal_tiling)
741bf215546Sopenharmony_ci         *optimal_tiling = ici.tiling == VK_IMAGE_TILING_OPTIMAL;
742bf215546Sopenharmony_ci
743bf215546Sopenharmony_ci      if (ici.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
744bf215546Sopenharmony_ci         obj->transfer_dst = true;
745bf215546Sopenharmony_ci
746bf215546Sopenharmony_ci#if defined(ZINK_USE_DMABUF) && !defined(_WIN32)
747bf215546Sopenharmony_ci      if (obj->is_aux) {
748bf215546Sopenharmony_ci         obj->modifier = mod;
749bf215546Sopenharmony_ci         obj->modifier_aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT << whandle->plane;
750bf215546Sopenharmony_ci         obj->plane_offsets[whandle->plane] = whandle->offset;
751bf215546Sopenharmony_ci         obj->plane_strides[whandle->plane] = whandle->stride;
752bf215546Sopenharmony_ci         obj->handle = os_dupfd_cloexec(whandle->handle);
753bf215546Sopenharmony_ci         if (obj->handle < 0) {
754bf215546Sopenharmony_ci            mesa_loge("ZINK: failed to dup dmabuf fd: %s\n", strerror(errno));
755bf215546Sopenharmony_ci            goto fail1;
756bf215546Sopenharmony_ci         }
757bf215546Sopenharmony_ci         return obj;
758bf215546Sopenharmony_ci      }
759bf215546Sopenharmony_ci#endif
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci      VkFormatFeatureFlags feats = 0;
762bf215546Sopenharmony_ci      switch (ici.tiling) {
763bf215546Sopenharmony_ci      case VK_IMAGE_TILING_LINEAR:
764bf215546Sopenharmony_ci         feats = screen->format_props[templ->format].linearTilingFeatures;
765bf215546Sopenharmony_ci         break;
766bf215546Sopenharmony_ci      case VK_IMAGE_TILING_OPTIMAL:
767bf215546Sopenharmony_ci         feats = screen->format_props[templ->format].optimalTilingFeatures;
768bf215546Sopenharmony_ci         break;
769bf215546Sopenharmony_ci      case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT:
770bf215546Sopenharmony_ci         feats = VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM;
771bf215546Sopenharmony_ci         /*
772bf215546Sopenharmony_ci            If is tiling then VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, the value of
773bf215546Sopenharmony_ci            imageCreateFormatFeatures is found by calling vkGetPhysicalDeviceFormatProperties2
774bf215546Sopenharmony_ci            with VkImageFormatProperties::format equal to VkImageCreateInfo::format and with
775bf215546Sopenharmony_ci            VkDrmFormatModifierPropertiesListEXT chained into VkImageFormatProperties2; by
776bf215546Sopenharmony_ci            collecting all members of the returned array
777bf215546Sopenharmony_ci            VkDrmFormatModifierPropertiesListEXT::pDrmFormatModifierProperties
778bf215546Sopenharmony_ci            whose drmFormatModifier belongs to imageCreateDrmFormatModifiers; and by taking the bitwise
779bf215546Sopenharmony_ci            intersection, over the collected array members, of drmFormatModifierTilingFeatures.
780bf215546Sopenharmony_ci            (The resultant imageCreateFormatFeatures may be empty).
781bf215546Sopenharmony_ci            * -Chapter 12. Resource Creation
782bf215546Sopenharmony_ci          */
783bf215546Sopenharmony_ci         for (unsigned i = 0; i < screen->modifier_props[templ->format].drmFormatModifierCount; i++)
784bf215546Sopenharmony_ci            feats &= screen->modifier_props[templ->format].pDrmFormatModifierProperties[i].drmFormatModifierTilingFeatures;
785bf215546Sopenharmony_ci         break;
786bf215546Sopenharmony_ci      default:
787bf215546Sopenharmony_ci         unreachable("unknown tiling");
788bf215546Sopenharmony_ci      }
789bf215546Sopenharmony_ci      obj->vkfeats = feats;
790bf215546Sopenharmony_ci      if (util_format_is_yuv(templ->format)) {
791bf215546Sopenharmony_ci         if (feats & VK_FORMAT_FEATURE_DISJOINT_BIT)
792bf215546Sopenharmony_ci            ici.flags |= VK_IMAGE_CREATE_DISJOINT_BIT;
793bf215546Sopenharmony_ci         VkSamplerYcbcrConversionCreateInfo sycci = {0};
794bf215546Sopenharmony_ci         sycci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
795bf215546Sopenharmony_ci         sycci.pNext = NULL;
796bf215546Sopenharmony_ci         sycci.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
797bf215546Sopenharmony_ci         sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
798bf215546Sopenharmony_ci         sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
799bf215546Sopenharmony_ci         sycci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
800bf215546Sopenharmony_ci         sycci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
801bf215546Sopenharmony_ci         sycci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
802bf215546Sopenharmony_ci         sycci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
803bf215546Sopenharmony_ci         if (!feats || (feats & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) {
804bf215546Sopenharmony_ci            sycci.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
805bf215546Sopenharmony_ci            sycci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
806bf215546Sopenharmony_ci         } else {
807bf215546Sopenharmony_ci            assert(feats & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT);
808bf215546Sopenharmony_ci            sycci.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
809bf215546Sopenharmony_ci            sycci.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
810bf215546Sopenharmony_ci         }
811bf215546Sopenharmony_ci         sycci.chromaFilter = VK_FILTER_LINEAR;
812bf215546Sopenharmony_ci         sycci.forceExplicitReconstruction = VK_FALSE;
813bf215546Sopenharmony_ci         VkResult res = VKSCR(CreateSamplerYcbcrConversion)(screen->dev, &sycci, NULL, &obj->sampler_conversion);
814bf215546Sopenharmony_ci         if (res != VK_SUCCESS) {
815bf215546Sopenharmony_ci            mesa_loge("ZINK: vkCreateSamplerYcbcrConversion failed");
816bf215546Sopenharmony_ci            goto fail1;
817bf215546Sopenharmony_ci         }
818bf215546Sopenharmony_ci      } else if (whandle) {
819bf215546Sopenharmony_ci         obj->plane_strides[whandle->plane] = whandle->stride;
820bf215546Sopenharmony_ci      }
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci      VkResult result = VKSCR(CreateImage)(screen->dev, &ici, NULL, &obj->image);
823bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
824bf215546Sopenharmony_ci         if (try_modifiers) {
825bf215546Sopenharmony_ci            for (unsigned i = 0; i < modifiers_count; i++) {
826bf215546Sopenharmony_ci               if (modifiers[i] == mod)
827bf215546Sopenharmony_ci                  continue;
828bf215546Sopenharmony_ci               idfmeci.drmFormatModifier = modifiers[i];
829bf215546Sopenharmony_ci               result = VKSCR(CreateImage)(screen->dev, &ici, NULL, &obj->image);
830bf215546Sopenharmony_ci               if (result == VK_SUCCESS)
831bf215546Sopenharmony_ci                  break;
832bf215546Sopenharmony_ci            }
833bf215546Sopenharmony_ci         }
834bf215546Sopenharmony_ci      }
835bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
836bf215546Sopenharmony_ci         mesa_loge("ZINK: vkCreateImage failed (%s)", vk_Result_to_str(result));
837bf215546Sopenharmony_ci         goto fail1;
838bf215546Sopenharmony_ci      }
839bf215546Sopenharmony_ci
840bf215546Sopenharmony_ci      if (ici.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
841bf215546Sopenharmony_ci         VkImageDrmFormatModifierPropertiesEXT modprops = {0};
842bf215546Sopenharmony_ci         modprops.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT;
843bf215546Sopenharmony_ci         result = VKSCR(GetImageDrmFormatModifierPropertiesEXT)(screen->dev, obj->image, &modprops);
844bf215546Sopenharmony_ci         if (result != VK_SUCCESS) {
845bf215546Sopenharmony_ci            mesa_loge("ZINK: vkGetImageDrmFormatModifierPropertiesEXT failed");
846bf215546Sopenharmony_ci            goto fail1;
847bf215546Sopenharmony_ci         }
848bf215546Sopenharmony_ci         obj->modifier = modprops.drmFormatModifier;
849bf215546Sopenharmony_ci         unsigned num_dmabuf_planes = screen->base.get_dmabuf_modifier_planes(&screen->base, obj->modifier, templ->format);
850bf215546Sopenharmony_ci         obj->modifier_aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
851bf215546Sopenharmony_ci         if (num_dmabuf_planes > 1)
852bf215546Sopenharmony_ci            obj->modifier_aspect |= VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
853bf215546Sopenharmony_ci         if (num_dmabuf_planes > 2)
854bf215546Sopenharmony_ci            obj->modifier_aspect |= VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
855bf215546Sopenharmony_ci         if (num_dmabuf_planes > 3)
856bf215546Sopenharmony_ci            obj->modifier_aspect |= VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
857bf215546Sopenharmony_ci         assert(num_dmabuf_planes <= 4);
858bf215546Sopenharmony_ci      }
859bf215546Sopenharmony_ci
860bf215546Sopenharmony_ci      if (VKSCR(GetImageMemoryRequirements2)) {
861bf215546Sopenharmony_ci         VkMemoryRequirements2 req2;
862bf215546Sopenharmony_ci         req2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
863bf215546Sopenharmony_ci         VkImageMemoryRequirementsInfo2 info2;
864bf215546Sopenharmony_ci         info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
865bf215546Sopenharmony_ci         info2.pNext = NULL;
866bf215546Sopenharmony_ci         info2.image = obj->image;
867bf215546Sopenharmony_ci         VkMemoryDedicatedRequirements ded;
868bf215546Sopenharmony_ci         ded.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
869bf215546Sopenharmony_ci         ded.pNext = NULL;
870bf215546Sopenharmony_ci         req2.pNext = &ded;
871bf215546Sopenharmony_ci         VkImagePlaneMemoryRequirementsInfo plane;
872bf215546Sopenharmony_ci         plane.sType = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO;
873bf215546Sopenharmony_ci         plane.pNext = NULL;
874bf215546Sopenharmony_ci         if (num_planes > 1)
875bf215546Sopenharmony_ci            info2.pNext = &plane;
876bf215546Sopenharmony_ci         unsigned offset = 0;
877bf215546Sopenharmony_ci         for (unsigned i = 0; i < num_planes; i++) {
878bf215546Sopenharmony_ci            assert(i < ARRAY_SIZE(plane_aspects));
879bf215546Sopenharmony_ci            plane.planeAspect = plane_aspects[i];
880bf215546Sopenharmony_ci            VKSCR(GetImageMemoryRequirements2)(screen->dev, &info2, &req2);
881bf215546Sopenharmony_ci            if (!i)
882bf215546Sopenharmony_ci               reqs.alignment = req2.memoryRequirements.alignment;
883bf215546Sopenharmony_ci            obj->plane_offsets[i] = offset;
884bf215546Sopenharmony_ci            offset += req2.memoryRequirements.size;
885bf215546Sopenharmony_ci            reqs.size += req2.memoryRequirements.size;
886bf215546Sopenharmony_ci            reqs.memoryTypeBits |= req2.memoryRequirements.memoryTypeBits;
887bf215546Sopenharmony_ci            need_dedicated |= ded.prefersDedicatedAllocation || ded.requiresDedicatedAllocation;
888bf215546Sopenharmony_ci         }
889bf215546Sopenharmony_ci      } else {
890bf215546Sopenharmony_ci         VKSCR(GetImageMemoryRequirements)(screen->dev, obj->image, &reqs);
891bf215546Sopenharmony_ci      }
892bf215546Sopenharmony_ci      if (templ->usage == PIPE_USAGE_STAGING && ici.tiling == VK_IMAGE_TILING_LINEAR)
893bf215546Sopenharmony_ci        flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
894bf215546Sopenharmony_ci      else
895bf215546Sopenharmony_ci        flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
896bf215546Sopenharmony_ci
897bf215546Sopenharmony_ci      obj->vkflags = ici.flags;
898bf215546Sopenharmony_ci      obj->vkusage = ici.usage;
899bf215546Sopenharmony_ci   }
900bf215546Sopenharmony_ci   obj->alignment = reqs.alignment;
901bf215546Sopenharmony_ci
902bf215546Sopenharmony_ci   if (templ->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT || templ->usage == PIPE_USAGE_DYNAMIC)
903bf215546Sopenharmony_ci      flags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
904bf215546Sopenharmony_ci   else if (!(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
905bf215546Sopenharmony_ci            templ->usage == PIPE_USAGE_STAGING)
906bf215546Sopenharmony_ci      flags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
907bf215546Sopenharmony_ci
908bf215546Sopenharmony_ci   if (templ->bind & ZINK_BIND_TRANSIENT)
909bf215546Sopenharmony_ci      flags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
910bf215546Sopenharmony_ci
911bf215546Sopenharmony_ci   VkMemoryAllocateInfo mai;
912bf215546Sopenharmony_ci   enum zink_alloc_flag aflags = templ->flags & PIPE_RESOURCE_FLAG_SPARSE ? ZINK_ALLOC_SPARSE : 0;
913bf215546Sopenharmony_ci   mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
914bf215546Sopenharmony_ci   mai.pNext = NULL;
915bf215546Sopenharmony_ci   mai.allocationSize = reqs.size;
916bf215546Sopenharmony_ci   enum zink_heap heap = zink_heap_from_domain_flags(flags, aflags);
917bf215546Sopenharmony_ci   mai.memoryTypeIndex = screen->heap_map[heap];
918bf215546Sopenharmony_ci   if (unlikely(!(reqs.memoryTypeBits & BITFIELD_BIT(mai.memoryTypeIndex)))) {
919bf215546Sopenharmony_ci      /* not valid based on reqs; demote to more compatible type */
920bf215546Sopenharmony_ci      switch (heap) {
921bf215546Sopenharmony_ci      case ZINK_HEAP_DEVICE_LOCAL_VISIBLE:
922bf215546Sopenharmony_ci         heap = ZINK_HEAP_DEVICE_LOCAL;
923bf215546Sopenharmony_ci         break;
924bf215546Sopenharmony_ci      case ZINK_HEAP_HOST_VISIBLE_CACHED:
925bf215546Sopenharmony_ci         heap = ZINK_HEAP_HOST_VISIBLE_COHERENT;
926bf215546Sopenharmony_ci         break;
927bf215546Sopenharmony_ci      default:
928bf215546Sopenharmony_ci         break;
929bf215546Sopenharmony_ci      }
930bf215546Sopenharmony_ci      mai.memoryTypeIndex = screen->heap_map[heap];
931bf215546Sopenharmony_ci      assert(reqs.memoryTypeBits & BITFIELD_BIT(mai.memoryTypeIndex));
932bf215546Sopenharmony_ci   }
933bf215546Sopenharmony_ci
934bf215546Sopenharmony_ci   VkMemoryDedicatedAllocateInfo ded_alloc_info = {
935bf215546Sopenharmony_ci      .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
936bf215546Sopenharmony_ci      .pNext = mai.pNext,
937bf215546Sopenharmony_ci      .image = obj->image,
938bf215546Sopenharmony_ci      .buffer = VK_NULL_HANDLE,
939bf215546Sopenharmony_ci   };
940bf215546Sopenharmony_ci
941bf215546Sopenharmony_ci   if (screen->info.have_KHR_dedicated_allocation && need_dedicated) {
942bf215546Sopenharmony_ci      ded_alloc_info.pNext = mai.pNext;
943bf215546Sopenharmony_ci      mai.pNext = &ded_alloc_info;
944bf215546Sopenharmony_ci   }
945bf215546Sopenharmony_ci
946bf215546Sopenharmony_ci   VkExportMemoryAllocateInfo emai;
947bf215546Sopenharmony_ci   if ((templ->bind & ZINK_BIND_VIDEO) || ((templ->bind & PIPE_BIND_SHARED) && shared) || (templ->bind & ZINK_BIND_DMABUF)) {
948bf215546Sopenharmony_ci      emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
949bf215546Sopenharmony_ci      emai.handleTypes = export_types;
950bf215546Sopenharmony_ci
951bf215546Sopenharmony_ci      emai.pNext = mai.pNext;
952bf215546Sopenharmony_ci      mai.pNext = &emai;
953bf215546Sopenharmony_ci      obj->exportable = true;
954bf215546Sopenharmony_ci   }
955bf215546Sopenharmony_ci
956bf215546Sopenharmony_ci#ifdef ZINK_USE_DMABUF
957bf215546Sopenharmony_ci
958bf215546Sopenharmony_ci#if !defined(_WIN32)
959bf215546Sopenharmony_ci   VkImportMemoryFdInfoKHR imfi = {
960bf215546Sopenharmony_ci      VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
961bf215546Sopenharmony_ci      NULL,
962bf215546Sopenharmony_ci   };
963bf215546Sopenharmony_ci
964bf215546Sopenharmony_ci   if (whandle) {
965bf215546Sopenharmony_ci      imfi.pNext = NULL;
966bf215546Sopenharmony_ci      imfi.handleType = external;
967bf215546Sopenharmony_ci      imfi.fd = os_dupfd_cloexec(whandle->handle);
968bf215546Sopenharmony_ci      if (imfi.fd < 0) {
969bf215546Sopenharmony_ci         mesa_loge("ZINK: failed to dup dmabuf fd: %s\n", strerror(errno));
970bf215546Sopenharmony_ci         goto fail1;
971bf215546Sopenharmony_ci      }
972bf215546Sopenharmony_ci
973bf215546Sopenharmony_ci      imfi.pNext = mai.pNext;
974bf215546Sopenharmony_ci      mai.pNext = &imfi;
975bf215546Sopenharmony_ci   }
976bf215546Sopenharmony_ci#else
977bf215546Sopenharmony_ci   VkImportMemoryWin32HandleInfoKHR imfi = {
978bf215546Sopenharmony_ci      VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
979bf215546Sopenharmony_ci      NULL,
980bf215546Sopenharmony_ci   };
981bf215546Sopenharmony_ci
982bf215546Sopenharmony_ci   if (whandle) {
983bf215546Sopenharmony_ci      HANDLE source_target = GetCurrentProcess();
984bf215546Sopenharmony_ci      HANDLE out_handle;
985bf215546Sopenharmony_ci
986bf215546Sopenharmony_ci      bool result = DuplicateHandle(source_target, whandle->handle, source_target, &out_handle, 0, false, DUPLICATE_SAME_ACCESS);
987bf215546Sopenharmony_ci
988bf215546Sopenharmony_ci      if (!result || !out_handle) {
989bf215546Sopenharmony_ci         mesa_loge("ZINK: failed to DuplicateHandle with winerr: %08x\n", (int)GetLastError());
990bf215546Sopenharmony_ci         goto fail1;
991bf215546Sopenharmony_ci      }
992bf215546Sopenharmony_ci
993bf215546Sopenharmony_ci      imfi.pNext = NULL;
994bf215546Sopenharmony_ci      imfi.handleType = external;
995bf215546Sopenharmony_ci      imfi.handle = out_handle;
996bf215546Sopenharmony_ci
997bf215546Sopenharmony_ci      imfi.pNext = mai.pNext;
998bf215546Sopenharmony_ci      mai.pNext = &imfi;
999bf215546Sopenharmony_ci   }
1000bf215546Sopenharmony_ci#endif
1001bf215546Sopenharmony_ci
1002bf215546Sopenharmony_ci#endif
1003bf215546Sopenharmony_ci
1004bf215546Sopenharmony_ci   unsigned alignment = MAX2(reqs.alignment, 256);
1005bf215546Sopenharmony_ci   if (templ->usage == PIPE_USAGE_STAGING && obj->is_buffer)
1006bf215546Sopenharmony_ci      alignment = MAX2(alignment, screen->info.props.limits.minMemoryMapAlignment);
1007bf215546Sopenharmony_ci   obj->alignment = alignment;
1008bf215546Sopenharmony_ciretry:
1009bf215546Sopenharmony_ci   obj->bo = zink_bo(zink_bo_create(screen, reqs.size, alignment, heap, mai.pNext ? ZINK_ALLOC_NO_SUBALLOC : 0, mai.pNext));
1010bf215546Sopenharmony_ci   if (!obj->bo) {
1011bf215546Sopenharmony_ci      if (heap == ZINK_HEAP_DEVICE_LOCAL_VISIBLE) {
1012bf215546Sopenharmony_ci         if (templ->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT || templ->usage == PIPE_USAGE_DYNAMIC)
1013bf215546Sopenharmony_ci            heap = ZINK_HEAP_HOST_VISIBLE_COHERENT;
1014bf215546Sopenharmony_ci         else
1015bf215546Sopenharmony_ci            heap = ZINK_HEAP_DEVICE_LOCAL;
1016bf215546Sopenharmony_ci         goto retry;
1017bf215546Sopenharmony_ci      }
1018bf215546Sopenharmony_ci      goto fail2;
1019bf215546Sopenharmony_ci   }
1020bf215546Sopenharmony_ci   if (aflags == ZINK_ALLOC_SPARSE) {
1021bf215546Sopenharmony_ci      obj->size = templ->width0;
1022bf215546Sopenharmony_ci   } else {
1023bf215546Sopenharmony_ci      obj->offset = zink_bo_get_offset(obj->bo);
1024bf215546Sopenharmony_ci      obj->size = zink_bo_get_size(obj->bo);
1025bf215546Sopenharmony_ci   }
1026bf215546Sopenharmony_ci
1027bf215546Sopenharmony_ci   obj->coherent = obj->bo->base.placement & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
1028bf215546Sopenharmony_ci   if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE)) {
1029bf215546Sopenharmony_ci      obj->host_visible = obj->bo->base.placement & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1030bf215546Sopenharmony_ci   }
1031bf215546Sopenharmony_ci
1032bf215546Sopenharmony_ci   if (templ->target == PIPE_BUFFER) {
1033bf215546Sopenharmony_ci      if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE)) {
1034bf215546Sopenharmony_ci         if (VKSCR(BindBufferMemory)(screen->dev, obj->buffer, zink_bo_get_mem(obj->bo), obj->offset) != VK_SUCCESS) {
1035bf215546Sopenharmony_ci            mesa_loge("ZINK: vkBindBufferMemory failed");
1036bf215546Sopenharmony_ci            goto fail3;
1037bf215546Sopenharmony_ci         }
1038bf215546Sopenharmony_ci         if (obj->storage_buffer && VKSCR(BindBufferMemory)(screen->dev, obj->storage_buffer, zink_bo_get_mem(obj->bo), obj->offset) != VK_SUCCESS) {
1039bf215546Sopenharmony_ci            mesa_loge("ZINK: vkBindBufferMemory failed");
1040bf215546Sopenharmony_ci            goto fail3;
1041bf215546Sopenharmony_ci         }
1042bf215546Sopenharmony_ci      }
1043bf215546Sopenharmony_ci   } else {
1044bf215546Sopenharmony_ci      if (num_planes > 1) {
1045bf215546Sopenharmony_ci         VkBindImageMemoryInfo infos[3];
1046bf215546Sopenharmony_ci         VkBindImagePlaneMemoryInfo planes[3];
1047bf215546Sopenharmony_ci         for (unsigned i = 0; i < num_planes; i++) {
1048bf215546Sopenharmony_ci            infos[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
1049bf215546Sopenharmony_ci            infos[i].image = obj->image;
1050bf215546Sopenharmony_ci            infos[i].memory = zink_bo_get_mem(obj->bo);
1051bf215546Sopenharmony_ci            infos[i].memoryOffset = obj->plane_offsets[i];
1052bf215546Sopenharmony_ci            if (templ->bind & ZINK_BIND_VIDEO) {
1053bf215546Sopenharmony_ci               infos[i].pNext = &planes[i];
1054bf215546Sopenharmony_ci               planes[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
1055bf215546Sopenharmony_ci               planes[i].pNext = NULL;
1056bf215546Sopenharmony_ci               planes[i].planeAspect = plane_aspects[i];
1057bf215546Sopenharmony_ci            }
1058bf215546Sopenharmony_ci         }
1059bf215546Sopenharmony_ci         if (VKSCR(BindImageMemory2)(screen->dev, num_planes, infos) != VK_SUCCESS) {
1060bf215546Sopenharmony_ci            mesa_loge("ZINK: vkBindImageMemory2 failed");
1061bf215546Sopenharmony_ci            goto fail3;
1062bf215546Sopenharmony_ci         }
1063bf215546Sopenharmony_ci      } else {
1064bf215546Sopenharmony_ci         if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE))
1065bf215546Sopenharmony_ci            if (VKSCR(BindImageMemory)(screen->dev, obj->image, zink_bo_get_mem(obj->bo), obj->offset) != VK_SUCCESS) {
1066bf215546Sopenharmony_ci               mesa_loge("ZINK: vkBindImageMemory failed");
1067bf215546Sopenharmony_ci               goto fail3;
1068bf215546Sopenharmony_ci            }
1069bf215546Sopenharmony_ci      }
1070bf215546Sopenharmony_ci   }
1071bf215546Sopenharmony_ci   return obj;
1072bf215546Sopenharmony_ci
1073bf215546Sopenharmony_cifail3:
1074bf215546Sopenharmony_ci   zink_bo_unref(screen, obj->bo);
1075bf215546Sopenharmony_ci
1076bf215546Sopenharmony_cifail2:
1077bf215546Sopenharmony_ci   if (templ->target == PIPE_BUFFER) {
1078bf215546Sopenharmony_ci      VKSCR(DestroyBuffer)(screen->dev, obj->buffer, NULL);
1079bf215546Sopenharmony_ci      VKSCR(DestroyBuffer)(screen->dev, obj->storage_buffer, NULL);
1080bf215546Sopenharmony_ci   } else
1081bf215546Sopenharmony_ci      VKSCR(DestroyImage)(screen->dev, obj->image, NULL);
1082bf215546Sopenharmony_cifail1:
1083bf215546Sopenharmony_ci   FREE(obj);
1084bf215546Sopenharmony_ci   return NULL;
1085bf215546Sopenharmony_ci}
1086bf215546Sopenharmony_ci
1087bf215546Sopenharmony_cistatic struct pipe_resource *
1088bf215546Sopenharmony_ciresource_create(struct pipe_screen *pscreen,
1089bf215546Sopenharmony_ci                const struct pipe_resource *templ,
1090bf215546Sopenharmony_ci                struct winsys_handle *whandle,
1091bf215546Sopenharmony_ci                unsigned external_usage,
1092bf215546Sopenharmony_ci                const uint64_t *modifiers, int modifiers_count,
1093bf215546Sopenharmony_ci                const void *loader_private)
1094bf215546Sopenharmony_ci{
1095bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pscreen);
1096bf215546Sopenharmony_ci   struct zink_resource *res = CALLOC_STRUCT_CL(zink_resource);
1097bf215546Sopenharmony_ci
1098bf215546Sopenharmony_ci   if (modifiers_count > 0 && screen->info.have_EXT_image_drm_format_modifier) {
1099bf215546Sopenharmony_ci      /* for rebinds */
1100bf215546Sopenharmony_ci      res->modifiers_count = modifiers_count;
1101bf215546Sopenharmony_ci      res->modifiers = mem_dup(modifiers, modifiers_count * sizeof(uint64_t));
1102bf215546Sopenharmony_ci      if (!res->modifiers) {
1103bf215546Sopenharmony_ci         FREE_CL(res);
1104bf215546Sopenharmony_ci         return NULL;
1105bf215546Sopenharmony_ci      }
1106bf215546Sopenharmony_ci   }
1107bf215546Sopenharmony_ci
1108bf215546Sopenharmony_ci   res->base.b = *templ;
1109bf215546Sopenharmony_ci
1110bf215546Sopenharmony_ci   threaded_resource_init(&res->base.b, false);
1111bf215546Sopenharmony_ci   pipe_reference_init(&res->base.b.reference, 1);
1112bf215546Sopenharmony_ci   res->base.b.screen = pscreen;
1113bf215546Sopenharmony_ci
1114bf215546Sopenharmony_ci   bool optimal_tiling = false;
1115bf215546Sopenharmony_ci   struct pipe_resource templ2 = *templ;
1116bf215546Sopenharmony_ci   if (templ2.flags & PIPE_RESOURCE_FLAG_SPARSE)
1117bf215546Sopenharmony_ci      templ2.bind |= PIPE_BIND_SHADER_IMAGE;
1118bf215546Sopenharmony_ci   if (screen->faked_e5sparse && templ->format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
1119bf215546Sopenharmony_ci      templ2.flags &= ~PIPE_RESOURCE_FLAG_SPARSE;
1120bf215546Sopenharmony_ci      res->base.b.flags &= ~PIPE_RESOURCE_FLAG_SPARSE;
1121bf215546Sopenharmony_ci   }
1122bf215546Sopenharmony_ci   res->obj = resource_object_create(screen, &templ2, whandle, &optimal_tiling, modifiers, modifiers_count, loader_private);
1123bf215546Sopenharmony_ci   if (!res->obj) {
1124bf215546Sopenharmony_ci      free(res->modifiers);
1125bf215546Sopenharmony_ci      FREE_CL(res);
1126bf215546Sopenharmony_ci      return NULL;
1127bf215546Sopenharmony_ci   }
1128bf215546Sopenharmony_ci
1129bf215546Sopenharmony_ci   res->internal_format = templ->format;
1130bf215546Sopenharmony_ci   if (templ->target == PIPE_BUFFER) {
1131bf215546Sopenharmony_ci      util_range_init(&res->valid_buffer_range);
1132bf215546Sopenharmony_ci      res->base.b.bind |= PIPE_BIND_SHADER_IMAGE;
1133bf215546Sopenharmony_ci      if (!screen->resizable_bar && templ->width0 >= 8196) {
1134bf215546Sopenharmony_ci         /* We don't want to evict buffers from VRAM by mapping them for CPU access,
1135bf215546Sopenharmony_ci          * because they might never be moved back again. If a buffer is large enough,
1136bf215546Sopenharmony_ci          * upload data by copying from a temporary GTT buffer. 8K might not seem much,
1137bf215546Sopenharmony_ci          * but there can be 100000 buffers.
1138bf215546Sopenharmony_ci          *
1139bf215546Sopenharmony_ci          * This tweak improves performance for viewperf.
1140bf215546Sopenharmony_ci          */
1141bf215546Sopenharmony_ci         res->base.b.flags |= PIPE_RESOURCE_FLAG_DONT_MAP_DIRECTLY;
1142bf215546Sopenharmony_ci      }
1143bf215546Sopenharmony_ci   } else {
1144bf215546Sopenharmony_ci      if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE)
1145bf215546Sopenharmony_ci         res->base.b.bind |= PIPE_BIND_SHADER_IMAGE;
1146bf215546Sopenharmony_ci      if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE) {
1147bf215546Sopenharmony_ci         uint32_t count = 1;
1148bf215546Sopenharmony_ci         VKSCR(GetImageSparseMemoryRequirements)(screen->dev, res->obj->image, &count, &res->sparse);
1149bf215546Sopenharmony_ci         res->base.b.nr_sparse_levels = res->sparse.imageMipTailFirstLod;
1150bf215546Sopenharmony_ci      }
1151bf215546Sopenharmony_ci      res->format = zink_get_format(screen, templ->format);
1152bf215546Sopenharmony_ci      if (templ->target == PIPE_TEXTURE_1D || templ->target == PIPE_TEXTURE_1D_ARRAY) {
1153bf215546Sopenharmony_ci         res->need_2D = (screen->need_2D_zs && util_format_is_depth_or_stencil(templ->format)) ||
1154bf215546Sopenharmony_ci                        (screen->need_2D_sparse && (templ->flags & PIPE_RESOURCE_FLAG_SPARSE));
1155bf215546Sopenharmony_ci      }
1156bf215546Sopenharmony_ci      res->dmabuf_acquire = whandle && whandle->type == WINSYS_HANDLE_TYPE_FD;
1157bf215546Sopenharmony_ci      res->dmabuf = res->dmabuf_acquire = whandle && whandle->type == WINSYS_HANDLE_TYPE_FD;
1158bf215546Sopenharmony_ci      res->layout = res->dmabuf_acquire ? VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED;
1159bf215546Sopenharmony_ci      res->optimal_tiling = optimal_tiling;
1160bf215546Sopenharmony_ci      res->aspect = aspect_from_format(templ->format);
1161bf215546Sopenharmony_ci   }
1162bf215546Sopenharmony_ci
1163bf215546Sopenharmony_ci   if (loader_private) {
1164bf215546Sopenharmony_ci      if (templ->bind & PIPE_BIND_DISPLAY_TARGET) {
1165bf215546Sopenharmony_ci         /* backbuffer */
1166bf215546Sopenharmony_ci         res->obj->dt = zink_kopper_displaytarget_create(screen,
1167bf215546Sopenharmony_ci                                                         res->base.b.bind,
1168bf215546Sopenharmony_ci                                                         res->base.b.format,
1169bf215546Sopenharmony_ci                                                         templ->width0,
1170bf215546Sopenharmony_ci                                                         templ->height0,
1171bf215546Sopenharmony_ci                                                         64, loader_private,
1172bf215546Sopenharmony_ci                                                         &res->dt_stride);
1173bf215546Sopenharmony_ci         assert(res->obj->dt);
1174bf215546Sopenharmony_ci      } else {
1175bf215546Sopenharmony_ci         /* frontbuffer */
1176bf215546Sopenharmony_ci         struct zink_resource *back = (void*)loader_private;
1177bf215546Sopenharmony_ci         struct kopper_displaytarget *cdt = back->obj->dt;
1178bf215546Sopenharmony_ci         cdt->refcount++;
1179bf215546Sopenharmony_ci         assert(back->obj->dt);
1180bf215546Sopenharmony_ci         res->obj->dt = back->obj->dt;
1181bf215546Sopenharmony_ci      }
1182bf215546Sopenharmony_ci      struct kopper_displaytarget *cdt = res->obj->dt;
1183bf215546Sopenharmony_ci      if (zink_kopper_has_srgb(cdt))
1184bf215546Sopenharmony_ci         res->obj->vkflags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1185bf215546Sopenharmony_ci      if (cdt->swapchain->scci.flags == VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR)
1186bf215546Sopenharmony_ci         res->obj->vkflags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
1187bf215546Sopenharmony_ci      res->obj->vkusage = cdt->swapchain->scci.imageUsage;
1188bf215546Sopenharmony_ci      res->base.b.bind |= PIPE_BIND_DISPLAY_TARGET;
1189bf215546Sopenharmony_ci      res->optimal_tiling = true;
1190bf215546Sopenharmony_ci      res->swapchain = true;
1191bf215546Sopenharmony_ci   }
1192bf215546Sopenharmony_ci   if (!res->obj->host_visible)
1193bf215546Sopenharmony_ci      res->base.b.flags |= PIPE_RESOURCE_FLAG_DONT_MAP_DIRECTLY;
1194bf215546Sopenharmony_ci   if (res->obj->is_buffer) {
1195bf215546Sopenharmony_ci      res->base.buffer_id_unique = util_idalloc_mt_alloc(&screen->buffer_ids);
1196bf215546Sopenharmony_ci      _mesa_hash_table_init(&res->bufferview_cache, NULL, NULL, equals_bvci);
1197bf215546Sopenharmony_ci      simple_mtx_init(&res->bufferview_mtx, mtx_plain);
1198bf215546Sopenharmony_ci   } else {
1199bf215546Sopenharmony_ci      _mesa_hash_table_init(&res->surface_cache, NULL, NULL, equals_ivci);
1200bf215546Sopenharmony_ci      simple_mtx_init(&res->surface_mtx, mtx_plain);
1201bf215546Sopenharmony_ci   }
1202bf215546Sopenharmony_ci   if (res->obj->exportable)
1203bf215546Sopenharmony_ci      res->base.b.bind |= ZINK_BIND_DMABUF;
1204bf215546Sopenharmony_ci   return &res->base.b;
1205bf215546Sopenharmony_ci}
1206bf215546Sopenharmony_ci
1207bf215546Sopenharmony_cistatic struct pipe_resource *
1208bf215546Sopenharmony_cizink_resource_create(struct pipe_screen *pscreen,
1209bf215546Sopenharmony_ci                     const struct pipe_resource *templ)
1210bf215546Sopenharmony_ci{
1211bf215546Sopenharmony_ci   return resource_create(pscreen, templ, NULL, 0, NULL, 0, NULL);
1212bf215546Sopenharmony_ci}
1213bf215546Sopenharmony_ci
1214bf215546Sopenharmony_cistatic struct pipe_resource *
1215bf215546Sopenharmony_cizink_resource_create_with_modifiers(struct pipe_screen *pscreen, const struct pipe_resource *templ,
1216bf215546Sopenharmony_ci                                    const uint64_t *modifiers, int modifiers_count)
1217bf215546Sopenharmony_ci{
1218bf215546Sopenharmony_ci   return resource_create(pscreen, templ, NULL, 0, modifiers, modifiers_count, NULL);
1219bf215546Sopenharmony_ci}
1220bf215546Sopenharmony_ci
1221bf215546Sopenharmony_cistatic struct pipe_resource *
1222bf215546Sopenharmony_cizink_resource_create_drawable(struct pipe_screen *pscreen,
1223bf215546Sopenharmony_ci                              const struct pipe_resource *templ,
1224bf215546Sopenharmony_ci                              const void *loader_private)
1225bf215546Sopenharmony_ci{
1226bf215546Sopenharmony_ci   return resource_create(pscreen, templ, NULL, 0, NULL, 0, loader_private);
1227bf215546Sopenharmony_ci}
1228bf215546Sopenharmony_ci
1229bf215546Sopenharmony_cistatic bool
1230bf215546Sopenharmony_ciadd_resource_bind(struct zink_context *ctx, struct zink_resource *res, unsigned bind)
1231bf215546Sopenharmony_ci{
1232bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(ctx->base.screen);
1233bf215546Sopenharmony_ci   assert((res->base.b.bind & bind) == 0);
1234bf215546Sopenharmony_ci   zink_resource_image_barrier(ctx, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0);
1235bf215546Sopenharmony_ci   res->base.b.bind |= bind;
1236bf215546Sopenharmony_ci   struct zink_resource_object *old_obj = res->obj;
1237bf215546Sopenharmony_ci   if (bind & ZINK_BIND_DMABUF && !res->modifiers_count && screen->info.have_EXT_image_drm_format_modifier) {
1238bf215546Sopenharmony_ci      res->modifiers_count = screen->modifier_props[res->base.b.format].drmFormatModifierCount;
1239bf215546Sopenharmony_ci      res->modifiers = malloc(res->modifiers_count * sizeof(uint64_t));
1240bf215546Sopenharmony_ci      for (unsigned i = 0; i < screen->modifier_props[res->base.b.format].drmFormatModifierCount; i++)
1241bf215546Sopenharmony_ci         res->modifiers[i] = screen->modifier_props[res->base.b.format].pDrmFormatModifierProperties[i].drmFormatModifier;
1242bf215546Sopenharmony_ci   }
1243bf215546Sopenharmony_ci   struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, &res->optimal_tiling, res->modifiers, res->modifiers_count, NULL);
1244bf215546Sopenharmony_ci   if (!new_obj) {
1245bf215546Sopenharmony_ci      debug_printf("new backing resource alloc failed!");
1246bf215546Sopenharmony_ci      res->base.b.bind &= ~bind;
1247bf215546Sopenharmony_ci      return false;
1248bf215546Sopenharmony_ci   }
1249bf215546Sopenharmony_ci   struct zink_resource staging = *res;
1250bf215546Sopenharmony_ci   staging.obj = old_obj;
1251bf215546Sopenharmony_ci   staging.all_binds = 0;
1252bf215546Sopenharmony_ci   res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
1253bf215546Sopenharmony_ci   res->obj->access = 0;
1254bf215546Sopenharmony_ci   res->obj->access_stage = 0;
1255bf215546Sopenharmony_ci   bool needs_unref = true;
1256bf215546Sopenharmony_ci   if (zink_resource_has_usage(res)) {
1257bf215546Sopenharmony_ci      zink_batch_reference_resource_move(&ctx->batch, res);
1258bf215546Sopenharmony_ci      needs_unref = false;
1259bf215546Sopenharmony_ci   }
1260bf215546Sopenharmony_ci   res->obj = new_obj;
1261bf215546Sopenharmony_ci   zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj);
1262bf215546Sopenharmony_ci   for (unsigned i = 0; i <= res->base.b.last_level; i++) {
1263bf215546Sopenharmony_ci      struct pipe_box box = {0, 0, 0,
1264bf215546Sopenharmony_ci                             u_minify(res->base.b.width0, i),
1265bf215546Sopenharmony_ci                             u_minify(res->base.b.height0, i), res->base.b.array_size};
1266bf215546Sopenharmony_ci      box.depth = util_num_layers(&res->base.b, i);
1267bf215546Sopenharmony_ci      ctx->base.resource_copy_region(&ctx->base, &res->base.b, i, 0, 0, 0, &staging.base.b, i, &box);
1268bf215546Sopenharmony_ci   }
1269bf215546Sopenharmony_ci   if (needs_unref)
1270bf215546Sopenharmony_ci      zink_resource_object_reference(screen, &old_obj, NULL);
1271bf215546Sopenharmony_ci   return true;
1272bf215546Sopenharmony_ci}
1273bf215546Sopenharmony_ci
1274bf215546Sopenharmony_cistatic bool
1275bf215546Sopenharmony_cizink_resource_get_param(struct pipe_screen *pscreen, struct pipe_context *pctx,
1276bf215546Sopenharmony_ci                        struct pipe_resource *pres,
1277bf215546Sopenharmony_ci                        unsigned plane,
1278bf215546Sopenharmony_ci                        unsigned layer,
1279bf215546Sopenharmony_ci                        unsigned level,
1280bf215546Sopenharmony_ci                        enum pipe_resource_param param,
1281bf215546Sopenharmony_ci                        unsigned handle_usage,
1282bf215546Sopenharmony_ci                        uint64_t *value)
1283bf215546Sopenharmony_ci{
1284bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pscreen);
1285bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(pres);
1286bf215546Sopenharmony_ci   struct zink_resource_object *obj = res->obj;
1287bf215546Sopenharmony_ci   struct winsys_handle whandle;
1288bf215546Sopenharmony_ci   VkImageAspectFlags aspect;
1289bf215546Sopenharmony_ci   if (obj->modifier_aspect) {
1290bf215546Sopenharmony_ci      switch (plane) {
1291bf215546Sopenharmony_ci      case 0:
1292bf215546Sopenharmony_ci         aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
1293bf215546Sopenharmony_ci         break;
1294bf215546Sopenharmony_ci      case 1:
1295bf215546Sopenharmony_ci         aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT;
1296bf215546Sopenharmony_ci         break;
1297bf215546Sopenharmony_ci      case 2:
1298bf215546Sopenharmony_ci         aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT;
1299bf215546Sopenharmony_ci         break;
1300bf215546Sopenharmony_ci      case 3:
1301bf215546Sopenharmony_ci         aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT;
1302bf215546Sopenharmony_ci         break;
1303bf215546Sopenharmony_ci      default:
1304bf215546Sopenharmony_ci         unreachable("how many planes you got in this thing?");
1305bf215546Sopenharmony_ci      }
1306bf215546Sopenharmony_ci   } else if (res->obj->sampler_conversion) {
1307bf215546Sopenharmony_ci      aspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
1308bf215546Sopenharmony_ci   } else {
1309bf215546Sopenharmony_ci      aspect = res->aspect;
1310bf215546Sopenharmony_ci   }
1311bf215546Sopenharmony_ci   switch (param) {
1312bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_NPLANES:
1313bf215546Sopenharmony_ci      if (screen->info.have_EXT_image_drm_format_modifier)
1314bf215546Sopenharmony_ci         *value = util_format_get_num_planes(res->drm_format);
1315bf215546Sopenharmony_ci      else
1316bf215546Sopenharmony_ci         *value = 1;
1317bf215546Sopenharmony_ci      break;
1318bf215546Sopenharmony_ci
1319bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_STRIDE: {
1320bf215546Sopenharmony_ci      VkImageSubresource sub_res = {0};
1321bf215546Sopenharmony_ci      VkSubresourceLayout sub_res_layout = {0};
1322bf215546Sopenharmony_ci
1323bf215546Sopenharmony_ci      sub_res.aspectMask = aspect;
1324bf215546Sopenharmony_ci
1325bf215546Sopenharmony_ci      VKSCR(GetImageSubresourceLayout)(screen->dev, obj->image, &sub_res, &sub_res_layout);
1326bf215546Sopenharmony_ci
1327bf215546Sopenharmony_ci      *value = sub_res_layout.rowPitch;
1328bf215546Sopenharmony_ci      break;
1329bf215546Sopenharmony_ci   }
1330bf215546Sopenharmony_ci
1331bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_OFFSET: {
1332bf215546Sopenharmony_ci         VkImageSubresource isr = {
1333bf215546Sopenharmony_ci            aspect,
1334bf215546Sopenharmony_ci            level,
1335bf215546Sopenharmony_ci            layer
1336bf215546Sopenharmony_ci         };
1337bf215546Sopenharmony_ci         VkSubresourceLayout srl;
1338bf215546Sopenharmony_ci         VKSCR(GetImageSubresourceLayout)(screen->dev, obj->image, &isr, &srl);
1339bf215546Sopenharmony_ci         *value = srl.offset;
1340bf215546Sopenharmony_ci         break;
1341bf215546Sopenharmony_ci   }
1342bf215546Sopenharmony_ci
1343bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_MODIFIER: {
1344bf215546Sopenharmony_ci      *value = obj->modifier;
1345bf215546Sopenharmony_ci      break;
1346bf215546Sopenharmony_ci   }
1347bf215546Sopenharmony_ci
1348bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_LAYER_STRIDE: {
1349bf215546Sopenharmony_ci         VkImageSubresource isr = {
1350bf215546Sopenharmony_ci            aspect,
1351bf215546Sopenharmony_ci            level,
1352bf215546Sopenharmony_ci            layer
1353bf215546Sopenharmony_ci         };
1354bf215546Sopenharmony_ci         VkSubresourceLayout srl;
1355bf215546Sopenharmony_ci         VKSCR(GetImageSubresourceLayout)(screen->dev, obj->image, &isr, &srl);
1356bf215546Sopenharmony_ci         if (res->base.b.target == PIPE_TEXTURE_3D)
1357bf215546Sopenharmony_ci            *value = srl.depthPitch;
1358bf215546Sopenharmony_ci         else
1359bf215546Sopenharmony_ci            *value = srl.arrayPitch;
1360bf215546Sopenharmony_ci         break;
1361bf215546Sopenharmony_ci   }
1362bf215546Sopenharmony_ci
1363bf215546Sopenharmony_ci      return false;
1364bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS:
1365bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED:
1366bf215546Sopenharmony_ci   case PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD: {
1367bf215546Sopenharmony_ci#ifdef ZINK_USE_DMABUF
1368bf215546Sopenharmony_ci      memset(&whandle, 0, sizeof(whandle));
1369bf215546Sopenharmony_ci      if (param == PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED)
1370bf215546Sopenharmony_ci         whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1371bf215546Sopenharmony_ci      if (param == PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS)
1372bf215546Sopenharmony_ci         whandle.type = WINSYS_HANDLE_TYPE_KMS;
1373bf215546Sopenharmony_ci      else if (param == PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD)
1374bf215546Sopenharmony_ci         whandle.type = WINSYS_HANDLE_TYPE_FD;
1375bf215546Sopenharmony_ci
1376bf215546Sopenharmony_ci      if (!pscreen->resource_get_handle(pscreen, pctx, pres, &whandle, handle_usage))
1377bf215546Sopenharmony_ci         return false;
1378bf215546Sopenharmony_ci
1379bf215546Sopenharmony_ci#ifdef _WIN32
1380bf215546Sopenharmony_ci      *value = (uintptr_t)whandle.handle;
1381bf215546Sopenharmony_ci#else
1382bf215546Sopenharmony_ci      *value = whandle.handle;
1383bf215546Sopenharmony_ci#endif
1384bf215546Sopenharmony_ci      break;
1385bf215546Sopenharmony_ci#else
1386bf215546Sopenharmony_ci      (void)whandle;
1387bf215546Sopenharmony_ci      return false;
1388bf215546Sopenharmony_ci#endif
1389bf215546Sopenharmony_ci   }
1390bf215546Sopenharmony_ci   }
1391bf215546Sopenharmony_ci   return true;
1392bf215546Sopenharmony_ci}
1393bf215546Sopenharmony_ci
1394bf215546Sopenharmony_cistatic bool
1395bf215546Sopenharmony_cizink_resource_get_handle(struct pipe_screen *pscreen,
1396bf215546Sopenharmony_ci                         struct pipe_context *context,
1397bf215546Sopenharmony_ci                         struct pipe_resource *tex,
1398bf215546Sopenharmony_ci                         struct winsys_handle *whandle,
1399bf215546Sopenharmony_ci                         unsigned usage)
1400bf215546Sopenharmony_ci{
1401bf215546Sopenharmony_ci   if (whandle->type == WINSYS_HANDLE_TYPE_FD || whandle->type == WINSYS_HANDLE_TYPE_KMS) {
1402bf215546Sopenharmony_ci#ifdef ZINK_USE_DMABUF
1403bf215546Sopenharmony_ci      struct zink_resource *res = zink_resource(tex);
1404bf215546Sopenharmony_ci      struct zink_screen *screen = zink_screen(pscreen);
1405bf215546Sopenharmony_ci      struct zink_resource_object *obj = res->obj;
1406bf215546Sopenharmony_ci
1407bf215546Sopenharmony_ci#if !defined(_WIN32)
1408bf215546Sopenharmony_ci      if (whandle->type == WINSYS_HANDLE_TYPE_KMS && screen->drm_fd == -1) {
1409bf215546Sopenharmony_ci         whandle->handle = -1;
1410bf215546Sopenharmony_ci      } else {
1411bf215546Sopenharmony_ci         if (!res->obj->exportable) {
1412bf215546Sopenharmony_ci            assert(!res->all_binds); //TODO handle if problematic
1413bf215546Sopenharmony_ci            assert(!zink_resource_usage_is_unflushed(res));
1414bf215546Sopenharmony_ci            unsigned bind = ZINK_BIND_DMABUF;
1415bf215546Sopenharmony_ci            if (!(res->base.b.bind & PIPE_BIND_SHARED))
1416bf215546Sopenharmony_ci               bind |= PIPE_BIND_SHARED;
1417bf215546Sopenharmony_ci            if (!add_resource_bind(screen->copy_context, res, bind))
1418bf215546Sopenharmony_ci               return false;
1419bf215546Sopenharmony_ci            p_atomic_inc(&screen->image_rebind_counter);
1420bf215546Sopenharmony_ci            screen->copy_context->base.flush(&screen->copy_context->base, NULL, 0);
1421bf215546Sopenharmony_ci            obj = res->obj;
1422bf215546Sopenharmony_ci         }
1423bf215546Sopenharmony_ci
1424bf215546Sopenharmony_ci         VkMemoryGetFdInfoKHR fd_info = {0};
1425bf215546Sopenharmony_ci         int fd;
1426bf215546Sopenharmony_ci         fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
1427bf215546Sopenharmony_ci         fd_info.memory = zink_bo_get_mem(obj->bo);
1428bf215546Sopenharmony_ci         if (whandle->type == WINSYS_HANDLE_TYPE_FD)
1429bf215546Sopenharmony_ci            fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1430bf215546Sopenharmony_ci         else
1431bf215546Sopenharmony_ci            fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
1432bf215546Sopenharmony_ci         VkResult result = VKSCR(GetMemoryFdKHR)(screen->dev, &fd_info, &fd);
1433bf215546Sopenharmony_ci         if (result != VK_SUCCESS) {
1434bf215546Sopenharmony_ci            mesa_loge("ZINK: vkGetMemoryFdKHR failed");
1435bf215546Sopenharmony_ci            return false;
1436bf215546Sopenharmony_ci         }
1437bf215546Sopenharmony_ci         if (whandle->type == WINSYS_HANDLE_TYPE_KMS) {
1438bf215546Sopenharmony_ci            uint32_t h;
1439bf215546Sopenharmony_ci            bool ret = zink_bo_get_kms_handle(screen, obj->bo, fd, &h);
1440bf215546Sopenharmony_ci            close(fd);
1441bf215546Sopenharmony_ci            if (!ret)
1442bf215546Sopenharmony_ci               return false;
1443bf215546Sopenharmony_ci            fd = h;
1444bf215546Sopenharmony_ci         }
1445bf215546Sopenharmony_ci
1446bf215546Sopenharmony_ci         whandle->handle = fd;
1447bf215546Sopenharmony_ci      }
1448bf215546Sopenharmony_ci#else
1449bf215546Sopenharmony_ci      VkMemoryGetWin32HandleInfoKHR handle_info = {0};
1450bf215546Sopenharmony_ci      HANDLE handle;
1451bf215546Sopenharmony_ci      handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
1452bf215546Sopenharmony_ci      //TODO: remove for wsi
1453bf215546Sopenharmony_ci      handle_info.memory = zink_bo_get_mem(obj->bo);
1454bf215546Sopenharmony_ci      handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
1455bf215546Sopenharmony_ci      VkResult result = VKSCR(GetMemoryWin32HandleKHR)(screen->dev, &handle_info, &handle);
1456bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
1457bf215546Sopenharmony_ci         return false;
1458bf215546Sopenharmony_ci      whandle->handle = handle;
1459bf215546Sopenharmony_ci#endif
1460bf215546Sopenharmony_ci      uint64_t value;
1461bf215546Sopenharmony_ci      zink_resource_get_param(pscreen, context, tex, 0, 0, 0, PIPE_RESOURCE_PARAM_MODIFIER, 0, &value);
1462bf215546Sopenharmony_ci      whandle->modifier = value;
1463bf215546Sopenharmony_ci      zink_resource_get_param(pscreen, context, tex, 0, 0, 0, PIPE_RESOURCE_PARAM_OFFSET, 0, &value);
1464bf215546Sopenharmony_ci      whandle->offset = value;
1465bf215546Sopenharmony_ci      zink_resource_get_param(pscreen, context, tex, 0, 0, 0, PIPE_RESOURCE_PARAM_STRIDE, 0, &value);
1466bf215546Sopenharmony_ci      whandle->stride = value;
1467bf215546Sopenharmony_ci#else
1468bf215546Sopenharmony_ci      return false;
1469bf215546Sopenharmony_ci#endif
1470bf215546Sopenharmony_ci   }
1471bf215546Sopenharmony_ci   return true;
1472bf215546Sopenharmony_ci}
1473bf215546Sopenharmony_ci
1474bf215546Sopenharmony_cistatic struct pipe_resource *
1475bf215546Sopenharmony_cizink_resource_from_handle(struct pipe_screen *pscreen,
1476bf215546Sopenharmony_ci                 const struct pipe_resource *templ,
1477bf215546Sopenharmony_ci                 struct winsys_handle *whandle,
1478bf215546Sopenharmony_ci                 unsigned usage)
1479bf215546Sopenharmony_ci{
1480bf215546Sopenharmony_ci#ifdef ZINK_USE_DMABUF
1481bf215546Sopenharmony_ci   if (whandle->modifier != DRM_FORMAT_MOD_INVALID &&
1482bf215546Sopenharmony_ci       !zink_screen(pscreen)->info.have_EXT_image_drm_format_modifier)
1483bf215546Sopenharmony_ci      return NULL;
1484bf215546Sopenharmony_ci
1485bf215546Sopenharmony_ci   struct pipe_resource templ2 = *templ;
1486bf215546Sopenharmony_ci   if (templ->format == PIPE_FORMAT_NONE)
1487bf215546Sopenharmony_ci      templ2.format = whandle->format;
1488bf215546Sopenharmony_ci
1489bf215546Sopenharmony_ci   uint64_t modifier = DRM_FORMAT_MOD_INVALID;
1490bf215546Sopenharmony_ci   int modifier_count = 0;
1491bf215546Sopenharmony_ci   if (whandle->modifier != DRM_FORMAT_MOD_INVALID) {
1492bf215546Sopenharmony_ci      modifier = whandle->modifier;
1493bf215546Sopenharmony_ci      modifier_count = 1;
1494bf215546Sopenharmony_ci   }
1495bf215546Sopenharmony_ci   struct pipe_resource *pres = resource_create(pscreen, &templ2, whandle, usage, &modifier, modifier_count, NULL);
1496bf215546Sopenharmony_ci   if (pres) {
1497bf215546Sopenharmony_ci      struct zink_resource *res = zink_resource(pres);
1498bf215546Sopenharmony_ci      res->drm_format = whandle->format;
1499bf215546Sopenharmony_ci      if (pres->target != PIPE_BUFFER)
1500bf215546Sopenharmony_ci         res->valid = true;
1501bf215546Sopenharmony_ci   }
1502bf215546Sopenharmony_ci   return pres;
1503bf215546Sopenharmony_ci#else
1504bf215546Sopenharmony_ci   return NULL;
1505bf215546Sopenharmony_ci#endif
1506bf215546Sopenharmony_ci}
1507bf215546Sopenharmony_ci
1508bf215546Sopenharmony_cistruct zink_memory_object {
1509bf215546Sopenharmony_ci   struct pipe_memory_object b;
1510bf215546Sopenharmony_ci   struct winsys_handle whandle;
1511bf215546Sopenharmony_ci};
1512bf215546Sopenharmony_ci
1513bf215546Sopenharmony_cistatic struct pipe_memory_object *
1514bf215546Sopenharmony_cizink_memobj_create_from_handle(struct pipe_screen *pscreen, struct winsys_handle *whandle, bool dedicated)
1515bf215546Sopenharmony_ci{
1516bf215546Sopenharmony_ci   struct zink_memory_object *memobj = CALLOC_STRUCT(zink_memory_object);
1517bf215546Sopenharmony_ci   if (!memobj)
1518bf215546Sopenharmony_ci      return NULL;
1519bf215546Sopenharmony_ci   memcpy(&memobj->whandle, whandle, sizeof(struct winsys_handle));
1520bf215546Sopenharmony_ci   memobj->whandle.type = ZINK_EXTERNAL_MEMORY_HANDLE;
1521bf215546Sopenharmony_ci
1522bf215546Sopenharmony_ci#ifdef ZINK_USE_DMABUF
1523bf215546Sopenharmony_ci
1524bf215546Sopenharmony_ci#if !defined(_WIN32)
1525bf215546Sopenharmony_ci   memobj->whandle.handle = os_dupfd_cloexec(whandle->handle);
1526bf215546Sopenharmony_ci#else
1527bf215546Sopenharmony_ci   HANDLE source_target = GetCurrentProcess();
1528bf215546Sopenharmony_ci   HANDLE out_handle;
1529bf215546Sopenharmony_ci
1530bf215546Sopenharmony_ci   DuplicateHandle(source_target, whandle->handle, source_target, &out_handle, 0, false, DUPLICATE_SAME_ACCESS);
1531bf215546Sopenharmony_ci   memobj->whandle.handle = out_handle;
1532bf215546Sopenharmony_ci
1533bf215546Sopenharmony_ci#endif /* _WIN32 */
1534bf215546Sopenharmony_ci#endif /* ZINK_USE_DMABUF */
1535bf215546Sopenharmony_ci
1536bf215546Sopenharmony_ci   return (struct pipe_memory_object *)memobj;
1537bf215546Sopenharmony_ci}
1538bf215546Sopenharmony_ci
1539bf215546Sopenharmony_cistatic void
1540bf215546Sopenharmony_cizink_memobj_destroy(struct pipe_screen *pscreen, struct pipe_memory_object *pmemobj)
1541bf215546Sopenharmony_ci{
1542bf215546Sopenharmony_ci#ifdef ZINK_USE_DMABUF
1543bf215546Sopenharmony_ci   struct zink_memory_object *memobj = (struct zink_memory_object *)pmemobj;
1544bf215546Sopenharmony_ci
1545bf215546Sopenharmony_ci#if !defined(_WIN32)
1546bf215546Sopenharmony_ci   close(memobj->whandle.handle);
1547bf215546Sopenharmony_ci#else
1548bf215546Sopenharmony_ci   CloseHandle(memobj->whandle.handle);
1549bf215546Sopenharmony_ci#endif /* _WIN32 */
1550bf215546Sopenharmony_ci#endif /* ZINK_USE_DMABUF */
1551bf215546Sopenharmony_ci
1552bf215546Sopenharmony_ci   FREE(pmemobj);
1553bf215546Sopenharmony_ci}
1554bf215546Sopenharmony_ci
1555bf215546Sopenharmony_cistatic struct pipe_resource *
1556bf215546Sopenharmony_cizink_resource_from_memobj(struct pipe_screen *pscreen,
1557bf215546Sopenharmony_ci                          const struct pipe_resource *templ,
1558bf215546Sopenharmony_ci                          struct pipe_memory_object *pmemobj,
1559bf215546Sopenharmony_ci                          uint64_t offset)
1560bf215546Sopenharmony_ci{
1561bf215546Sopenharmony_ci   struct zink_memory_object *memobj = (struct zink_memory_object *)pmemobj;
1562bf215546Sopenharmony_ci
1563bf215546Sopenharmony_ci   struct pipe_resource *pres = resource_create(pscreen, templ, &memobj->whandle, 0, NULL, 0, NULL);
1564bf215546Sopenharmony_ci   if (pres && pres->target != PIPE_BUFFER)
1565bf215546Sopenharmony_ci      zink_resource(pres)->valid = true;
1566bf215546Sopenharmony_ci   return pres;
1567bf215546Sopenharmony_ci}
1568bf215546Sopenharmony_ci
1569bf215546Sopenharmony_cistatic bool
1570bf215546Sopenharmony_ciinvalidate_buffer(struct zink_context *ctx, struct zink_resource *res)
1571bf215546Sopenharmony_ci{
1572bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(ctx->base.screen);
1573bf215546Sopenharmony_ci
1574bf215546Sopenharmony_ci   assert(res->base.b.target == PIPE_BUFFER);
1575bf215546Sopenharmony_ci
1576bf215546Sopenharmony_ci   if (res->base.b.flags & PIPE_RESOURCE_FLAG_SPARSE)
1577bf215546Sopenharmony_ci      return false;
1578bf215546Sopenharmony_ci
1579bf215546Sopenharmony_ci   if (res->valid_buffer_range.start > res->valid_buffer_range.end)
1580bf215546Sopenharmony_ci      return false;
1581bf215546Sopenharmony_ci
1582bf215546Sopenharmony_ci   if (res->so_valid)
1583bf215546Sopenharmony_ci      ctx->dirty_so_targets = true;
1584bf215546Sopenharmony_ci   /* force counter buffer reset */
1585bf215546Sopenharmony_ci   res->so_valid = false;
1586bf215546Sopenharmony_ci
1587bf215546Sopenharmony_ci   util_range_set_empty(&res->valid_buffer_range);
1588bf215546Sopenharmony_ci   if (!zink_resource_has_usage(res))
1589bf215546Sopenharmony_ci      return false;
1590bf215546Sopenharmony_ci
1591bf215546Sopenharmony_ci   struct zink_resource_object *old_obj = res->obj;
1592bf215546Sopenharmony_ci   struct zink_resource_object *new_obj = resource_object_create(screen, &res->base.b, NULL, NULL, NULL, 0, NULL);
1593bf215546Sopenharmony_ci   if (!new_obj) {
1594bf215546Sopenharmony_ci      debug_printf("new backing resource alloc failed!");
1595bf215546Sopenharmony_ci      return false;
1596bf215546Sopenharmony_ci   }
1597bf215546Sopenharmony_ci   /* this ref must be transferred before rebind or else BOOM */
1598bf215546Sopenharmony_ci   zink_batch_reference_resource_move(&ctx->batch, res);
1599bf215546Sopenharmony_ci   res->obj = new_obj;
1600bf215546Sopenharmony_ci   zink_resource_rebind(ctx, res);
1601bf215546Sopenharmony_ci   zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj);
1602bf215546Sopenharmony_ci   return true;
1603bf215546Sopenharmony_ci}
1604bf215546Sopenharmony_ci
1605bf215546Sopenharmony_ci
1606bf215546Sopenharmony_cistatic void
1607bf215546Sopenharmony_cizink_resource_invalidate(struct pipe_context *pctx, struct pipe_resource *pres)
1608bf215546Sopenharmony_ci{
1609bf215546Sopenharmony_ci   if (pres->target == PIPE_BUFFER)
1610bf215546Sopenharmony_ci      invalidate_buffer(zink_context(pctx), zink_resource(pres));
1611bf215546Sopenharmony_ci   else {
1612bf215546Sopenharmony_ci      struct zink_resource *res = zink_resource(pres);
1613bf215546Sopenharmony_ci      if (res->valid && res->fb_binds)
1614bf215546Sopenharmony_ci         zink_context(pctx)->rp_loadop_changed = true;
1615bf215546Sopenharmony_ci      res->valid = false;
1616bf215546Sopenharmony_ci   }
1617bf215546Sopenharmony_ci}
1618bf215546Sopenharmony_ci
1619bf215546Sopenharmony_cistatic void
1620bf215546Sopenharmony_cizink_transfer_copy_bufimage(struct zink_context *ctx,
1621bf215546Sopenharmony_ci                            struct zink_resource *dst,
1622bf215546Sopenharmony_ci                            struct zink_resource *src,
1623bf215546Sopenharmony_ci                            struct zink_transfer *trans)
1624bf215546Sopenharmony_ci{
1625bf215546Sopenharmony_ci   assert((trans->base.b.usage & (PIPE_MAP_DEPTH_ONLY | PIPE_MAP_STENCIL_ONLY)) !=
1626bf215546Sopenharmony_ci          (PIPE_MAP_DEPTH_ONLY | PIPE_MAP_STENCIL_ONLY));
1627bf215546Sopenharmony_ci
1628bf215546Sopenharmony_ci   bool buf2img = src->base.b.target == PIPE_BUFFER;
1629bf215546Sopenharmony_ci
1630bf215546Sopenharmony_ci   struct pipe_box box = trans->base.b.box;
1631bf215546Sopenharmony_ci   int x = box.x;
1632bf215546Sopenharmony_ci   if (buf2img)
1633bf215546Sopenharmony_ci      box.x = trans->offset;
1634bf215546Sopenharmony_ci
1635bf215546Sopenharmony_ci   if (dst->obj->transfer_dst)
1636bf215546Sopenharmony_ci      zink_copy_image_buffer(ctx, dst, src, trans->base.b.level, buf2img ? x : 0,
1637bf215546Sopenharmony_ci                              box.y, box.z, trans->base.b.level, &box, trans->base.b.usage);
1638bf215546Sopenharmony_ci   else
1639bf215546Sopenharmony_ci      util_blitter_copy_texture(ctx->blitter, &dst->base.b, trans->base.b.level,
1640bf215546Sopenharmony_ci                                x, box.y, box.z, &src->base.b,
1641bf215546Sopenharmony_ci                                0, &box);
1642bf215546Sopenharmony_ci}
1643bf215546Sopenharmony_ci
1644bf215546Sopenharmony_ciALWAYS_INLINE static void
1645bf215546Sopenharmony_cialign_offset_size(const VkDeviceSize alignment, VkDeviceSize *offset, VkDeviceSize *size, VkDeviceSize obj_size)
1646bf215546Sopenharmony_ci{
1647bf215546Sopenharmony_ci   VkDeviceSize align = *offset % alignment;
1648bf215546Sopenharmony_ci   if (alignment - 1 > *offset)
1649bf215546Sopenharmony_ci      *offset = 0;
1650bf215546Sopenharmony_ci   else
1651bf215546Sopenharmony_ci      *offset -= align, *size += align;
1652bf215546Sopenharmony_ci   align = alignment - (*size % alignment);
1653bf215546Sopenharmony_ci   if (*offset + *size + align > obj_size)
1654bf215546Sopenharmony_ci      *size = obj_size - *offset;
1655bf215546Sopenharmony_ci   else
1656bf215546Sopenharmony_ci      *size += align;
1657bf215546Sopenharmony_ci}
1658bf215546Sopenharmony_ci
1659bf215546Sopenharmony_ciVkMappedMemoryRange
1660bf215546Sopenharmony_cizink_resource_init_mem_range(struct zink_screen *screen, struct zink_resource_object *obj, VkDeviceSize offset, VkDeviceSize size)
1661bf215546Sopenharmony_ci{
1662bf215546Sopenharmony_ci   assert(obj->size);
1663bf215546Sopenharmony_ci   align_offset_size(screen->info.props.limits.nonCoherentAtomSize, &offset, &size, obj->size);
1664bf215546Sopenharmony_ci   VkMappedMemoryRange range = {
1665bf215546Sopenharmony_ci      VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1666bf215546Sopenharmony_ci      NULL,
1667bf215546Sopenharmony_ci      zink_bo_get_mem(obj->bo),
1668bf215546Sopenharmony_ci      offset,
1669bf215546Sopenharmony_ci      size
1670bf215546Sopenharmony_ci   };
1671bf215546Sopenharmony_ci   assert(range.size);
1672bf215546Sopenharmony_ci   return range;
1673bf215546Sopenharmony_ci}
1674bf215546Sopenharmony_ci
1675bf215546Sopenharmony_cistatic void *
1676bf215546Sopenharmony_cimap_resource(struct zink_screen *screen, struct zink_resource *res)
1677bf215546Sopenharmony_ci{
1678bf215546Sopenharmony_ci   assert(res->obj->host_visible);
1679bf215546Sopenharmony_ci   return zink_bo_map(screen, res->obj->bo);
1680bf215546Sopenharmony_ci}
1681bf215546Sopenharmony_ci
1682bf215546Sopenharmony_cistatic void
1683bf215546Sopenharmony_ciunmap_resource(struct zink_screen *screen, struct zink_resource *res)
1684bf215546Sopenharmony_ci{
1685bf215546Sopenharmony_ci   zink_bo_unmap(screen, res->obj->bo);
1686bf215546Sopenharmony_ci}
1687bf215546Sopenharmony_ci
1688bf215546Sopenharmony_cistatic struct zink_transfer *
1689bf215546Sopenharmony_cicreate_transfer(struct zink_context *ctx, struct pipe_resource *pres, unsigned usage, const struct pipe_box *box)
1690bf215546Sopenharmony_ci{
1691bf215546Sopenharmony_ci   struct zink_transfer *trans;
1692bf215546Sopenharmony_ci
1693bf215546Sopenharmony_ci   if (usage & PIPE_MAP_THREAD_SAFE)
1694bf215546Sopenharmony_ci      trans = calloc(1, sizeof(*trans));
1695bf215546Sopenharmony_ci   else if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC)
1696bf215546Sopenharmony_ci      trans = slab_zalloc(&ctx->transfer_pool_unsync);
1697bf215546Sopenharmony_ci   else
1698bf215546Sopenharmony_ci      trans = slab_zalloc(&ctx->transfer_pool);
1699bf215546Sopenharmony_ci   if (!trans)
1700bf215546Sopenharmony_ci      return NULL;
1701bf215546Sopenharmony_ci
1702bf215546Sopenharmony_ci   pipe_resource_reference(&trans->base.b.resource, pres);
1703bf215546Sopenharmony_ci
1704bf215546Sopenharmony_ci   trans->base.b.usage = usage;
1705bf215546Sopenharmony_ci   trans->base.b.box = *box;
1706bf215546Sopenharmony_ci   return trans;
1707bf215546Sopenharmony_ci}
1708bf215546Sopenharmony_ci
1709bf215546Sopenharmony_cistatic void
1710bf215546Sopenharmony_cidestroy_transfer(struct zink_context *ctx, struct zink_transfer *trans)
1711bf215546Sopenharmony_ci{
1712bf215546Sopenharmony_ci   if (trans->base.b.usage & PIPE_MAP_THREAD_SAFE) {
1713bf215546Sopenharmony_ci      free(trans);
1714bf215546Sopenharmony_ci   } else {
1715bf215546Sopenharmony_ci      /* Don't use pool_transfers_unsync. We are always in the driver
1716bf215546Sopenharmony_ci       * thread. Freeing an object into a different pool is allowed.
1717bf215546Sopenharmony_ci       */
1718bf215546Sopenharmony_ci      slab_free(&ctx->transfer_pool, trans);
1719bf215546Sopenharmony_ci   }
1720bf215546Sopenharmony_ci}
1721bf215546Sopenharmony_ci
1722bf215546Sopenharmony_cistatic void *
1723bf215546Sopenharmony_cizink_buffer_map(struct pipe_context *pctx,
1724bf215546Sopenharmony_ci                    struct pipe_resource *pres,
1725bf215546Sopenharmony_ci                    unsigned level,
1726bf215546Sopenharmony_ci                    unsigned usage,
1727bf215546Sopenharmony_ci                    const struct pipe_box *box,
1728bf215546Sopenharmony_ci                    struct pipe_transfer **transfer)
1729bf215546Sopenharmony_ci{
1730bf215546Sopenharmony_ci   struct zink_context *ctx = zink_context(pctx);
1731bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pctx->screen);
1732bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(pres);
1733bf215546Sopenharmony_ci   struct zink_transfer *trans = create_transfer(ctx, pres, usage, box);
1734bf215546Sopenharmony_ci   if (!trans)
1735bf215546Sopenharmony_ci      return NULL;
1736bf215546Sopenharmony_ci
1737bf215546Sopenharmony_ci   void *ptr = NULL;
1738bf215546Sopenharmony_ci
1739bf215546Sopenharmony_ci   if (res->base.is_user_ptr)
1740bf215546Sopenharmony_ci      usage |= PIPE_MAP_PERSISTENT;
1741bf215546Sopenharmony_ci
1742bf215546Sopenharmony_ci   /* See if the buffer range being mapped has never been initialized,
1743bf215546Sopenharmony_ci    * in which case it can be mapped unsynchronized. */
1744bf215546Sopenharmony_ci   if (!(usage & (PIPE_MAP_UNSYNCHRONIZED | TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED)) &&
1745bf215546Sopenharmony_ci       usage & PIPE_MAP_WRITE && !res->base.is_shared &&
1746bf215546Sopenharmony_ci       !util_ranges_intersect(&res->valid_buffer_range, box->x, box->x + box->width)) {
1747bf215546Sopenharmony_ci      usage |= PIPE_MAP_UNSYNCHRONIZED;
1748bf215546Sopenharmony_ci   }
1749bf215546Sopenharmony_ci
1750bf215546Sopenharmony_ci   /* If discarding the entire range, discard the whole resource instead. */
1751bf215546Sopenharmony_ci   if (usage & PIPE_MAP_DISCARD_RANGE && box->x == 0 && box->width == res->base.b.width0) {
1752bf215546Sopenharmony_ci      usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;
1753bf215546Sopenharmony_ci   }
1754bf215546Sopenharmony_ci
1755bf215546Sopenharmony_ci   /* If a buffer in VRAM is too large and the range is discarded, don't
1756bf215546Sopenharmony_ci    * map it directly. This makes sure that the buffer stays in VRAM.
1757bf215546Sopenharmony_ci    */
1758bf215546Sopenharmony_ci   bool force_discard_range = false;
1759bf215546Sopenharmony_ci   if (usage & (PIPE_MAP_DISCARD_WHOLE_RESOURCE | PIPE_MAP_DISCARD_RANGE) &&
1760bf215546Sopenharmony_ci       !(usage & PIPE_MAP_PERSISTENT) &&
1761bf215546Sopenharmony_ci       res->base.b.flags & PIPE_RESOURCE_FLAG_DONT_MAP_DIRECTLY) {
1762bf215546Sopenharmony_ci      usage &= ~(PIPE_MAP_DISCARD_WHOLE_RESOURCE | PIPE_MAP_UNSYNCHRONIZED);
1763bf215546Sopenharmony_ci      usage |= PIPE_MAP_DISCARD_RANGE;
1764bf215546Sopenharmony_ci      force_discard_range = true;
1765bf215546Sopenharmony_ci   }
1766bf215546Sopenharmony_ci
1767bf215546Sopenharmony_ci   if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE &&
1768bf215546Sopenharmony_ci       !(usage & (PIPE_MAP_UNSYNCHRONIZED | TC_TRANSFER_MAP_NO_INVALIDATE))) {
1769bf215546Sopenharmony_ci      assert(usage & PIPE_MAP_WRITE);
1770bf215546Sopenharmony_ci
1771bf215546Sopenharmony_ci      if (invalidate_buffer(ctx, res)) {
1772bf215546Sopenharmony_ci         /* At this point, the buffer is always idle. */
1773bf215546Sopenharmony_ci         usage |= PIPE_MAP_UNSYNCHRONIZED;
1774bf215546Sopenharmony_ci      } else {
1775bf215546Sopenharmony_ci         /* Fall back to a temporary buffer. */
1776bf215546Sopenharmony_ci         usage |= PIPE_MAP_DISCARD_RANGE;
1777bf215546Sopenharmony_ci      }
1778bf215546Sopenharmony_ci   }
1779bf215546Sopenharmony_ci
1780bf215546Sopenharmony_ci   unsigned map_offset = box->x;
1781bf215546Sopenharmony_ci   if (usage & PIPE_MAP_DISCARD_RANGE &&
1782bf215546Sopenharmony_ci        (!res->obj->host_visible ||
1783bf215546Sopenharmony_ci        !(usage & (PIPE_MAP_UNSYNCHRONIZED | PIPE_MAP_PERSISTENT)))) {
1784bf215546Sopenharmony_ci
1785bf215546Sopenharmony_ci      /* Check if mapping this buffer would cause waiting for the GPU.
1786bf215546Sopenharmony_ci       */
1787bf215546Sopenharmony_ci
1788bf215546Sopenharmony_ci      if (!res->obj->host_visible || force_discard_range ||
1789bf215546Sopenharmony_ci          !zink_resource_usage_check_completion(screen, res, ZINK_RESOURCE_ACCESS_RW)) {
1790bf215546Sopenharmony_ci         /* Do a wait-free write-only transfer using a temporary buffer. */
1791bf215546Sopenharmony_ci         unsigned offset;
1792bf215546Sopenharmony_ci
1793bf215546Sopenharmony_ci         /* If we are not called from the driver thread, we have
1794bf215546Sopenharmony_ci          * to use the uploader from u_threaded_context, which is
1795bf215546Sopenharmony_ci          * local to the calling thread.
1796bf215546Sopenharmony_ci          */
1797bf215546Sopenharmony_ci         struct u_upload_mgr *mgr;
1798bf215546Sopenharmony_ci         if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC)
1799bf215546Sopenharmony_ci            mgr = ctx->tc->base.stream_uploader;
1800bf215546Sopenharmony_ci         else
1801bf215546Sopenharmony_ci            mgr = ctx->base.stream_uploader;
1802bf215546Sopenharmony_ci         u_upload_alloc(mgr, 0, box->width,
1803bf215546Sopenharmony_ci                     screen->info.props.limits.minMemoryMapAlignment, &offset,
1804bf215546Sopenharmony_ci                     (struct pipe_resource **)&trans->staging_res, (void **)&ptr);
1805bf215546Sopenharmony_ci         res = zink_resource(trans->staging_res);
1806bf215546Sopenharmony_ci         trans->offset = offset;
1807bf215546Sopenharmony_ci         usage |= PIPE_MAP_UNSYNCHRONIZED;
1808bf215546Sopenharmony_ci         ptr = ((uint8_t *)ptr);
1809bf215546Sopenharmony_ci      } else {
1810bf215546Sopenharmony_ci         /* At this point, the buffer is always idle (we checked it above). */
1811bf215546Sopenharmony_ci         usage |= PIPE_MAP_UNSYNCHRONIZED;
1812bf215546Sopenharmony_ci      }
1813bf215546Sopenharmony_ci   } else if (usage & PIPE_MAP_DONTBLOCK) {
1814bf215546Sopenharmony_ci      /* sparse/device-local will always need to wait since it has to copy */
1815bf215546Sopenharmony_ci      if (!res->obj->host_visible)
1816bf215546Sopenharmony_ci         goto success;
1817bf215546Sopenharmony_ci      if (!zink_resource_usage_check_completion(screen, res, ZINK_RESOURCE_ACCESS_WRITE))
1818bf215546Sopenharmony_ci         goto success;
1819bf215546Sopenharmony_ci      usage |= PIPE_MAP_UNSYNCHRONIZED;
1820bf215546Sopenharmony_ci   } else if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
1821bf215546Sopenharmony_ci              (((usage & PIPE_MAP_READ) && !(usage & PIPE_MAP_PERSISTENT) && res->base.b.usage != PIPE_USAGE_STAGING) || !res->obj->host_visible)) {
1822bf215546Sopenharmony_ci      assert(!(usage & (TC_TRANSFER_MAP_THREADED_UNSYNC | PIPE_MAP_THREAD_SAFE)));
1823bf215546Sopenharmony_ci      if (!res->obj->host_visible || !(usage & PIPE_MAP_ONCE)) {
1824bf215546Sopenharmony_ci         trans->offset = box->x % screen->info.props.limits.minMemoryMapAlignment;
1825bf215546Sopenharmony_ci         trans->staging_res = pipe_buffer_create(&screen->base, PIPE_BIND_LINEAR, PIPE_USAGE_STAGING, box->width + trans->offset);
1826bf215546Sopenharmony_ci         if (!trans->staging_res)
1827bf215546Sopenharmony_ci            goto fail;
1828bf215546Sopenharmony_ci         struct zink_resource *staging_res = zink_resource(trans->staging_res);
1829bf215546Sopenharmony_ci         zink_copy_buffer(ctx, staging_res, res, trans->offset, box->x, box->width);
1830bf215546Sopenharmony_ci         res = staging_res;
1831bf215546Sopenharmony_ci         usage &= ~PIPE_MAP_UNSYNCHRONIZED;
1832bf215546Sopenharmony_ci         map_offset = trans->offset;
1833bf215546Sopenharmony_ci      }
1834bf215546Sopenharmony_ci   } else if ((usage & PIPE_MAP_UNSYNCHRONIZED) && !res->obj->host_visible) {
1835bf215546Sopenharmony_ci      trans->offset = box->x % screen->info.props.limits.minMemoryMapAlignment;
1836bf215546Sopenharmony_ci      trans->staging_res = pipe_buffer_create(&screen->base, PIPE_BIND_LINEAR, PIPE_USAGE_STAGING, box->width + trans->offset);
1837bf215546Sopenharmony_ci      if (!trans->staging_res)
1838bf215546Sopenharmony_ci         goto fail;
1839bf215546Sopenharmony_ci      struct zink_resource *staging_res = zink_resource(trans->staging_res);
1840bf215546Sopenharmony_ci      res = staging_res;
1841bf215546Sopenharmony_ci      map_offset = trans->offset;
1842bf215546Sopenharmony_ci   }
1843bf215546Sopenharmony_ci
1844bf215546Sopenharmony_ci   if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
1845bf215546Sopenharmony_ci      if (usage & PIPE_MAP_WRITE)
1846bf215546Sopenharmony_ci         zink_resource_usage_wait(ctx, res, ZINK_RESOURCE_ACCESS_RW);
1847bf215546Sopenharmony_ci      else
1848bf215546Sopenharmony_ci         zink_resource_usage_wait(ctx, res, ZINK_RESOURCE_ACCESS_WRITE);
1849bf215546Sopenharmony_ci      res->obj->access = 0;
1850bf215546Sopenharmony_ci      res->obj->access_stage = 0;
1851bf215546Sopenharmony_ci   }
1852bf215546Sopenharmony_ci
1853bf215546Sopenharmony_ci   if (!ptr) {
1854bf215546Sopenharmony_ci      /* if writing to a streamout buffer, ensure synchronization next time it's used */
1855bf215546Sopenharmony_ci      if (usage & PIPE_MAP_WRITE && res->so_valid) {
1856bf215546Sopenharmony_ci         ctx->dirty_so_targets = true;
1857bf215546Sopenharmony_ci         /* force counter buffer reset */
1858bf215546Sopenharmony_ci         res->so_valid = false;
1859bf215546Sopenharmony_ci      }
1860bf215546Sopenharmony_ci      ptr = map_resource(screen, res);
1861bf215546Sopenharmony_ci      if (!ptr)
1862bf215546Sopenharmony_ci         goto fail;
1863bf215546Sopenharmony_ci      ptr = ((uint8_t *)ptr) + map_offset;
1864bf215546Sopenharmony_ci   }
1865bf215546Sopenharmony_ci
1866bf215546Sopenharmony_ci   if (!res->obj->coherent
1867bf215546Sopenharmony_ci#if defined(MVK_VERSION)
1868bf215546Sopenharmony_ci      // Work around for MoltenVk limitation specifically on coherent memory
1869bf215546Sopenharmony_ci      // MoltenVk returns blank memory ranges when there should be data present
1870bf215546Sopenharmony_ci      // This is a known limitation of MoltenVK.
1871bf215546Sopenharmony_ci      // See https://github.com/KhronosGroup/MoltenVK/blob/master/Docs/MoltenVK_Runtime_UserGuide.md#known-moltenvk-limitations
1872bf215546Sopenharmony_ci
1873bf215546Sopenharmony_ci       || screen->instance_info.have_MVK_moltenvk
1874bf215546Sopenharmony_ci#endif
1875bf215546Sopenharmony_ci      ) {
1876bf215546Sopenharmony_ci      VkDeviceSize size = box->width;
1877bf215546Sopenharmony_ci      VkDeviceSize offset = res->obj->offset + trans->offset;
1878bf215546Sopenharmony_ci      VkMappedMemoryRange range = zink_resource_init_mem_range(screen, res->obj, offset, size);
1879bf215546Sopenharmony_ci      if (VKSCR(InvalidateMappedMemoryRanges)(screen->dev, 1, &range) != VK_SUCCESS) {
1880bf215546Sopenharmony_ci         mesa_loge("ZINK: vkInvalidateMappedMemoryRanges failed");
1881bf215546Sopenharmony_ci         zink_bo_unmap(screen, res->obj->bo);
1882bf215546Sopenharmony_ci         goto fail;
1883bf215546Sopenharmony_ci      }
1884bf215546Sopenharmony_ci   }
1885bf215546Sopenharmony_ci   trans->base.b.usage = usage;
1886bf215546Sopenharmony_ci   if (usage & PIPE_MAP_WRITE)
1887bf215546Sopenharmony_ci      util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width);
1888bf215546Sopenharmony_ci   if ((usage & PIPE_MAP_PERSISTENT) && !(usage & PIPE_MAP_COHERENT))
1889bf215546Sopenharmony_ci      res->obj->persistent_maps++;
1890bf215546Sopenharmony_ci
1891bf215546Sopenharmony_cisuccess:
1892bf215546Sopenharmony_ci   *transfer = &trans->base.b;
1893bf215546Sopenharmony_ci   return ptr;
1894bf215546Sopenharmony_ci
1895bf215546Sopenharmony_cifail:
1896bf215546Sopenharmony_ci   destroy_transfer(ctx, trans);
1897bf215546Sopenharmony_ci   return NULL;
1898bf215546Sopenharmony_ci}
1899bf215546Sopenharmony_ci
1900bf215546Sopenharmony_cistatic void *
1901bf215546Sopenharmony_cizink_image_map(struct pipe_context *pctx,
1902bf215546Sopenharmony_ci                  struct pipe_resource *pres,
1903bf215546Sopenharmony_ci                  unsigned level,
1904bf215546Sopenharmony_ci                  unsigned usage,
1905bf215546Sopenharmony_ci                  const struct pipe_box *box,
1906bf215546Sopenharmony_ci                  struct pipe_transfer **transfer)
1907bf215546Sopenharmony_ci{
1908bf215546Sopenharmony_ci   struct zink_context *ctx = zink_context(pctx);
1909bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pctx->screen);
1910bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(pres);
1911bf215546Sopenharmony_ci   struct zink_transfer *trans = create_transfer(ctx, pres, usage, box);
1912bf215546Sopenharmony_ci   if (!trans)
1913bf215546Sopenharmony_ci      return NULL;
1914bf215546Sopenharmony_ci
1915bf215546Sopenharmony_ci   trans->base.b.level = level;
1916bf215546Sopenharmony_ci   if (zink_is_swapchain(res))
1917bf215546Sopenharmony_ci      /* this is probably a multi-chain which has already been acquired */
1918bf215546Sopenharmony_ci      zink_kopper_acquire(ctx, res, 0);
1919bf215546Sopenharmony_ci
1920bf215546Sopenharmony_ci   void *ptr;
1921bf215546Sopenharmony_ci   if (usage & PIPE_MAP_WRITE && !(usage & PIPE_MAP_READ))
1922bf215546Sopenharmony_ci      /* this is like a blit, so we can potentially dump some clears or maybe we have to  */
1923bf215546Sopenharmony_ci      zink_fb_clears_apply_or_discard(ctx, pres, zink_rect_from_box(box), false);
1924bf215546Sopenharmony_ci   else if (usage & PIPE_MAP_READ)
1925bf215546Sopenharmony_ci      /* if the map region intersects with any clears then we have to apply them */
1926bf215546Sopenharmony_ci      zink_fb_clears_apply_region(ctx, pres, zink_rect_from_box(box));
1927bf215546Sopenharmony_ci   if (res->optimal_tiling || !res->obj->host_visible) {
1928bf215546Sopenharmony_ci      enum pipe_format format = pres->format;
1929bf215546Sopenharmony_ci      if (usage & PIPE_MAP_DEPTH_ONLY)
1930bf215546Sopenharmony_ci         format = util_format_get_depth_only(pres->format);
1931bf215546Sopenharmony_ci      else if (usage & PIPE_MAP_STENCIL_ONLY)
1932bf215546Sopenharmony_ci         format = PIPE_FORMAT_S8_UINT;
1933bf215546Sopenharmony_ci      trans->base.b.stride = util_format_get_stride(format, box->width);
1934bf215546Sopenharmony_ci      trans->base.b.layer_stride = util_format_get_2d_size(format,
1935bf215546Sopenharmony_ci                                                         trans->base.b.stride,
1936bf215546Sopenharmony_ci                                                         box->height);
1937bf215546Sopenharmony_ci
1938bf215546Sopenharmony_ci      struct pipe_resource templ = *pres;
1939bf215546Sopenharmony_ci      templ.next = NULL;
1940bf215546Sopenharmony_ci      templ.format = format;
1941bf215546Sopenharmony_ci      templ.usage = usage & PIPE_MAP_READ ? PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;
1942bf215546Sopenharmony_ci      templ.target = PIPE_BUFFER;
1943bf215546Sopenharmony_ci      templ.bind = PIPE_BIND_LINEAR;
1944bf215546Sopenharmony_ci      templ.width0 = trans->base.b.layer_stride * box->depth;
1945bf215546Sopenharmony_ci      templ.height0 = templ.depth0 = 0;
1946bf215546Sopenharmony_ci      templ.last_level = 0;
1947bf215546Sopenharmony_ci      templ.array_size = 1;
1948bf215546Sopenharmony_ci      templ.flags = 0;
1949bf215546Sopenharmony_ci
1950bf215546Sopenharmony_ci      trans->staging_res = zink_resource_create(pctx->screen, &templ);
1951bf215546Sopenharmony_ci      if (!trans->staging_res)
1952bf215546Sopenharmony_ci         goto fail;
1953bf215546Sopenharmony_ci
1954bf215546Sopenharmony_ci      struct zink_resource *staging_res = zink_resource(trans->staging_res);
1955bf215546Sopenharmony_ci
1956bf215546Sopenharmony_ci      if (usage & PIPE_MAP_READ) {
1957bf215546Sopenharmony_ci         /* force multi-context sync */
1958bf215546Sopenharmony_ci         if (zink_resource_usage_is_unflushed_write(res))
1959bf215546Sopenharmony_ci            zink_resource_usage_wait(ctx, res, ZINK_RESOURCE_ACCESS_WRITE);
1960bf215546Sopenharmony_ci         zink_transfer_copy_bufimage(ctx, staging_res, res, trans);
1961bf215546Sopenharmony_ci         /* need to wait for rendering to finish */
1962bf215546Sopenharmony_ci         zink_fence_wait(pctx);
1963bf215546Sopenharmony_ci      }
1964bf215546Sopenharmony_ci
1965bf215546Sopenharmony_ci      ptr = map_resource(screen, staging_res);
1966bf215546Sopenharmony_ci   } else {
1967bf215546Sopenharmony_ci      assert(!res->optimal_tiling);
1968bf215546Sopenharmony_ci      ptr = map_resource(screen, res);
1969bf215546Sopenharmony_ci      if (!ptr)
1970bf215546Sopenharmony_ci         goto fail;
1971bf215546Sopenharmony_ci      if (zink_resource_has_usage(res)) {
1972bf215546Sopenharmony_ci         if (usage & PIPE_MAP_WRITE)
1973bf215546Sopenharmony_ci            zink_fence_wait(pctx);
1974bf215546Sopenharmony_ci         else
1975bf215546Sopenharmony_ci            zink_resource_usage_wait(ctx, res, ZINK_RESOURCE_ACCESS_WRITE);
1976bf215546Sopenharmony_ci      }
1977bf215546Sopenharmony_ci      VkImageSubresource isr = {
1978bf215546Sopenharmony_ci         res->modifiers ? res->obj->modifier_aspect : res->aspect,
1979bf215546Sopenharmony_ci         level,
1980bf215546Sopenharmony_ci         0
1981bf215546Sopenharmony_ci      };
1982bf215546Sopenharmony_ci      VkSubresourceLayout srl;
1983bf215546Sopenharmony_ci      VKSCR(GetImageSubresourceLayout)(screen->dev, res->obj->image, &isr, &srl);
1984bf215546Sopenharmony_ci      trans->base.b.stride = srl.rowPitch;
1985bf215546Sopenharmony_ci      if (res->base.b.target == PIPE_TEXTURE_3D)
1986bf215546Sopenharmony_ci         trans->base.b.layer_stride = srl.depthPitch;
1987bf215546Sopenharmony_ci      else
1988bf215546Sopenharmony_ci         trans->base.b.layer_stride = srl.arrayPitch;
1989bf215546Sopenharmony_ci      trans->offset = srl.offset;
1990bf215546Sopenharmony_ci      trans->depthPitch = srl.depthPitch;
1991bf215546Sopenharmony_ci      const struct util_format_description *desc = util_format_description(res->base.b.format);
1992bf215546Sopenharmony_ci      unsigned offset = srl.offset +
1993bf215546Sopenharmony_ci                        box->z * srl.depthPitch +
1994bf215546Sopenharmony_ci                        (box->y / desc->block.height) * srl.rowPitch +
1995bf215546Sopenharmony_ci                        (box->x / desc->block.width) * (desc->block.bits / 8);
1996bf215546Sopenharmony_ci      if (!res->obj->coherent) {
1997bf215546Sopenharmony_ci         VkDeviceSize size = (VkDeviceSize)box->width * box->height * desc->block.bits / 8;
1998bf215546Sopenharmony_ci         VkMappedMemoryRange range = zink_resource_init_mem_range(screen, res->obj, res->obj->offset + offset, size);
1999bf215546Sopenharmony_ci         if (VKSCR(FlushMappedMemoryRanges)(screen->dev, 1, &range) != VK_SUCCESS) {
2000bf215546Sopenharmony_ci            mesa_loge("ZINK: vkFlushMappedMemoryRanges failed");
2001bf215546Sopenharmony_ci         }
2002bf215546Sopenharmony_ci      }
2003bf215546Sopenharmony_ci      ptr = ((uint8_t *)ptr) + offset;
2004bf215546Sopenharmony_ci   }
2005bf215546Sopenharmony_ci   if (!ptr)
2006bf215546Sopenharmony_ci      goto fail;
2007bf215546Sopenharmony_ci   if (usage & PIPE_MAP_WRITE) {
2008bf215546Sopenharmony_ci      if (!res->valid && res->fb_binds)
2009bf215546Sopenharmony_ci         ctx->rp_loadop_changed = true;
2010bf215546Sopenharmony_ci      res->valid = true;
2011bf215546Sopenharmony_ci   }
2012bf215546Sopenharmony_ci
2013bf215546Sopenharmony_ci   if (sizeof(void*) == 4)
2014bf215546Sopenharmony_ci      trans->base.b.usage |= ZINK_MAP_TEMPORARY;
2015bf215546Sopenharmony_ci   if ((usage & PIPE_MAP_PERSISTENT) && !(usage & PIPE_MAP_COHERENT))
2016bf215546Sopenharmony_ci      res->obj->persistent_maps++;
2017bf215546Sopenharmony_ci
2018bf215546Sopenharmony_ci   *transfer = &trans->base.b;
2019bf215546Sopenharmony_ci   return ptr;
2020bf215546Sopenharmony_ci
2021bf215546Sopenharmony_cifail:
2022bf215546Sopenharmony_ci   destroy_transfer(ctx, trans);
2023bf215546Sopenharmony_ci   return NULL;
2024bf215546Sopenharmony_ci}
2025bf215546Sopenharmony_ci
2026bf215546Sopenharmony_cistatic void
2027bf215546Sopenharmony_cizink_transfer_flush_region(struct pipe_context *pctx,
2028bf215546Sopenharmony_ci                           struct pipe_transfer *ptrans,
2029bf215546Sopenharmony_ci                           const struct pipe_box *box)
2030bf215546Sopenharmony_ci{
2031bf215546Sopenharmony_ci   struct zink_context *ctx = zink_context(pctx);
2032bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(ptrans->resource);
2033bf215546Sopenharmony_ci   struct zink_transfer *trans = (struct zink_transfer *)ptrans;
2034bf215546Sopenharmony_ci
2035bf215546Sopenharmony_ci   if (trans->base.b.usage & PIPE_MAP_WRITE) {
2036bf215546Sopenharmony_ci      struct zink_screen *screen = zink_screen(pctx->screen);
2037bf215546Sopenharmony_ci      struct zink_resource *m = trans->staging_res ? zink_resource(trans->staging_res) :
2038bf215546Sopenharmony_ci                                                     res;
2039bf215546Sopenharmony_ci      ASSERTED VkDeviceSize size, src_offset, dst_offset = 0;
2040bf215546Sopenharmony_ci      if (m->obj->is_buffer) {
2041bf215546Sopenharmony_ci         size = box->width;
2042bf215546Sopenharmony_ci         src_offset = box->x + (trans->staging_res ? trans->offset : ptrans->box.x);
2043bf215546Sopenharmony_ci         dst_offset = box->x + ptrans->box.x;
2044bf215546Sopenharmony_ci      } else {
2045bf215546Sopenharmony_ci         size = (VkDeviceSize)box->width * box->height * util_format_get_blocksize(m->base.b.format);
2046bf215546Sopenharmony_ci         src_offset = trans->offset +
2047bf215546Sopenharmony_ci                  box->z * trans->depthPitch +
2048bf215546Sopenharmony_ci                  util_format_get_2d_size(m->base.b.format, trans->base.b.stride, box->y) +
2049bf215546Sopenharmony_ci                  util_format_get_stride(m->base.b.format, box->x);
2050bf215546Sopenharmony_ci         assert(src_offset + size <= res->obj->size);
2051bf215546Sopenharmony_ci      }
2052bf215546Sopenharmony_ci      if (!m->obj->coherent) {
2053bf215546Sopenharmony_ci         VkMappedMemoryRange range = zink_resource_init_mem_range(screen, m->obj, m->obj->offset, m->obj->size);
2054bf215546Sopenharmony_ci         if (VKSCR(FlushMappedMemoryRanges)(screen->dev, 1, &range) != VK_SUCCESS) {
2055bf215546Sopenharmony_ci            mesa_loge("ZINK: vkFlushMappedMemoryRanges failed");
2056bf215546Sopenharmony_ci         }
2057bf215546Sopenharmony_ci      }
2058bf215546Sopenharmony_ci      if (trans->staging_res) {
2059bf215546Sopenharmony_ci         struct zink_resource *staging_res = zink_resource(trans->staging_res);
2060bf215546Sopenharmony_ci
2061bf215546Sopenharmony_ci         if (ptrans->resource->target == PIPE_BUFFER)
2062bf215546Sopenharmony_ci            zink_copy_buffer(ctx, res, staging_res, dst_offset, src_offset, size);
2063bf215546Sopenharmony_ci         else
2064bf215546Sopenharmony_ci            zink_transfer_copy_bufimage(ctx, res, staging_res, trans);
2065bf215546Sopenharmony_ci      }
2066bf215546Sopenharmony_ci   }
2067bf215546Sopenharmony_ci}
2068bf215546Sopenharmony_ci
2069bf215546Sopenharmony_cistatic void
2070bf215546Sopenharmony_citransfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
2071bf215546Sopenharmony_ci{
2072bf215546Sopenharmony_ci   struct zink_context *ctx = zink_context(pctx);
2073bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(ptrans->resource);
2074bf215546Sopenharmony_ci   struct zink_transfer *trans = (struct zink_transfer *)ptrans;
2075bf215546Sopenharmony_ci
2076bf215546Sopenharmony_ci   if (!(trans->base.b.usage & (PIPE_MAP_FLUSH_EXPLICIT | PIPE_MAP_COHERENT))) {
2077bf215546Sopenharmony_ci      /* flush_region is relative to the mapped region: use only the extents */
2078bf215546Sopenharmony_ci      struct pipe_box box = ptrans->box;
2079bf215546Sopenharmony_ci      box.x = box.y = box.z = 0;
2080bf215546Sopenharmony_ci      zink_transfer_flush_region(pctx, ptrans, &box);
2081bf215546Sopenharmony_ci   }
2082bf215546Sopenharmony_ci
2083bf215546Sopenharmony_ci   if ((trans->base.b.usage & PIPE_MAP_PERSISTENT) && !(trans->base.b.usage & PIPE_MAP_COHERENT))
2084bf215546Sopenharmony_ci      res->obj->persistent_maps--;
2085bf215546Sopenharmony_ci
2086bf215546Sopenharmony_ci   if (trans->staging_res)
2087bf215546Sopenharmony_ci      pipe_resource_reference(&trans->staging_res, NULL);
2088bf215546Sopenharmony_ci   pipe_resource_reference(&trans->base.b.resource, NULL);
2089bf215546Sopenharmony_ci
2090bf215546Sopenharmony_ci   destroy_transfer(ctx, trans);
2091bf215546Sopenharmony_ci}
2092bf215546Sopenharmony_ci
2093bf215546Sopenharmony_cistatic void
2094bf215546Sopenharmony_cido_transfer_unmap(struct zink_screen *screen, struct zink_transfer *trans)
2095bf215546Sopenharmony_ci{
2096bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(trans->staging_res);
2097bf215546Sopenharmony_ci   if (!res)
2098bf215546Sopenharmony_ci      res = zink_resource(trans->base.b.resource);
2099bf215546Sopenharmony_ci   unmap_resource(screen, res);
2100bf215546Sopenharmony_ci}
2101bf215546Sopenharmony_ci
2102bf215546Sopenharmony_cistatic void
2103bf215546Sopenharmony_cizink_buffer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
2104bf215546Sopenharmony_ci{
2105bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pctx->screen);
2106bf215546Sopenharmony_ci   struct zink_transfer *trans = (struct zink_transfer *)ptrans;
2107bf215546Sopenharmony_ci   if (trans->base.b.usage & PIPE_MAP_ONCE && !trans->staging_res)
2108bf215546Sopenharmony_ci      do_transfer_unmap(screen, trans);
2109bf215546Sopenharmony_ci   transfer_unmap(pctx, ptrans);
2110bf215546Sopenharmony_ci}
2111bf215546Sopenharmony_ci
2112bf215546Sopenharmony_cistatic void
2113bf215546Sopenharmony_cizink_image_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
2114bf215546Sopenharmony_ci{
2115bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pctx->screen);
2116bf215546Sopenharmony_ci   struct zink_transfer *trans = (struct zink_transfer *)ptrans;
2117bf215546Sopenharmony_ci   if (sizeof(void*) == 4)
2118bf215546Sopenharmony_ci      do_transfer_unmap(screen, trans);
2119bf215546Sopenharmony_ci   transfer_unmap(pctx, ptrans);
2120bf215546Sopenharmony_ci}
2121bf215546Sopenharmony_ci
2122bf215546Sopenharmony_cistatic void
2123bf215546Sopenharmony_cizink_buffer_subdata(struct pipe_context *ctx, struct pipe_resource *buffer,
2124bf215546Sopenharmony_ci                    unsigned usage, unsigned offset, unsigned size, const void *data)
2125bf215546Sopenharmony_ci{
2126bf215546Sopenharmony_ci   struct pipe_transfer *transfer = NULL;
2127bf215546Sopenharmony_ci   struct pipe_box box;
2128bf215546Sopenharmony_ci   uint8_t *map = NULL;
2129bf215546Sopenharmony_ci
2130bf215546Sopenharmony_ci   usage |= PIPE_MAP_WRITE;
2131bf215546Sopenharmony_ci
2132bf215546Sopenharmony_ci   if (!(usage & PIPE_MAP_DIRECTLY))
2133bf215546Sopenharmony_ci      usage |= PIPE_MAP_DISCARD_RANGE;
2134bf215546Sopenharmony_ci
2135bf215546Sopenharmony_ci   u_box_1d(offset, size, &box);
2136bf215546Sopenharmony_ci   map = zink_buffer_map(ctx, buffer, 0, usage, &box, &transfer);
2137bf215546Sopenharmony_ci   if (!map)
2138bf215546Sopenharmony_ci      return;
2139bf215546Sopenharmony_ci
2140bf215546Sopenharmony_ci   memcpy(map, data, size);
2141bf215546Sopenharmony_ci   zink_buffer_unmap(ctx, transfer);
2142bf215546Sopenharmony_ci}
2143bf215546Sopenharmony_ci
2144bf215546Sopenharmony_cistatic struct pipe_resource *
2145bf215546Sopenharmony_cizink_resource_get_separate_stencil(struct pipe_resource *pres)
2146bf215546Sopenharmony_ci{
2147bf215546Sopenharmony_ci   /* For packed depth-stencil, we treat depth as the primary resource
2148bf215546Sopenharmony_ci    * and store S8 as the "second plane" resource.
2149bf215546Sopenharmony_ci    */
2150bf215546Sopenharmony_ci   if (pres->next && pres->next->format == PIPE_FORMAT_S8_UINT)
2151bf215546Sopenharmony_ci      return pres->next;
2152bf215546Sopenharmony_ci
2153bf215546Sopenharmony_ci   return NULL;
2154bf215546Sopenharmony_ci
2155bf215546Sopenharmony_ci}
2156bf215546Sopenharmony_ci
2157bf215546Sopenharmony_cibool
2158bf215546Sopenharmony_cizink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res)
2159bf215546Sopenharmony_ci{
2160bf215546Sopenharmony_ci   /* base resource already has the cap */
2161bf215546Sopenharmony_ci   if (res->base.b.bind & PIPE_BIND_SHADER_IMAGE)
2162bf215546Sopenharmony_ci      return true;
2163bf215546Sopenharmony_ci   if (res->obj->is_buffer) {
2164bf215546Sopenharmony_ci      unreachable("zink: all buffers should have this bit");
2165bf215546Sopenharmony_ci      return true;
2166bf215546Sopenharmony_ci   }
2167bf215546Sopenharmony_ci   assert(!res->obj->dt);
2168bf215546Sopenharmony_ci   zink_fb_clears_apply_region(ctx, &res->base.b, (struct u_rect){0, res->base.b.width0, 0, res->base.b.height0});
2169bf215546Sopenharmony_ci   bool ret = add_resource_bind(ctx, res, PIPE_BIND_SHADER_IMAGE);
2170bf215546Sopenharmony_ci   if (ret)
2171bf215546Sopenharmony_ci      zink_resource_rebind(ctx, res);
2172bf215546Sopenharmony_ci
2173bf215546Sopenharmony_ci   return ret;
2174bf215546Sopenharmony_ci}
2175bf215546Sopenharmony_ci
2176bf215546Sopenharmony_civoid
2177bf215546Sopenharmony_cizink_resource_setup_transfer_layouts(struct zink_context *ctx, struct zink_resource *src, struct zink_resource *dst)
2178bf215546Sopenharmony_ci{
2179bf215546Sopenharmony_ci   if (src == dst) {
2180bf215546Sopenharmony_ci      /* The Vulkan 1.1 specification says the following about valid usage
2181bf215546Sopenharmony_ci       * of vkCmdBlitImage:
2182bf215546Sopenharmony_ci       *
2183bf215546Sopenharmony_ci       * "srcImageLayout must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
2184bf215546Sopenharmony_ci       *  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL"
2185bf215546Sopenharmony_ci       *
2186bf215546Sopenharmony_ci       * and:
2187bf215546Sopenharmony_ci       *
2188bf215546Sopenharmony_ci       * "dstImageLayout must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
2189bf215546Sopenharmony_ci       *  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL"
2190bf215546Sopenharmony_ci       *
2191bf215546Sopenharmony_ci       * Since we cant have the same image in two states at the same time,
2192bf215546Sopenharmony_ci       * we're effectively left with VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or
2193bf215546Sopenharmony_ci       * VK_IMAGE_LAYOUT_GENERAL. And since this isn't a present-related
2194bf215546Sopenharmony_ci       * operation, VK_IMAGE_LAYOUT_GENERAL seems most appropriate.
2195bf215546Sopenharmony_ci       */
2196bf215546Sopenharmony_ci      zink_resource_image_barrier(ctx, src,
2197bf215546Sopenharmony_ci                                  VK_IMAGE_LAYOUT_GENERAL,
2198bf215546Sopenharmony_ci                                  VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
2199bf215546Sopenharmony_ci                                  VK_PIPELINE_STAGE_TRANSFER_BIT);
2200bf215546Sopenharmony_ci   } else {
2201bf215546Sopenharmony_ci      zink_resource_image_barrier(ctx, src,
2202bf215546Sopenharmony_ci                                  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2203bf215546Sopenharmony_ci                                  VK_ACCESS_TRANSFER_READ_BIT,
2204bf215546Sopenharmony_ci                                  VK_PIPELINE_STAGE_TRANSFER_BIT);
2205bf215546Sopenharmony_ci
2206bf215546Sopenharmony_ci      zink_resource_image_barrier(ctx, dst,
2207bf215546Sopenharmony_ci                                  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2208bf215546Sopenharmony_ci                                  VK_ACCESS_TRANSFER_WRITE_BIT,
2209bf215546Sopenharmony_ci                                  VK_PIPELINE_STAGE_TRANSFER_BIT);
2210bf215546Sopenharmony_ci   }
2211bf215546Sopenharmony_ci}
2212bf215546Sopenharmony_ci
2213bf215546Sopenharmony_civoid
2214bf215546Sopenharmony_cizink_get_depth_stencil_resources(struct pipe_resource *res,
2215bf215546Sopenharmony_ci                                 struct zink_resource **out_z,
2216bf215546Sopenharmony_ci                                 struct zink_resource **out_s)
2217bf215546Sopenharmony_ci{
2218bf215546Sopenharmony_ci   if (!res) {
2219bf215546Sopenharmony_ci      if (out_z) *out_z = NULL;
2220bf215546Sopenharmony_ci      if (out_s) *out_s = NULL;
2221bf215546Sopenharmony_ci      return;
2222bf215546Sopenharmony_ci   }
2223bf215546Sopenharmony_ci
2224bf215546Sopenharmony_ci   if (res->format != PIPE_FORMAT_S8_UINT) {
2225bf215546Sopenharmony_ci      if (out_z) *out_z = zink_resource(res);
2226bf215546Sopenharmony_ci      if (out_s) *out_s = zink_resource(zink_resource_get_separate_stencil(res));
2227bf215546Sopenharmony_ci   } else {
2228bf215546Sopenharmony_ci      if (out_z) *out_z = NULL;
2229bf215546Sopenharmony_ci      if (out_s) *out_s = zink_resource(res);
2230bf215546Sopenharmony_ci   }
2231bf215546Sopenharmony_ci}
2232bf215546Sopenharmony_ci
2233bf215546Sopenharmony_cistatic void
2234bf215546Sopenharmony_cizink_resource_set_separate_stencil(struct pipe_resource *pres,
2235bf215546Sopenharmony_ci                                   struct pipe_resource *stencil)
2236bf215546Sopenharmony_ci{
2237bf215546Sopenharmony_ci   assert(util_format_has_depth(util_format_description(pres->format)));
2238bf215546Sopenharmony_ci   pipe_resource_reference(&pres->next, stencil);
2239bf215546Sopenharmony_ci}
2240bf215546Sopenharmony_ci
2241bf215546Sopenharmony_cistatic enum pipe_format
2242bf215546Sopenharmony_cizink_resource_get_internal_format(struct pipe_resource *pres)
2243bf215546Sopenharmony_ci{
2244bf215546Sopenharmony_ci   struct zink_resource *res = zink_resource(pres);
2245bf215546Sopenharmony_ci   return res->internal_format;
2246bf215546Sopenharmony_ci}
2247bf215546Sopenharmony_ci
2248bf215546Sopenharmony_cistatic const struct u_transfer_vtbl transfer_vtbl = {
2249bf215546Sopenharmony_ci   .resource_create       = zink_resource_create,
2250bf215546Sopenharmony_ci   .resource_destroy      = zink_resource_destroy,
2251bf215546Sopenharmony_ci   .transfer_map          = zink_image_map,
2252bf215546Sopenharmony_ci   .transfer_unmap        = zink_image_unmap,
2253bf215546Sopenharmony_ci   .transfer_flush_region = zink_transfer_flush_region,
2254bf215546Sopenharmony_ci   .get_internal_format   = zink_resource_get_internal_format,
2255bf215546Sopenharmony_ci   .set_stencil           = zink_resource_set_separate_stencil,
2256bf215546Sopenharmony_ci   .get_stencil           = zink_resource_get_separate_stencil,
2257bf215546Sopenharmony_ci};
2258bf215546Sopenharmony_ci
2259bf215546Sopenharmony_cibool
2260bf215546Sopenharmony_cizink_screen_resource_init(struct pipe_screen *pscreen)
2261bf215546Sopenharmony_ci{
2262bf215546Sopenharmony_ci   struct zink_screen *screen = zink_screen(pscreen);
2263bf215546Sopenharmony_ci   pscreen->resource_create = zink_resource_create;
2264bf215546Sopenharmony_ci   pscreen->resource_create_with_modifiers = zink_resource_create_with_modifiers;
2265bf215546Sopenharmony_ci   pscreen->resource_create_drawable = zink_resource_create_drawable;
2266bf215546Sopenharmony_ci   pscreen->resource_destroy = zink_resource_destroy;
2267bf215546Sopenharmony_ci   pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, true, true, false, false, !screen->have_D24_UNORM_S8_UINT);
2268bf215546Sopenharmony_ci
2269bf215546Sopenharmony_ci   if (screen->info.have_KHR_external_memory_fd || screen->info.have_KHR_external_memory_win32) {
2270bf215546Sopenharmony_ci      pscreen->resource_get_handle = zink_resource_get_handle;
2271bf215546Sopenharmony_ci      pscreen->resource_from_handle = zink_resource_from_handle;
2272bf215546Sopenharmony_ci   }
2273bf215546Sopenharmony_ci   if (screen->instance_info.have_KHR_external_memory_capabilities) {
2274bf215546Sopenharmony_ci      pscreen->memobj_create_from_handle = zink_memobj_create_from_handle;
2275bf215546Sopenharmony_ci      pscreen->memobj_destroy = zink_memobj_destroy;
2276bf215546Sopenharmony_ci      pscreen->resource_from_memobj = zink_resource_from_memobj;
2277bf215546Sopenharmony_ci   }
2278bf215546Sopenharmony_ci   pscreen->resource_get_param = zink_resource_get_param;
2279bf215546Sopenharmony_ci   return true;
2280bf215546Sopenharmony_ci}
2281bf215546Sopenharmony_ci
2282bf215546Sopenharmony_civoid
2283bf215546Sopenharmony_cizink_context_resource_init(struct pipe_context *pctx)
2284bf215546Sopenharmony_ci{
2285bf215546Sopenharmony_ci   pctx->buffer_map = zink_buffer_map;
2286bf215546Sopenharmony_ci   pctx->buffer_unmap = zink_buffer_unmap;
2287bf215546Sopenharmony_ci   pctx->texture_map = u_transfer_helper_deinterleave_transfer_map;
2288bf215546Sopenharmony_ci   pctx->texture_unmap = u_transfer_helper_deinterleave_transfer_unmap;
2289bf215546Sopenharmony_ci
2290bf215546Sopenharmony_ci   pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
2291bf215546Sopenharmony_ci   pctx->buffer_subdata = zink_buffer_subdata;
2292bf215546Sopenharmony_ci   pctx->texture_subdata = u_default_texture_subdata;
2293bf215546Sopenharmony_ci   pctx->invalidate_resource = zink_resource_invalidate;
2294bf215546Sopenharmony_ci}
2295