1 /*
2  * Copyright 2018 Collabora Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "zink_resource.h"
25 
26 #include "zink_batch.h"
27 #include "zink_context.h"
28 #include "zink_screen.h"
29 
30 #include "util/slab.h"
31 #include "util/u_debug.h"
32 #include "util/format/u_format.h"
33 #include "util/u_inlines.h"
34 #include "util/u_memory.h"
35 
36 #include "frontend/sw_winsys.h"
37 
38 static void
zink_resource_destroy(struct pipe_screen * pscreen,struct pipe_resource * pres)39 zink_resource_destroy(struct pipe_screen *pscreen,
40                       struct pipe_resource *pres)
41 {
42    struct zink_screen *screen = zink_screen(pscreen);
43    struct zink_resource *res = zink_resource(pres);
44    if (pres->target == PIPE_BUFFER)
45       vkDestroyBuffer(screen->dev, res->buffer, NULL);
46    else
47       vkDestroyImage(screen->dev, res->image, NULL);
48 
49    vkFreeMemory(screen->dev, res->mem, NULL);
50    FREE(res);
51 }
52 
53 static uint32_t
get_memory_type_index(struct zink_screen * screen,const VkMemoryRequirements * reqs,VkMemoryPropertyFlags props)54 get_memory_type_index(struct zink_screen *screen,
55                       const VkMemoryRequirements *reqs,
56                       VkMemoryPropertyFlags props)
57 {
58    for (uint32_t i = 0u; i < VK_MAX_MEMORY_TYPES; i++) {
59       if (((reqs->memoryTypeBits >> i) & 1) == 1) {
60          if ((screen->mem_props.memoryTypes[i].propertyFlags & props) == props) {
61             return i;
62             break;
63          }
64       }
65    }
66 
67    unreachable("Unsupported memory-type");
68    return 0;
69 }
70 
71 static VkImageAspectFlags
aspect_from_format(enum pipe_format fmt)72 aspect_from_format(enum pipe_format fmt)
73 {
74    if (util_format_is_depth_or_stencil(fmt)) {
75       VkImageAspectFlags aspect = 0;
76       const struct util_format_description *desc = util_format_description(fmt);
77       if (util_format_has_depth(desc))
78          aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
79       if (util_format_has_stencil(desc))
80          aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
81       return aspect;
82    } else
83      return VK_IMAGE_ASPECT_COLOR_BIT;
84 }
85 
86 static struct pipe_resource *
resource_create(struct pipe_screen * pscreen,const struct pipe_resource * templ,struct winsys_handle * whandle,unsigned external_usage)87 resource_create(struct pipe_screen *pscreen,
88                 const struct pipe_resource *templ,
89                 struct winsys_handle *whandle,
90                 unsigned external_usage)
91 {
92    struct zink_screen *screen = zink_screen(pscreen);
93    struct zink_resource *res = CALLOC_STRUCT(zink_resource);
94 
95    res->base = *templ;
96 
97    pipe_reference_init(&res->base.reference, 1);
98    res->base.screen = pscreen;
99 
100    VkMemoryRequirements reqs;
101    VkMemoryPropertyFlags flags = 0;
102    if (templ->target == PIPE_BUFFER) {
103       VkBufferCreateInfo bci = {};
104       bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
105       bci.size = templ->width0;
106 
107       bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
108                   VK_BUFFER_USAGE_TRANSFER_DST_BIT;
109 
110       if (templ->bind & PIPE_BIND_VERTEX_BUFFER)
111          bci.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
112 
113       if (templ->bind & PIPE_BIND_INDEX_BUFFER)
114          bci.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
115 
116       if (templ->bind & PIPE_BIND_CONSTANT_BUFFER)
117          bci.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
118 
119       if (templ->bind & PIPE_BIND_SHADER_BUFFER)
120          bci.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
121 
122       if (templ->bind & PIPE_BIND_COMMAND_ARGS_BUFFER)
123          bci.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
124 
125       if (templ->bind == (PIPE_BIND_STREAM_OUTPUT | PIPE_BIND_CUSTOM)) {
126          bci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;
127       } else if (templ->bind & PIPE_BIND_STREAM_OUTPUT) {
128          bci.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
129       }
130 
131       if (vkCreateBuffer(screen->dev, &bci, NULL, &res->buffer) !=
132           VK_SUCCESS) {
133          FREE(res);
134          return NULL;
135       }
136 
137       vkGetBufferMemoryRequirements(screen->dev, res->buffer, &reqs);
138       flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
139    } else {
140       res->format = zink_get_format(screen, templ->format);
141 
142       VkImageCreateInfo ici = {};
143       ici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
144       ici.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
145 
146       switch (templ->target) {
147       case PIPE_TEXTURE_1D:
148       case PIPE_TEXTURE_1D_ARRAY:
149          ici.imageType = VK_IMAGE_TYPE_1D;
150          break;
151 
152       case PIPE_TEXTURE_CUBE:
153       case PIPE_TEXTURE_CUBE_ARRAY:
154          ici.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
155          /* fall-through */
156       case PIPE_TEXTURE_2D:
157       case PIPE_TEXTURE_2D_ARRAY:
158       case PIPE_TEXTURE_RECT:
159          ici.imageType = VK_IMAGE_TYPE_2D;
160          break;
161 
162       case PIPE_TEXTURE_3D:
163          ici.imageType = VK_IMAGE_TYPE_3D;
164          if (templ->bind & PIPE_BIND_RENDER_TARGET)
165             ici.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
166          break;
167 
168       case PIPE_BUFFER:
169          unreachable("PIPE_BUFFER should already be handled");
170 
171       default:
172          unreachable("Unknown target");
173       }
174 
175       ici.format = res->format;
176       ici.extent.width = templ->width0;
177       ici.extent.height = templ->height0;
178       ici.extent.depth = templ->depth0;
179       ici.mipLevels = templ->last_level + 1;
180       ici.arrayLayers = MAX2(templ->array_size, 1);
181       ici.samples = templ->nr_samples ? templ->nr_samples : VK_SAMPLE_COUNT_1_BIT;
182       ici.tiling = templ->bind & PIPE_BIND_LINEAR ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
183 
184       if (templ->target == PIPE_TEXTURE_CUBE ||
185           templ->target == PIPE_TEXTURE_CUBE_ARRAY)
186          ici.arrayLayers *= 6;
187 
188       if (templ->bind & PIPE_BIND_SHARED)
189          ici.tiling = VK_IMAGE_TILING_LINEAR;
190 
191       if (templ->usage == PIPE_USAGE_STAGING)
192          ici.tiling = VK_IMAGE_TILING_LINEAR;
193 
194       /* sadly, gallium doesn't let us know if it'll ever need this, so we have to assume */
195       ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
196                   VK_IMAGE_USAGE_TRANSFER_DST_BIT |
197                   VK_IMAGE_USAGE_SAMPLED_BIT;
198 
199       if (templ->bind & PIPE_BIND_SHADER_IMAGE)
200          ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
201 
202       if (templ->bind & PIPE_BIND_RENDER_TARGET)
203          ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
204 
205       if (templ->bind & PIPE_BIND_DEPTH_STENCIL)
206          ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
207 
208       if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE)
209          ici.usage |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
210 
211       if (templ->bind & PIPE_BIND_STREAM_OUTPUT)
212          ici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
213 
214       ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
215       ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
216       res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
217 
218       VkResult result = vkCreateImage(screen->dev, &ici, NULL, &res->image);
219       if (result != VK_SUCCESS) {
220          FREE(res);
221          return NULL;
222       }
223 
224       res->optimial_tiling = ici.tiling != VK_IMAGE_TILING_LINEAR;
225       res->aspect = aspect_from_format(templ->format);
226 
227       vkGetImageMemoryRequirements(screen->dev, res->image, &reqs);
228       if (templ->usage == PIPE_USAGE_STAGING || (screen->winsys && (templ->bind & (PIPE_BIND_SCANOUT|PIPE_BIND_DISPLAY_TARGET|PIPE_BIND_SHARED))))
229         flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
230       else
231         flags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
232    }
233 
234    VkMemoryAllocateInfo mai = {};
235    mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
236    mai.allocationSize = reqs.size;
237    mai.memoryTypeIndex = get_memory_type_index(screen, &reqs, flags);
238 
239    VkExportMemoryAllocateInfo emai = {};
240    if (templ->bind & PIPE_BIND_SHARED) {
241       emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
242       emai.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
243       mai.pNext = &emai;
244    }
245 
246    VkImportMemoryFdInfoKHR imfi = {
247       VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
248       NULL,
249    };
250 
251    if (whandle && whandle->type == WINSYS_HANDLE_TYPE_FD) {
252       imfi.pNext = NULL;
253       imfi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
254       imfi.fd = whandle->handle;
255 
256       emai.pNext = &imfi;
257    }
258 
259    if (vkAllocateMemory(screen->dev, &mai, NULL, &res->mem) != VK_SUCCESS)
260       goto fail;
261 
262    res->offset = 0;
263    res->size = reqs.size;
264 
265    if (templ->target == PIPE_BUFFER)
266       vkBindBufferMemory(screen->dev, res->buffer, res->mem, res->offset);
267    else
268       vkBindImageMemory(screen->dev, res->image, res->mem, res->offset);
269 
270    if (screen->winsys && (templ->bind & (PIPE_BIND_DISPLAY_TARGET |
271                                          PIPE_BIND_SCANOUT |
272                                          PIPE_BIND_SHARED))) {
273       struct sw_winsys *winsys = screen->winsys;
274       res->dt = winsys->displaytarget_create(screen->winsys,
275                                              res->base.bind,
276                                              res->base.format,
277                                              templ->width0,
278                                              templ->height0,
279                                              64, NULL,
280                                              &res->dt_stride);
281    }
282 
283    return &res->base;
284 
285 fail:
286    if (templ->target == PIPE_BUFFER)
287       vkDestroyBuffer(screen->dev, res->buffer, NULL);
288    else
289       vkDestroyImage(screen->dev, res->image, NULL);
290 
291    FREE(res);
292 
293    return NULL;
294 }
295 
296 static struct pipe_resource *
zink_resource_create(struct pipe_screen * pscreen,const struct pipe_resource * templ)297 zink_resource_create(struct pipe_screen *pscreen,
298                      const struct pipe_resource *templ)
299 {
300    return resource_create(pscreen, templ, NULL, 0);
301 }
302 
303 static bool
zink_resource_get_handle(struct pipe_screen * pscreen,struct pipe_context * context,struct pipe_resource * tex,struct winsys_handle * whandle,unsigned usage)304 zink_resource_get_handle(struct pipe_screen *pscreen,
305                          struct pipe_context *context,
306                          struct pipe_resource *tex,
307                          struct winsys_handle *whandle,
308                          unsigned usage)
309 {
310    struct zink_resource *res = zink_resource(tex);
311    struct zink_screen *screen = zink_screen(pscreen);
312    VkMemoryGetFdInfoKHR fd_info = {};
313    int fd;
314 
315    if (res->base.target != PIPE_BUFFER) {
316       VkImageSubresource sub_res = {};
317       VkSubresourceLayout sub_res_layout = {};
318 
319       sub_res.aspectMask = res->aspect;
320 
321       vkGetImageSubresourceLayout(screen->dev, res->image, &sub_res, &sub_res_layout);
322 
323       whandle->stride = sub_res_layout.rowPitch;
324    }
325 
326    if (whandle->type == WINSYS_HANDLE_TYPE_FD) {
327       fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
328       fd_info.memory = res->mem;
329       fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
330       VkResult result = (*screen->vk_GetMemoryFdKHR)(screen->dev, &fd_info, &fd);
331       if (result != VK_SUCCESS)
332          return false;
333       whandle->handle = fd;
334    }
335    return true;
336 }
337 
338 static struct pipe_resource *
zink_resource_from_handle(struct pipe_screen * pscreen,const struct pipe_resource * templ,struct winsys_handle * whandle,unsigned usage)339 zink_resource_from_handle(struct pipe_screen *pscreen,
340                  const struct pipe_resource *templ,
341                  struct winsys_handle *whandle,
342                  unsigned usage)
343 {
344    return resource_create(pscreen, templ, whandle, usage);
345 }
346 
347 void
zink_screen_resource_init(struct pipe_screen * pscreen)348 zink_screen_resource_init(struct pipe_screen *pscreen)
349 {
350    pscreen->resource_create = zink_resource_create;
351    pscreen->resource_destroy = zink_resource_destroy;
352 
353    if (zink_screen(pscreen)->have_KHR_external_memory_fd) {
354       pscreen->resource_get_handle = zink_resource_get_handle;
355       pscreen->resource_from_handle = zink_resource_from_handle;
356    }
357 }
358 
359 static bool
zink_transfer_copy_bufimage(struct zink_context * ctx,struct zink_resource * res,struct zink_resource * staging_res,struct zink_transfer * trans,bool buf2img)360 zink_transfer_copy_bufimage(struct zink_context *ctx,
361                             struct zink_resource *res,
362                             struct zink_resource *staging_res,
363                             struct zink_transfer *trans,
364                             bool buf2img)
365 {
366    struct zink_batch *batch = zink_batch_no_rp(ctx);
367 
368    if (buf2img) {
369       if (res->layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
370          zink_resource_barrier(batch->cmdbuf, res, res->aspect,
371                                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
372       }
373    } else {
374       if (res->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
375          zink_resource_barrier(batch->cmdbuf, res, res->aspect,
376                                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
377       }
378    }
379 
380    VkBufferImageCopy copyRegion = {};
381    copyRegion.bufferOffset = staging_res->offset;
382    copyRegion.bufferRowLength = 0;
383    copyRegion.bufferImageHeight = 0;
384    copyRegion.imageSubresource.mipLevel = trans->base.level;
385    copyRegion.imageSubresource.layerCount = 1;
386    if (res->base.array_size > 1) {
387       copyRegion.imageSubresource.baseArrayLayer = trans->base.box.z;
388       copyRegion.imageSubresource.layerCount = trans->base.box.depth;
389       copyRegion.imageExtent.depth = 1;
390    } else {
391       copyRegion.imageOffset.z = trans->base.box.z;
392       copyRegion.imageExtent.depth = trans->base.box.depth;
393    }
394    copyRegion.imageOffset.x = trans->base.box.x;
395    copyRegion.imageOffset.y = trans->base.box.y;
396 
397    copyRegion.imageExtent.width = trans->base.box.width;
398    copyRegion.imageExtent.height = trans->base.box.height;
399 
400    zink_batch_reference_resoure(batch, res);
401    zink_batch_reference_resoure(batch, staging_res);
402 
403    unsigned aspects = res->aspect;
404    while (aspects) {
405       int aspect = 1 << u_bit_scan(&aspects);
406       copyRegion.imageSubresource.aspectMask = aspect;
407 
408       if (buf2img)
409          vkCmdCopyBufferToImage(batch->cmdbuf, staging_res->buffer, res->image, res->layout, 1, &copyRegion);
410       else
411          vkCmdCopyImageToBuffer(batch->cmdbuf, res->image, res->layout, staging_res->buffer, 1, &copyRegion);
412    }
413 
414    return true;
415 }
416 
417 static void *
zink_transfer_map(struct pipe_context * pctx,struct pipe_resource * pres,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** transfer)418 zink_transfer_map(struct pipe_context *pctx,
419                   struct pipe_resource *pres,
420                   unsigned level,
421                   unsigned usage,
422                   const struct pipe_box *box,
423                   struct pipe_transfer **transfer)
424 {
425    struct zink_context *ctx = zink_context(pctx);
426    struct zink_screen *screen = zink_screen(pctx->screen);
427    struct zink_resource *res = zink_resource(pres);
428 
429    struct zink_transfer *trans = slab_alloc(&ctx->transfer_pool);
430    if (!trans)
431       return NULL;
432 
433    memset(trans, 0, sizeof(*trans));
434    pipe_resource_reference(&trans->base.resource, pres);
435 
436    trans->base.resource = pres;
437    trans->base.level = level;
438    trans->base.usage = usage;
439    trans->base.box = *box;
440 
441    void *ptr;
442    if (pres->target == PIPE_BUFFER) {
443       if (usage & PIPE_TRANSFER_READ) {
444          /* need to wait for rendering to finish
445           * TODO: optimize/fix this to be much less obtrusive
446           * mesa/mesa#2966
447           */
448          struct pipe_fence_handle *fence = NULL;
449          pctx->flush(pctx, &fence, PIPE_FLUSH_HINT_FINISH);
450          if (fence) {
451             pctx->screen->fence_finish(pctx->screen, NULL, fence,
452                                        PIPE_TIMEOUT_INFINITE);
453             pctx->screen->fence_reference(pctx->screen, &fence, NULL);
454          }
455       }
456 
457 
458       VkResult result = vkMapMemory(screen->dev, res->mem, res->offset, res->size, 0, &ptr);
459       if (result != VK_SUCCESS)
460          return NULL;
461 
462       trans->base.stride = 0;
463       trans->base.layer_stride = 0;
464       ptr = ((uint8_t *)ptr) + box->x;
465    } else {
466       if (res->optimial_tiling || ((res->base.usage != PIPE_USAGE_STAGING))) {
467          trans->base.stride = util_format_get_stride(pres->format, box->width);
468          trans->base.layer_stride = util_format_get_2d_size(pres->format,
469                                                             trans->base.stride,
470                                                             box->height);
471 
472          struct pipe_resource templ = *pres;
473          templ.usage = PIPE_USAGE_STAGING;
474          templ.target = PIPE_BUFFER;
475          templ.bind = 0;
476          templ.width0 = trans->base.layer_stride * box->depth;
477          templ.height0 = templ.depth0 = 0;
478          templ.last_level = 0;
479          templ.array_size = 1;
480          templ.flags = 0;
481 
482          trans->staging_res = zink_resource_create(pctx->screen, &templ);
483          if (!trans->staging_res)
484             return NULL;
485 
486          struct zink_resource *staging_res = zink_resource(trans->staging_res);
487 
488          if (usage & PIPE_TRANSFER_READ) {
489             struct zink_context *ctx = zink_context(pctx);
490             bool ret = zink_transfer_copy_bufimage(ctx, res,
491                                                    staging_res, trans,
492                                                    false);
493             if (ret == false)
494                return NULL;
495 
496             /* need to wait for rendering to finish */
497             struct pipe_fence_handle *fence = NULL;
498             pctx->flush(pctx, &fence, PIPE_FLUSH_HINT_FINISH);
499             if (fence) {
500                pctx->screen->fence_finish(pctx->screen, NULL, fence,
501                                           PIPE_TIMEOUT_INFINITE);
502                pctx->screen->fence_reference(pctx->screen, &fence, NULL);
503             }
504          }
505 
506          VkResult result = vkMapMemory(screen->dev, staging_res->mem,
507                                        staging_res->offset,
508                                        staging_res->size, 0, &ptr);
509          if (result != VK_SUCCESS)
510             return NULL;
511 
512       } else {
513          assert(!res->optimial_tiling);
514          VkResult result = vkMapMemory(screen->dev, res->mem, res->offset, res->size, 0, &ptr);
515          if (result != VK_SUCCESS)
516             return NULL;
517          VkImageSubresource isr = {
518             res->aspect,
519             level,
520             0
521          };
522          VkSubresourceLayout srl;
523          vkGetImageSubresourceLayout(screen->dev, res->image, &isr, &srl);
524          trans->base.stride = srl.rowPitch;
525          trans->base.layer_stride = srl.arrayPitch;
526          ptr = ((uint8_t *)ptr) + box->z * srl.depthPitch +
527                                   box->y * srl.rowPitch +
528                                   box->x;
529       }
530    }
531 
532    *transfer = &trans->base;
533    return ptr;
534 }
535 
536 static void
zink_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * ptrans)537 zink_transfer_unmap(struct pipe_context *pctx,
538                     struct pipe_transfer *ptrans)
539 {
540    struct zink_context *ctx = zink_context(pctx);
541    struct zink_screen *screen = zink_screen(pctx->screen);
542    struct zink_resource *res = zink_resource(ptrans->resource);
543    struct zink_transfer *trans = (struct zink_transfer *)ptrans;
544    if (trans->staging_res) {
545       struct zink_resource *staging_res = zink_resource(trans->staging_res);
546       vkUnmapMemory(screen->dev, staging_res->mem);
547 
548       if (trans->base.usage & PIPE_TRANSFER_WRITE) {
549          struct zink_context *ctx = zink_context(pctx);
550 
551          zink_transfer_copy_bufimage(ctx, res, staging_res, trans, true);
552       }
553 
554       pipe_resource_reference(&trans->staging_res, NULL);
555    } else
556       vkUnmapMemory(screen->dev, res->mem);
557 
558    pipe_resource_reference(&trans->base.resource, NULL);
559    slab_free(&ctx->transfer_pool, ptrans);
560 }
561 
562 void
zink_context_resource_init(struct pipe_context * pctx)563 zink_context_resource_init(struct pipe_context *pctx)
564 {
565    pctx->transfer_map = zink_transfer_map;
566    pctx->transfer_unmap = zink_transfer_unmap;
567 
568    pctx->transfer_flush_region = u_default_transfer_flush_region;
569    pctx->buffer_subdata = u_default_buffer_subdata;
570    pctx->texture_subdata = u_default_texture_subdata;
571 }
572