turnip: update setup_slices
[mesa.git] / src / freedreno / vulkan / tu_image.c
1 /*
2 * Copyright © 2016 Red Hat.
3 * Copyright © 2016 Bas Nieuwenhuizen
4 *
5 * based in part on anv driver which is:
6 * Copyright © 2015 Intel Corporation
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 */
27
28 #include "tu_private.h"
29
30 #include "util/debug.h"
31 #include "util/u_atomic.h"
32 #include "vk_format.h"
33 #include "vk_util.h"
34
35 static inline bool
36 image_level_linear(struct tu_image *image, int level)
37 {
38 unsigned w = u_minify(image->extent.width, level);
39 return w < 16;
40 }
41
42 /* indexed by cpp, including msaa 2x and 4x: */
43 static const struct {
44 unsigned pitchalign;
45 unsigned heightalign;
46 } tile_alignment[] = {
47 [1] = { 128, 32 },
48 [2] = { 128, 16 },
49 [3] = { 64, 32 },
50 [4] = { 64, 16 },
51 [6] = { 64, 16 },
52 [8] = { 64, 16 },
53 [12] = { 64, 16 },
54 [16] = { 64, 16 },
55 [24] = { 64, 16 },
56 [32] = { 64, 16 },
57 [48] = { 64, 16 },
58 [64] = { 64, 16 },
59
60 /* special case for r8g8: */
61 [0] = { 64, 32 },
62 };
63
64 static void
65 setup_slices(struct tu_image *image, const VkImageCreateInfo *pCreateInfo)
66 {
67 VkFormat format = pCreateInfo->format;
68 enum vk_format_layout layout = vk_format_description(format)->layout;
69 uint32_t layer_size = 0;
70 int ta = image->cpp;
71
72 /* The r8g8 format seems to not play by the normal tiling rules: */
73 if (image->cpp == 2 && vk_format_get_nr_components(format) == 2)
74 ta = 0;
75
76 for (unsigned level = 0; level < pCreateInfo->mipLevels; level++) {
77 struct tu_image_level *slice = &image->levels[level];
78 uint32_t width = u_minify(pCreateInfo->extent.width, level);
79 uint32_t height = u_minify(pCreateInfo->extent.height, level);
80 uint32_t depth = u_minify(pCreateInfo->extent.depth, level);
81 uint32_t aligned_height = height;
82 uint32_t blocks;
83 uint32_t pitchalign;
84
85 if (image->tile_mode && !image_level_linear(image, level)) {
86 /* tiled levels of 3D textures are rounded up to PoT dimensions: */
87 if (pCreateInfo->imageType == VK_IMAGE_TYPE_3D) {
88 width = util_next_power_of_two(width);
89 height = aligned_height = util_next_power_of_two(height);
90 }
91 pitchalign = tile_alignment[ta].pitchalign;
92 aligned_height = align(aligned_height, tile_alignment[ta].heightalign);
93 } else {
94 pitchalign = 64;
95 }
96
97 /* The blits used for mem<->gmem work at a granularity of
98 * 32x32, which can cause faults due to over-fetch on the
99 * last level. The simple solution is to over-allocate a
100 * bit the last level to ensure any over-fetch is harmless.
101 * The pitch is already sufficiently aligned, but height
102 * may not be:
103 */
104 if (level + 1 == pCreateInfo->mipLevels)
105 aligned_height = align(aligned_height, 32);
106
107 if (layout == VK_FORMAT_LAYOUT_ASTC)
108 slice->pitch =
109 util_align_npot(width, pitchalign * vk_format_get_blockwidth(format));
110 else
111 slice->pitch = align(width, pitchalign);
112
113 slice->offset = layer_size;
114 blocks = vk_format_get_block_count(format, slice->pitch, aligned_height);
115
116 /* 1d array and 2d array textures must all have the same layer size
117 * for each miplevel on a6xx. 3d textures can have different layer
118 * sizes for high levels, but the hw auto-sizer is buggy (or at least
119 * different than what this code does), so as soon as the layer size
120 * range gets into range, we stop reducing it.
121 */
122 if (pCreateInfo->imageType == VK_IMAGE_TYPE_3D) {
123 if (level < 1 || image->levels[level - 1].size > 0xf000) {
124 slice->size = align(blocks * image->cpp, 4096);
125 } else {
126 slice->size = image->levels[level - 1].size;
127 }
128 } else {
129 slice->size = blocks * image->cpp;
130 }
131
132 layer_size += slice->size * depth;
133 }
134
135 image->layer_size = align(layer_size, 4096);
136 }
137
138 VkResult
139 tu_image_create(VkDevice _device,
140 const struct tu_image_create_info *create_info,
141 const VkAllocationCallbacks *alloc,
142 VkImage *pImage)
143 {
144 TU_FROM_HANDLE(tu_device, device, _device);
145 const VkImageCreateInfo *pCreateInfo = create_info->vk_info;
146 struct tu_image *image = NULL;
147 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
148
149 tu_assert(pCreateInfo->mipLevels > 0);
150 tu_assert(pCreateInfo->arrayLayers > 0);
151 tu_assert(pCreateInfo->samples > 0);
152 tu_assert(pCreateInfo->extent.width > 0);
153 tu_assert(pCreateInfo->extent.height > 0);
154 tu_assert(pCreateInfo->extent.depth > 0);
155
156 image = vk_zalloc2(&device->alloc, alloc, sizeof(*image), 8,
157 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
158 if (!image)
159 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
160
161 image->type = pCreateInfo->imageType;
162
163 image->vk_format = pCreateInfo->format;
164 image->tiling = pCreateInfo->tiling;
165 image->usage = pCreateInfo->usage;
166 image->flags = pCreateInfo->flags;
167 image->extent = pCreateInfo->extent;
168 image->level_count = pCreateInfo->mipLevels;
169 image->layer_count = pCreateInfo->arrayLayers;
170 image->samples = pCreateInfo->samples;
171 image->cpp = vk_format_get_blocksize(image->vk_format) * image->samples;
172
173 image->exclusive = pCreateInfo->sharingMode == VK_SHARING_MODE_EXCLUSIVE;
174 if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) {
175 for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i)
176 if (pCreateInfo->pQueueFamilyIndices[i] ==
177 VK_QUEUE_FAMILY_EXTERNAL)
178 image->queue_family_mask |= (1u << TU_MAX_QUEUE_FAMILIES) - 1u;
179 else
180 image->queue_family_mask |=
181 1u << pCreateInfo->pQueueFamilyIndices[i];
182 }
183
184 image->shareable =
185 vk_find_struct_const(pCreateInfo->pNext,
186 EXTERNAL_MEMORY_IMAGE_CREATE_INFO) != NULL;
187
188 image->tile_mode = TILE6_LINEAR;
189 if (pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL && !create_info->scanout)
190 image->tile_mode = TILE6_3;
191
192 setup_slices(image, pCreateInfo);
193
194 image->size = image->layer_size * pCreateInfo->arrayLayers;
195 *pImage = tu_image_to_handle(image);
196
197 return VK_SUCCESS;
198 }
199
200 static enum a6xx_tex_fetchsize
201 tu6_fetchsize(VkFormat format)
202 {
203 if (vk_format_description(format)->layout == VK_FORMAT_LAYOUT_ASTC)
204 return TFETCH6_16_BYTE;
205
206 switch (vk_format_get_blocksize(format) / vk_format_get_blockwidth(format)) {
207 case 1: return TFETCH6_1_BYTE;
208 case 2: return TFETCH6_2_BYTE;
209 case 4: return TFETCH6_4_BYTE;
210 case 8: return TFETCH6_8_BYTE;
211 case 16: return TFETCH6_16_BYTE;
212 default:
213 unreachable("bad block size");
214 }
215 }
216
217 static uint32_t
218 tu6_texswiz(const VkComponentMapping *comps, const unsigned char *fmt_swiz)
219 {
220 unsigned char swiz[4] = {comps->r, comps->g, comps->b, comps->a};
221 unsigned char vk_swizzle[] = {
222 [VK_COMPONENT_SWIZZLE_ZERO] = A6XX_TEX_ZERO,
223 [VK_COMPONENT_SWIZZLE_ONE] = A6XX_TEX_ONE,
224 [VK_COMPONENT_SWIZZLE_R] = A6XX_TEX_X,
225 [VK_COMPONENT_SWIZZLE_G] = A6XX_TEX_Y,
226 [VK_COMPONENT_SWIZZLE_B] = A6XX_TEX_Z,
227 [VK_COMPONENT_SWIZZLE_A] = A6XX_TEX_W,
228 };
229 for (unsigned i = 0; i < 4; i++) {
230 swiz[i] = (swiz[i] == VK_COMPONENT_SWIZZLE_IDENTITY) ? i : vk_swizzle[swiz[i]];
231 /* if format has 0/1 in channel, use that (needed for bc1_rgb) */
232 if (swiz[i] < 4) {
233 switch (fmt_swiz[swiz[i]]) {
234 case VK_SWIZZLE_0: swiz[i] = A6XX_TEX_ZERO; break;
235 case VK_SWIZZLE_1: swiz[i] = A6XX_TEX_ONE; break;
236 }
237 }
238 }
239
240 return A6XX_TEX_CONST_0_SWIZ_X(swiz[0]) |
241 A6XX_TEX_CONST_0_SWIZ_Y(swiz[1]) |
242 A6XX_TEX_CONST_0_SWIZ_Z(swiz[2]) |
243 A6XX_TEX_CONST_0_SWIZ_W(swiz[3]);
244 }
245
246 static enum a6xx_tex_type
247 tu6_tex_type(VkImageViewType type)
248 {
249 switch (type) {
250 default:
251 case VK_IMAGE_VIEW_TYPE_1D:
252 case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
253 return A6XX_TEX_1D;
254 case VK_IMAGE_VIEW_TYPE_2D:
255 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
256 return A6XX_TEX_2D;
257 case VK_IMAGE_VIEW_TYPE_3D:
258 return A6XX_TEX_3D;
259 case VK_IMAGE_VIEW_TYPE_CUBE:
260 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
261 return A6XX_TEX_CUBE;
262 }
263 }
264
265 void
266 tu_image_view_init(struct tu_image_view *iview,
267 struct tu_device *device,
268 const VkImageViewCreateInfo *pCreateInfo)
269 {
270 TU_FROM_HANDLE(tu_image, image, pCreateInfo->image);
271 const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange;
272
273 switch (image->type) {
274 case VK_IMAGE_TYPE_1D:
275 case VK_IMAGE_TYPE_2D:
276 assert(range->baseArrayLayer + tu_get_layerCount(image, range) <=
277 image->layer_count);
278 break;
279 case VK_IMAGE_TYPE_3D:
280 assert(range->baseArrayLayer + tu_get_layerCount(image, range) <=
281 tu_minify(image->extent.depth, range->baseMipLevel));
282 break;
283 default:
284 unreachable("bad VkImageType");
285 }
286
287 iview->image = image;
288 iview->type = pCreateInfo->viewType;
289 iview->vk_format = pCreateInfo->format;
290 iview->aspect_mask = pCreateInfo->subresourceRange.aspectMask;
291
292 if (iview->aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) {
293 iview->vk_format = vk_format_stencil_only(iview->vk_format);
294 } else if (iview->aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT) {
295 iview->vk_format = vk_format_depth_only(iview->vk_format);
296 }
297
298 // should we minify?
299 iview->extent = image->extent;
300
301 iview->base_layer = range->baseArrayLayer;
302 iview->layer_count = tu_get_layerCount(image, range);
303 iview->base_mip = range->baseMipLevel;
304 iview->level_count = tu_get_levelCount(image, range);
305
306 memset(iview->descriptor, 0, sizeof(iview->descriptor));
307
308 const struct tu_native_format *fmt = tu6_get_native_format(iview->vk_format);
309 struct tu_image_level *slice0 = &image->levels[iview->base_mip];
310 uint64_t base_addr = image->bo->iova + iview->base_layer * image->layer_size + slice0->offset;
311 uint32_t pitch = (slice0->pitch / vk_format_get_blockwidth(iview->vk_format)) *
312 vk_format_get_blocksize(iview->vk_format);
313 enum a6xx_tile_mode tile_mode =
314 image_level_linear(image, iview->base_mip) ? TILE6_LINEAR : image->tile_mode;
315
316 iview->descriptor[0] =
317 A6XX_TEX_CONST_0_TILE_MODE(tile_mode) |
318 COND(vk_format_is_srgb(iview->vk_format), A6XX_TEX_CONST_0_SRGB) |
319 A6XX_TEX_CONST_0_FMT(fmt->tex) |
320 A6XX_TEX_CONST_0_SAMPLES(0) |
321 A6XX_TEX_CONST_0_SWAP(image->tile_mode ? WZYX : fmt->swap) |
322 tu6_texswiz(&pCreateInfo->components, vk_format_description(iview->vk_format)->swizzle) |
323 A6XX_TEX_CONST_0_MIPLVLS(iview->level_count - 1);
324 iview->descriptor[1] =
325 A6XX_TEX_CONST_1_WIDTH(u_minify(image->extent.width, iview->base_mip)) |
326 A6XX_TEX_CONST_1_HEIGHT(u_minify(image->extent.height, iview->base_mip));
327 iview->descriptor[2] =
328 A6XX_TEX_CONST_2_FETCHSIZE(tu6_fetchsize(iview->vk_format)) |
329 A6XX_TEX_CONST_2_PITCH(pitch) |
330 A6XX_TEX_CONST_2_TYPE(tu6_tex_type(pCreateInfo->viewType));
331 iview->descriptor[3] = 0;
332 iview->descriptor[4] = base_addr;
333 iview->descriptor[5] = base_addr >> 32;
334
335 if (pCreateInfo->viewType != VK_IMAGE_VIEW_TYPE_3D) {
336 iview->descriptor[3] |= A6XX_TEX_CONST_3_ARRAY_PITCH(image->layer_size);
337 iview->descriptor[5] |= A6XX_TEX_CONST_5_DEPTH(iview->layer_count);
338 } else {
339 iview->descriptor[3] |=
340 A6XX_TEX_CONST_3_MIN_LAYERSZ(image->levels[image->level_count - 1].size) |
341 A6XX_TEX_CONST_3_ARRAY_PITCH(slice0->size);
342 iview->descriptor[5] |=
343 A6XX_TEX_CONST_5_DEPTH(u_minify(image->extent.depth, iview->base_mip));
344 }
345 }
346
347 unsigned
348 tu_image_queue_family_mask(const struct tu_image *image,
349 uint32_t family,
350 uint32_t queue_family)
351 {
352 if (!image->exclusive)
353 return image->queue_family_mask;
354 if (family == VK_QUEUE_FAMILY_EXTERNAL)
355 return (1u << TU_MAX_QUEUE_FAMILIES) - 1u;
356 if (family == VK_QUEUE_FAMILY_IGNORED)
357 return 1u << queue_family;
358 return 1u << family;
359 }
360
361 VkResult
362 tu_CreateImage(VkDevice device,
363 const VkImageCreateInfo *pCreateInfo,
364 const VkAllocationCallbacks *pAllocator,
365 VkImage *pImage)
366 {
367 #ifdef ANDROID
368 const VkNativeBufferANDROID *gralloc_info =
369 vk_find_struct_const(pCreateInfo->pNext, NATIVE_BUFFER_ANDROID);
370
371 if (gralloc_info)
372 return tu_image_from_gralloc(device, pCreateInfo, gralloc_info,
373 pAllocator, pImage);
374 #endif
375
376 const struct wsi_image_create_info *wsi_info =
377 vk_find_struct_const(pCreateInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA);
378 bool scanout = wsi_info && wsi_info->scanout;
379
380 return tu_image_create(device,
381 &(struct tu_image_create_info) {
382 .vk_info = pCreateInfo,
383 .scanout = scanout,
384 },
385 pAllocator, pImage);
386 }
387
388 void
389 tu_DestroyImage(VkDevice _device,
390 VkImage _image,
391 const VkAllocationCallbacks *pAllocator)
392 {
393 TU_FROM_HANDLE(tu_device, device, _device);
394 TU_FROM_HANDLE(tu_image, image, _image);
395
396 if (!image)
397 return;
398
399 if (image->owned_memory != VK_NULL_HANDLE)
400 tu_FreeMemory(_device, image->owned_memory, pAllocator);
401
402 vk_free2(&device->alloc, pAllocator, image);
403 }
404
405 void
406 tu_GetImageSubresourceLayout(VkDevice _device,
407 VkImage _image,
408 const VkImageSubresource *pSubresource,
409 VkSubresourceLayout *pLayout)
410 {
411 TU_FROM_HANDLE(tu_image, image, _image);
412
413 const uint32_t layer_offset = image->layer_size * pSubresource->arrayLayer;
414 const struct tu_image_level *level =
415 image->levels + pSubresource->mipLevel;
416
417 pLayout->offset = layer_offset + level->offset;
418 pLayout->size = level->size;
419 pLayout->rowPitch =
420 level->pitch * vk_format_get_blocksize(image->vk_format);
421 pLayout->arrayPitch = image->layer_size;
422 pLayout->depthPitch = level->size;
423 }
424
425 VkResult
426 tu_CreateImageView(VkDevice _device,
427 const VkImageViewCreateInfo *pCreateInfo,
428 const VkAllocationCallbacks *pAllocator,
429 VkImageView *pView)
430 {
431 TU_FROM_HANDLE(tu_device, device, _device);
432 struct tu_image_view *view;
433
434 view = vk_alloc2(&device->alloc, pAllocator, sizeof(*view), 8,
435 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
436 if (view == NULL)
437 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
438
439 tu_image_view_init(view, device, pCreateInfo);
440
441 *pView = tu_image_view_to_handle(view);
442
443 return VK_SUCCESS;
444 }
445
446 void
447 tu_DestroyImageView(VkDevice _device,
448 VkImageView _iview,
449 const VkAllocationCallbacks *pAllocator)
450 {
451 TU_FROM_HANDLE(tu_device, device, _device);
452 TU_FROM_HANDLE(tu_image_view, iview, _iview);
453
454 if (!iview)
455 return;
456 vk_free2(&device->alloc, pAllocator, iview);
457 }
458
459 void
460 tu_buffer_view_init(struct tu_buffer_view *view,
461 struct tu_device *device,
462 const VkBufferViewCreateInfo *pCreateInfo)
463 {
464 TU_FROM_HANDLE(tu_buffer, buffer, pCreateInfo->buffer);
465
466 view->range = pCreateInfo->range == VK_WHOLE_SIZE
467 ? buffer->size - pCreateInfo->offset
468 : pCreateInfo->range;
469 view->vk_format = pCreateInfo->format;
470 }
471
472 VkResult
473 tu_CreateBufferView(VkDevice _device,
474 const VkBufferViewCreateInfo *pCreateInfo,
475 const VkAllocationCallbacks *pAllocator,
476 VkBufferView *pView)
477 {
478 TU_FROM_HANDLE(tu_device, device, _device);
479 struct tu_buffer_view *view;
480
481 view = vk_alloc2(&device->alloc, pAllocator, sizeof(*view), 8,
482 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
483 if (!view)
484 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
485
486 tu_buffer_view_init(view, device, pCreateInfo);
487
488 *pView = tu_buffer_view_to_handle(view);
489
490 return VK_SUCCESS;
491 }
492
493 void
494 tu_DestroyBufferView(VkDevice _device,
495 VkBufferView bufferView,
496 const VkAllocationCallbacks *pAllocator)
497 {
498 TU_FROM_HANDLE(tu_device, device, _device);
499 TU_FROM_HANDLE(tu_buffer_view, view, bufferView);
500
501 if (!view)
502 return;
503
504 vk_free2(&device->alloc, pAllocator, view);
505 }