2 * Copyright 2018 Collabora Ltd.
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:
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
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.
24 #include "zink_resource.h"
26 #include "zink_cmdbuf.h"
27 #include "zink_context.h"
28 #include "zink_screen.h"
30 #include "util/slab.h"
31 #include "util/u_debug.h"
32 #include "util/u_format.h"
33 #include "util/u_inlines.h"
34 #include "util/u_memory.h"
36 #include "state_tracker/sw_winsys.h"
39 zink_resource_destroy(struct pipe_screen
*pscreen
,
40 struct pipe_resource
*pres
)
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
);
47 vkDestroyImage(screen
->dev
, res
->image
, NULL
);
49 vkFreeMemory(screen
->dev
, res
->mem
, NULL
);
54 get_memory_type_index(struct zink_screen
*screen
,
55 const VkMemoryRequirements
*reqs
,
56 VkMemoryPropertyFlags props
)
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
) {
67 unreachable("Unsupported memory-type");
72 zink_aspect_from_format(enum pipe_format fmt
)
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
;
83 return VK_IMAGE_ASPECT_COLOR_BIT
;
86 static struct pipe_resource
*
87 zink_resource_create(struct pipe_screen
*pscreen
,
88 const struct pipe_resource
*templ
)
90 struct zink_screen
*screen
= zink_screen(pscreen
);
91 struct zink_resource
*res
= CALLOC_STRUCT(zink_resource
);
95 pipe_reference_init(&res
->base
.reference
, 1);
96 res
->base
.screen
= pscreen
;
98 VkMemoryRequirements reqs
;
99 VkMemoryPropertyFlags flags
= 0;
100 if (templ
->target
== PIPE_BUFFER
) {
101 VkBufferCreateInfo bci
= {};
102 bci
.sType
= VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
;
103 bci
.size
= templ
->width0
;
107 if (templ
->bind
& PIPE_BIND_VERTEX_BUFFER
)
108 bci
.usage
|= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
;
110 if (templ
->bind
& PIPE_BIND_INDEX_BUFFER
)
111 bci
.usage
|= VK_BUFFER_USAGE_INDEX_BUFFER_BIT
;
113 if (templ
->bind
& PIPE_BIND_CONSTANT_BUFFER
)
114 bci
.usage
|= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
;
116 if (templ
->bind
& PIPE_BIND_SHADER_BUFFER
)
117 bci
.usage
|= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
;
119 if (templ
->bind
& PIPE_BIND_COMMAND_ARGS_BUFFER
)
120 bci
.usage
|= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
;
122 if (templ
->usage
== PIPE_USAGE_STAGING
)
123 bci
.usage
|= VK_BUFFER_USAGE_TRANSFER_SRC_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT
;
125 if (vkCreateBuffer(screen
->dev
, &bci
, NULL
, &res
->buffer
) !=
131 vkGetBufferMemoryRequirements(screen
->dev
, res
->buffer
, &reqs
);
132 flags
|= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
;
134 res
->format
= zink_get_format(templ
->format
);
136 VkImageCreateInfo ici
= {};
137 ici
.sType
= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
;
139 switch (templ
->target
) {
140 case PIPE_TEXTURE_1D
:
141 case PIPE_TEXTURE_1D_ARRAY
:
142 ici
.imageType
= VK_IMAGE_TYPE_1D
;
145 case PIPE_TEXTURE_2D
:
146 case PIPE_TEXTURE_2D_ARRAY
:
147 case PIPE_TEXTURE_CUBE
:
148 case PIPE_TEXTURE_CUBE_ARRAY
:
149 case PIPE_TEXTURE_RECT
:
150 ici
.imageType
= VK_IMAGE_TYPE_2D
;
151 /* cube and 2D array needs some quirks here */
152 if (templ
->target
== PIPE_TEXTURE_CUBE
)
153 ici
.flags
= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
;
154 else if (templ
->target
== PIPE_TEXTURE_2D_ARRAY
)
155 ici
.flags
= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR
;
156 else if (templ
->target
== PIPE_TEXTURE_CUBE_ARRAY
)
157 ici
.flags
= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
|
158 VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR
;
161 case PIPE_TEXTURE_3D
:
162 ici
.imageType
= VK_IMAGE_TYPE_3D
;
166 unreachable("PIPE_BUFFER should already be handled");
169 unreachable("Unknown target");
172 ici
.format
= res
->format
;
173 ici
.extent
.width
= templ
->width0
;
174 ici
.extent
.height
= templ
->height0
;
175 ici
.extent
.depth
= templ
->depth0
;
176 ici
.mipLevels
= templ
->last_level
+ 1;
177 ici
.arrayLayers
= templ
->array_size
;
178 ici
.samples
= templ
->nr_samples
? templ
->nr_samples
: VK_SAMPLE_COUNT_1_BIT
;
179 ici
.tiling
= templ
->bind
& PIPE_BIND_LINEAR
? VK_IMAGE_TILING_LINEAR
: VK_IMAGE_TILING_OPTIMAL
;
181 if (templ
->target
== PIPE_TEXTURE_CUBE
||
182 templ
->target
== PIPE_TEXTURE_CUBE_ARRAY
)
183 ici
.arrayLayers
*= 6;
185 if (templ
->bind
& (PIPE_BIND_DISPLAY_TARGET
|
188 // assert(ici.tiling == VK_IMAGE_TILING_LINEAR);
189 ici
.tiling
= VK_IMAGE_TILING_LINEAR
;
192 if (templ
->usage
== PIPE_USAGE_STAGING
)
193 ici
.tiling
= VK_IMAGE_TILING_LINEAR
;
195 /* sadly, gallium doesn't let us know if it'll ever need this, so we have to assume */
196 ici
.usage
= VK_IMAGE_USAGE_TRANSFER_SRC_BIT
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
;
198 if (templ
->bind
& PIPE_BIND_SAMPLER_VIEW
)
199 ici
.usage
|= VK_IMAGE_USAGE_SAMPLED_BIT
;
201 if (templ
->bind
& PIPE_BIND_SHADER_IMAGE
)
202 ici
.usage
|= VK_IMAGE_USAGE_STORAGE_BIT
;
204 if (templ
->bind
& PIPE_BIND_RENDER_TARGET
)
205 ici
.usage
|= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
;
207 if (templ
->bind
& PIPE_BIND_DEPTH_STENCIL
)
208 ici
.usage
|= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
;
210 if (templ
->flags
& PIPE_RESOURCE_FLAG_SPARSE
)
211 ici
.usage
|= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
;
213 if (templ
->bind
& PIPE_BIND_STREAM_OUTPUT
)
214 ici
.usage
|= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
;
216 ici
.sharingMode
= VK_SHARING_MODE_EXCLUSIVE
;
217 ici
.initialLayout
= VK_IMAGE_LAYOUT_UNDEFINED
;
218 res
->layout
= VK_IMAGE_LAYOUT_UNDEFINED
;
220 VkResult result
= vkCreateImage(screen
->dev
, &ici
, NULL
, &res
->image
);
221 if (result
!= VK_SUCCESS
) {
226 res
->optimial_tiling
= ici
.tiling
!= VK_IMAGE_TILING_LINEAR
;
227 res
->aspect
= zink_aspect_from_format(templ
->format
);
229 vkGetImageMemoryRequirements(screen
->dev
, res
->image
, &reqs
);
230 if (templ
->usage
== PIPE_USAGE_STAGING
|| (screen
->winsys
&& (templ
->bind
& (PIPE_BIND_SCANOUT
|PIPE_BIND_DISPLAY_TARGET
|PIPE_BIND_SHARED
))))
231 flags
|= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
;
233 flags
|= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
;
236 VkMemoryAllocateInfo mai
= {};
237 mai
.sType
= VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
;
238 mai
.allocationSize
= reqs
.size
;
239 mai
.memoryTypeIndex
= get_memory_type_index(screen
, &reqs
, flags
);
241 VkExportMemoryAllocateInfo emai
= {};
242 if (templ
->bind
& PIPE_BIND_SHARED
) {
243 emai
.sType
= VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO
;
244 emai
.handleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
;
248 if (vkAllocateMemory(screen
->dev
, &mai
, NULL
, &res
->mem
) != VK_SUCCESS
)
252 res
->size
= reqs
.size
;
254 if (templ
->target
== PIPE_BUFFER
)
255 vkBindBufferMemory(screen
->dev
, res
->buffer
, res
->mem
, res
->offset
);
257 vkBindImageMemory(screen
->dev
, res
->image
, res
->mem
, res
->offset
);
259 if (screen
->winsys
&& (templ
->bind
& (PIPE_BIND_DISPLAY_TARGET
|
261 PIPE_BIND_SHARED
))) {
262 struct sw_winsys
*winsys
= screen
->winsys
;
263 res
->dt
= winsys
->displaytarget_create(screen
->winsys
,
275 if (templ
->target
== PIPE_BUFFER
)
276 vkDestroyBuffer(screen
->dev
, res
->buffer
, NULL
);
278 vkDestroyImage(screen
->dev
, res
->image
, NULL
);
286 zink_resource_get_handle(struct pipe_screen
*pscreen
,
287 struct pipe_context
*context
,
288 struct pipe_resource
*tex
,
289 struct winsys_handle
*whandle
,
292 struct zink_resource
*res
= zink_resource(tex
);
293 struct zink_screen
*screen
= zink_screen(pscreen
);
294 VkMemoryGetFdInfoKHR fd_info
= {};
297 if (res
->base
.target
!= PIPE_BUFFER
) {
298 VkImageSubresource sub_res
= {};
299 VkSubresourceLayout sub_res_layout
= {};
301 sub_res
.aspectMask
= res
->aspect
;
303 vkGetImageSubresourceLayout(screen
->dev
, res
->image
, &sub_res
, &sub_res_layout
);
305 whandle
->stride
= sub_res_layout
.rowPitch
;
308 if (whandle
->type
== WINSYS_HANDLE_TYPE_FD
) {
310 if (!screen
->vk_GetMemoryFdKHR
)
311 screen
->vk_GetMemoryFdKHR
= (PFN_vkGetMemoryFdKHR
)vkGetDeviceProcAddr(screen
->dev
, "vkGetMemoryFdKHR");
312 if (!screen
->vk_GetMemoryFdKHR
)
314 fd_info
.sType
= VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR
;
315 fd_info
.memory
= res
->mem
;
316 fd_info
.handleType
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT
;
317 VkResult result
= (*screen
->vk_GetMemoryFdKHR
)(screen
->dev
, &fd_info
, &fd
);
318 if (result
!= VK_SUCCESS
)
320 whandle
->handle
= fd
;
326 zink_screen_resource_init(struct pipe_screen
*pscreen
)
328 pscreen
->resource_create
= zink_resource_create
;
329 pscreen
->resource_destroy
= zink_resource_destroy
;
330 pscreen
->resource_get_handle
= zink_resource_get_handle
;
334 zink_transfer_copy_bufimage(struct zink_context
*ctx
,
335 struct zink_resource
*res
,
336 struct zink_resource
*staging_res
,
337 struct zink_transfer
*trans
,
340 struct zink_cmdbuf
*cmdbuf
= zink_start_cmdbuf(ctx
);
344 if (res
->layout
!= VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
&&
345 res
->layout
!= VK_IMAGE_LAYOUT_GENERAL
) {
346 zink_resource_barrier(cmdbuf
->cmdbuf
, res
, res
->aspect
,
347 VK_IMAGE_LAYOUT_GENERAL
);
348 res
->layout
= VK_IMAGE_LAYOUT_GENERAL
;
351 VkBufferImageCopy copyRegion
= {};
352 copyRegion
.bufferOffset
= staging_res
->offset
;
353 copyRegion
.bufferRowLength
= 0;
354 copyRegion
.bufferImageHeight
= 0;
355 copyRegion
.imageSubresource
.aspectMask
= res
->aspect
;
356 copyRegion
.imageSubresource
.mipLevel
= trans
->base
.level
;
357 copyRegion
.imageSubresource
.layerCount
= 1;
358 if (res
->base
.array_size
> 1) {
359 copyRegion
.imageSubresource
.baseArrayLayer
= trans
->base
.box
.z
;
360 copyRegion
.imageSubresource
.layerCount
= trans
->base
.box
.depth
;
362 copyRegion
.imageOffset
.z
= trans
->base
.box
.z
;
363 copyRegion
.imageExtent
.depth
= trans
->base
.box
.depth
;
365 copyRegion
.imageOffset
.x
= trans
->base
.box
.x
;
366 copyRegion
.imageOffset
.y
= trans
->base
.box
.y
;
368 copyRegion
.imageExtent
.width
= trans
->base
.box
.width
;
369 copyRegion
.imageExtent
.height
= trans
->base
.box
.height
;
371 zink_cmdbuf_reference_resoure(cmdbuf
, res
);
372 zink_cmdbuf_reference_resoure(cmdbuf
, staging_res
);
375 vkCmdCopyBufferToImage(cmdbuf
->cmdbuf
, staging_res
->buffer
, res
->image
, res
->layout
, 1, ©Region
);
377 vkCmdCopyImageToBuffer(cmdbuf
->cmdbuf
, res
->image
, res
->layout
, staging_res
->buffer
, 1, ©Region
);
379 zink_end_cmdbuf(ctx
, cmdbuf
);
384 zink_transfer_map(struct pipe_context
*pctx
,
385 struct pipe_resource
*pres
,
388 const struct pipe_box
*box
,
389 struct pipe_transfer
**transfer
)
391 struct zink_context
*ctx
= zink_context(pctx
);
392 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
393 struct zink_resource
*res
= zink_resource(pres
);
395 struct zink_transfer
*trans
= slab_alloc(&ctx
->transfer_pool
);
399 memset(trans
, 0, sizeof(*trans
));
400 pipe_resource_reference(&trans
->base
.resource
, pres
);
402 trans
->base
.resource
= pres
;
403 trans
->base
.level
= level
;
404 trans
->base
.usage
= usage
;
405 trans
->base
.box
= *box
;
408 if (pres
->target
== PIPE_BUFFER
) {
409 VkResult result
= vkMapMemory(screen
->dev
, res
->mem
, res
->offset
, res
->size
, 0, &ptr
);
410 if (result
!= VK_SUCCESS
)
413 trans
->base
.stride
= 0;
414 trans
->base
.layer_stride
= 0;
415 ptr
= ((uint8_t *)ptr
) + box
->x
;
417 if (res
->optimial_tiling
|| ((res
->base
.usage
!= PIPE_USAGE_STAGING
))) {
418 trans
->base
.stride
= util_format_get_stride(pres
->format
, box
->width
);
419 trans
->base
.layer_stride
= util_format_get_2d_size(pres
->format
,
423 struct pipe_resource templ
= *pres
;
424 templ
.usage
= PIPE_USAGE_STAGING
;
425 templ
.target
= PIPE_BUFFER
;
426 templ
.bind
= 0; // HACK: there's no transfer binding, but usage should tell us enough
427 templ
.width0
= trans
->base
.layer_stride
* box
->depth
;
428 templ
.height0
= templ
.depth0
= 0;
429 templ
.last_level
= 0;
430 templ
.array_size
= 1;
433 trans
->staging_res
= zink_resource_create(pctx
->screen
, &templ
);
434 if (!trans
->staging_res
)
437 struct zink_resource
*staging_res
= zink_resource(trans
->staging_res
);
439 if (usage
& PIPE_TRANSFER_READ
) {
440 struct zink_context
*ctx
= zink_context(pctx
);
441 bool ret
= zink_transfer_copy_bufimage(ctx
, res
,
448 VkResult result
= vkMapMemory(screen
->dev
, staging_res
->mem
,
450 staging_res
->size
, 0, &ptr
);
451 if (result
!= VK_SUCCESS
)
455 assert(!res
->optimial_tiling
);
456 VkResult result
= vkMapMemory(screen
->dev
, res
->mem
, res
->offset
, res
->size
, 0, &ptr
);
457 if (result
!= VK_SUCCESS
)
459 VkImageSubresource isr
= {
464 VkSubresourceLayout srl
;
465 vkGetImageSubresourceLayout(screen
->dev
, res
->image
, &isr
, &srl
);
466 trans
->base
.stride
= srl
.rowPitch
;
467 trans
->base
.layer_stride
= srl
.arrayPitch
;
468 ptr
= ((uint8_t *)ptr
) + box
->z
* srl
.depthPitch
+
469 box
->y
* srl
.rowPitch
+
474 *transfer
= &trans
->base
;
479 zink_transfer_unmap(struct pipe_context
*pctx
,
480 struct pipe_transfer
*ptrans
)
482 struct zink_context
*ctx
= zink_context(pctx
);
483 struct zink_screen
*screen
= zink_screen(pctx
->screen
);
484 struct zink_resource
*res
= zink_resource(ptrans
->resource
);
485 struct zink_transfer
*trans
= (struct zink_transfer
*)ptrans
;
486 if (trans
->staging_res
) {
487 struct zink_resource
*staging_res
= zink_resource(trans
->staging_res
);
488 vkUnmapMemory(screen
->dev
, staging_res
->mem
);
490 if (trans
->base
.usage
& PIPE_TRANSFER_WRITE
) {
491 struct zink_context
*ctx
= zink_context(pctx
);
493 zink_transfer_copy_bufimage(ctx
, res
, staging_res
, trans
, true);
496 pipe_resource_reference(&trans
->staging_res
, NULL
);
498 vkUnmapMemory(screen
->dev
, res
->mem
);
500 pipe_resource_reference(&trans
->base
.resource
, NULL
);
501 slab_free(&ctx
->transfer_pool
, ptrans
);
505 zink_context_resource_init(struct pipe_context
*pctx
)
507 pctx
->transfer_map
= zink_transfer_map
;
508 pctx
->transfer_unmap
= zink_transfer_unmap
;
510 pctx
->transfer_flush_region
= u_default_transfer_flush_region
;
511 pctx
->buffer_subdata
= u_default_buffer_subdata
;
512 pctx
->texture_subdata
= u_default_texture_subdata
;