turnip: Add image layout calculations.
[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 DEALINGS
25 * IN THE SOFTWARE.
26 */
27
28 #include "tu_private.h"
29 #include "util/debug.h"
30 #include "util/u_atomic.h"
31 #include "vk_format.h"
32 #include "vk_util.h"
33
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: */
43 static const struct {
44 unsigned pitchalign;
45 unsigned heightalign;
46 } tile_alignment[] = {
47 [1] = { 128, 32 },
48 [2] = { 128, 16 },
49 [3] = { 128, 16 },
50 [4] = { 64, 16 },
51 [8] = { 64, 16 },
52 [12] = { 64, 16 },
53 [16] = { 64, 16 },
54 };
55
56 static void
57 setup_slices(struct tu_image *image, const VkImageCreateInfo *pCreateInfo)
58 {
59 enum vk_format_layout layout = vk_format_description(pCreateInfo->format)->layout;
60 uint32_t layer_size = 0;
61 uint32_t width = pCreateInfo->extent.width;
62 uint32_t height = pCreateInfo->extent.height;
63 uint32_t depth = pCreateInfo->extent.depth;
64 bool layer_first = pCreateInfo->imageType != VK_IMAGE_TYPE_3D;
65 uint32_t alignment = pCreateInfo->imageType == VK_IMAGE_TYPE_3D ? 4096 : 1;
66 uint32_t cpp = vk_format_get_blocksize(pCreateInfo->format);
67
68 uint32_t heightalign = tile_alignment[cpp].heightalign;
69
70 for (unsigned level = 0; level < pCreateInfo->mipLevels; level++) {
71 struct tu_image_level *slice = &image->levels[level];
72 bool linear_level = image_level_linear(image, level);
73 uint32_t aligned_height = height;
74 uint32_t blocks;
75 uint32_t pitchalign;
76
77 if (image->tile_mode && !linear_level) {
78 pitchalign = tile_alignment[cpp].pitchalign;
79 aligned_height = align(aligned_height, heightalign);
80 } else {
81 pitchalign = 64;
82
83 /* The blits used for mem<->gmem work at a granularity of
84 * 32x32, which can cause faults due to over-fetch on the
85 * last level. The simple solution is to over-allocate a
86 * bit the last level to ensure any over-fetch is harmless.
87 * The pitch is already sufficiently aligned, but height
88 * may not be:
89 */
90 if ((level + 1 == pCreateInfo->mipLevels))
91 aligned_height = align(aligned_height, 32);
92 }
93
94 if (layout == VK_FORMAT_LAYOUT_ASTC)
95 slice->pitch =
96 util_align_npot(width, pitchalign * vk_format_get_blockwidth(pCreateInfo->format));
97 else
98 slice->pitch = align(width, pitchalign);
99
100 slice->offset = layer_size;
101 blocks = vk_format_get_block_count(pCreateInfo->format, slice->pitch, aligned_height);
102
103 /* 1d array and 2d array textures must all have the same layer size
104 * for each miplevel on a3xx. 3d textures can have different layer
105 * sizes for high levels, but the hw auto-sizer is buggy (or at least
106 * different than what this code does), so as soon as the layer size
107 * range gets into range, we stop reducing it.
108 */
109 if (pCreateInfo->imageType == VK_IMAGE_TYPE_3D && (
110 level == 1 ||
111 (level > 1 && image->levels[level - 1].size > 0xf000)))
112 slice->size = align(blocks * cpp, alignment);
113 else if (level == 0 || layer_first || alignment == 1)
114 slice->size = align(blocks * cpp, alignment);
115 else
116 slice->size = image->levels[level - 1].size;
117
118 layer_size += slice->size * depth;
119
120 width = u_minify(width, 1);
121 height = u_minify(height, 1);
122 depth = u_minify(depth, 1);
123 }
124
125 image->layer_size = layer_size;
126 }
127
128
129 VkResult
130 tu_image_create(VkDevice _device,
131 const struct tu_image_create_info *create_info,
132 const VkAllocationCallbacks *alloc,
133 VkImage *pImage)
134 {
135 TU_FROM_HANDLE(tu_device, device, _device);
136 const VkImageCreateInfo *pCreateInfo = create_info->vk_info;
137 struct tu_image *image = NULL;
138 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
139
140 tu_assert(pCreateInfo->mipLevels > 0);
141 tu_assert(pCreateInfo->arrayLayers > 0);
142 tu_assert(pCreateInfo->samples > 0);
143 tu_assert(pCreateInfo->extent.width > 0);
144 tu_assert(pCreateInfo->extent.height > 0);
145 tu_assert(pCreateInfo->extent.depth > 0);
146
147 image = vk_zalloc2(&device->alloc,
148 alloc,
149 sizeof(*image),
150 8,
151 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
152 if (!image)
153 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
154
155 image->type = pCreateInfo->imageType;
156
157 image->vk_format = pCreateInfo->format;
158 image->tiling = pCreateInfo->tiling;
159 image->usage = pCreateInfo->usage;
160 image->flags = pCreateInfo->flags;
161 image->extent = pCreateInfo->extent;
162
163 image->exclusive = pCreateInfo->sharingMode == VK_SHARING_MODE_EXCLUSIVE;
164 if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) {
165 for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i)
166 if (pCreateInfo->pQueueFamilyIndices[i] ==
167 VK_QUEUE_FAMILY_EXTERNAL_KHR)
168 image->queue_family_mask |= (1u << TU_MAX_QUEUE_FAMILIES) - 1u;
169 else
170 image->queue_family_mask |= 1u
171 << pCreateInfo->pQueueFamilyIndices[i];
172 }
173
174 image->shareable =
175 vk_find_struct_const(pCreateInfo->pNext,
176 EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR) != NULL;
177
178 image->tile_mode = pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ? 3 : 0;
179 setup_slices(image, pCreateInfo);
180
181 image->size = image->layer_size * pCreateInfo->arrayLayers;
182 *pImage = tu_image_to_handle(image);
183
184 return VK_SUCCESS;
185 }
186
187 void
188 tu_image_view_init(struct tu_image_view *iview,
189 struct tu_device *device,
190 const VkImageViewCreateInfo *pCreateInfo)
191 {
192 }
193
194 unsigned
195 tu_image_queue_family_mask(const struct tu_image *image,
196 uint32_t family,
197 uint32_t queue_family)
198 {
199 if (!image->exclusive)
200 return image->queue_family_mask;
201 if (family == VK_QUEUE_FAMILY_EXTERNAL_KHR)
202 return (1u << TU_MAX_QUEUE_FAMILIES) - 1u;
203 if (family == VK_QUEUE_FAMILY_IGNORED)
204 return 1u << queue_family;
205 return 1u << family;
206 }
207
208 VkResult
209 tu_CreateImage(VkDevice device,
210 const VkImageCreateInfo *pCreateInfo,
211 const VkAllocationCallbacks *pAllocator,
212 VkImage *pImage)
213 {
214 #ifdef ANDROID
215 const VkNativeBufferANDROID *gralloc_info =
216 vk_find_struct_const(pCreateInfo->pNext, NATIVE_BUFFER_ANDROID);
217
218 if (gralloc_info)
219 return tu_image_from_gralloc(
220 device, pCreateInfo, gralloc_info, pAllocator, pImage);
221 #endif
222
223 return tu_image_create(device,
224 &(struct tu_image_create_info) {
225 .vk_info = pCreateInfo,
226 .scanout = false,
227 },
228 pAllocator,
229 pImage);
230 }
231
232 void
233 tu_DestroyImage(VkDevice _device,
234 VkImage _image,
235 const VkAllocationCallbacks *pAllocator)
236 {
237 TU_FROM_HANDLE(tu_device, device, _device);
238 TU_FROM_HANDLE(tu_image, image, _image);
239
240 if (!image)
241 return;
242
243 if (image->owned_memory != VK_NULL_HANDLE)
244 tu_FreeMemory(_device, image->owned_memory, pAllocator);
245
246 vk_free2(&device->alloc, pAllocator, image);
247 }
248
249 void
250 tu_GetImageSubresourceLayout(VkDevice _device,
251 VkImage _image,
252 const VkImageSubresource *pSubresource,
253 VkSubresourceLayout *pLayout)
254 {
255 }
256
257 VkResult
258 tu_CreateImageView(VkDevice _device,
259 const VkImageViewCreateInfo *pCreateInfo,
260 const VkAllocationCallbacks *pAllocator,
261 VkImageView *pView)
262 {
263 TU_FROM_HANDLE(tu_device, device, _device);
264 struct tu_image_view *view;
265
266 view = vk_alloc2(&device->alloc,
267 pAllocator,
268 sizeof(*view),
269 8,
270 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
271 if (view == NULL)
272 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
273
274 tu_image_view_init(view, device, pCreateInfo);
275
276 *pView = tu_image_view_to_handle(view);
277
278 return VK_SUCCESS;
279 }
280
281 void
282 tu_DestroyImageView(VkDevice _device,
283 VkImageView _iview,
284 const VkAllocationCallbacks *pAllocator)
285 {
286 TU_FROM_HANDLE(tu_device, device, _device);
287 TU_FROM_HANDLE(tu_image_view, iview, _iview);
288
289 if (!iview)
290 return;
291 vk_free2(&device->alloc, pAllocator, iview);
292 }
293
294 void
295 tu_buffer_view_init(struct tu_buffer_view *view,
296 struct tu_device *device,
297 const VkBufferViewCreateInfo *pCreateInfo)
298 {
299 TU_FROM_HANDLE(tu_buffer, buffer, pCreateInfo->buffer);
300
301 view->range = pCreateInfo->range == VK_WHOLE_SIZE
302 ? buffer->size - pCreateInfo->offset
303 : pCreateInfo->range;
304 view->vk_format = pCreateInfo->format;
305 }
306
307 VkResult
308 tu_CreateBufferView(VkDevice _device,
309 const VkBufferViewCreateInfo *pCreateInfo,
310 const VkAllocationCallbacks *pAllocator,
311 VkBufferView *pView)
312 {
313 TU_FROM_HANDLE(tu_device, device, _device);
314 struct tu_buffer_view *view;
315
316 view = vk_alloc2(&device->alloc,
317 pAllocator,
318 sizeof(*view),
319 8,
320 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
321 if (!view)
322 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
323
324 tu_buffer_view_init(view, device, pCreateInfo);
325
326 *pView = tu_buffer_view_to_handle(view);
327
328 return VK_SUCCESS;
329 }
330
331 void
332 tu_DestroyBufferView(VkDevice _device,
333 VkBufferView bufferView,
334 const VkAllocationCallbacks *pAllocator)
335 {
336 TU_FROM_HANDLE(tu_device, device, _device);
337 TU_FROM_HANDLE(tu_buffer_view, view, bufferView);
338
339 if (!view)
340 return;
341
342 vk_free2(&device->alloc, pAllocator, view);
343 }