1/*
2 * Copyright © 2019 Red Hat.
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include "lvp_private.h"
25#include "util/format/u_format.h"
26#include "util/u_inlines.h"
27#include "pipe/p_state.h"
28
29static VkResult
30lvp_image_create(VkDevice _device,
31                 const VkImageCreateInfo *pCreateInfo,
32                 const VkAllocationCallbacks* alloc,
33                 VkImage *pImage)
34{
35   LVP_FROM_HANDLE(lvp_device, device, _device);
36   struct lvp_image *image;
37
38   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
39
40   image = vk_image_create(&device->vk, pCreateInfo, alloc, sizeof(*image));
41   if (image == NULL)
42      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
43
44   image->alignment = 16;
45   {
46      struct pipe_resource template;
47
48      memset(&template, 0, sizeof(template));
49
50      template.screen = device->pscreen;
51      switch (pCreateInfo->imageType) {
52      case VK_IMAGE_TYPE_1D:
53         template.target = pCreateInfo->arrayLayers > 1 ? PIPE_TEXTURE_1D_ARRAY : PIPE_TEXTURE_1D;
54         break;
55      default:
56      case VK_IMAGE_TYPE_2D:
57         template.target = pCreateInfo->arrayLayers > 1 ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
58         break;
59      case VK_IMAGE_TYPE_3D:
60         template.target = PIPE_TEXTURE_3D;
61         break;
62      }
63
64      template.format = lvp_vk_format_to_pipe_format(pCreateInfo->format);
65
66      bool is_ds = util_format_is_depth_or_stencil(template.format);
67
68      if (pCreateInfo->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
69         template.bind |= PIPE_BIND_RENDER_TARGET;
70         /* sampler view is needed for resolve blits */
71         if (pCreateInfo->samples > 1)
72            template.bind |= PIPE_BIND_SAMPLER_VIEW;
73      }
74
75      if (pCreateInfo->usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
76         if (!is_ds)
77            template.bind |= PIPE_BIND_RENDER_TARGET;
78         else
79            template.bind |= PIPE_BIND_DEPTH_STENCIL;
80      }
81
82      if (pCreateInfo->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
83         template.bind |= PIPE_BIND_DEPTH_STENCIL;
84
85      if (pCreateInfo->usage & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
86                                VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))
87         template.bind |= PIPE_BIND_SAMPLER_VIEW;
88
89      if (pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT)
90         template.bind |= PIPE_BIND_SHADER_IMAGE;
91
92      template.width0 = pCreateInfo->extent.width;
93      template.height0 = pCreateInfo->extent.height;
94      template.depth0 = pCreateInfo->extent.depth;
95      template.array_size = pCreateInfo->arrayLayers;
96      template.last_level = pCreateInfo->mipLevels - 1;
97      template.nr_samples = pCreateInfo->samples;
98      template.nr_storage_samples = pCreateInfo->samples;
99      image->bo = device->pscreen->resource_create_unbacked(device->pscreen,
100                                                            &template,
101                                                            &image->size);
102      if (!image->bo)
103         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
104   }
105   *pImage = lvp_image_to_handle(image);
106
107   return VK_SUCCESS;
108}
109
110struct lvp_image *
111lvp_swapchain_get_image(VkSwapchainKHR swapchain,
112                        uint32_t index)
113{
114   uint32_t n_images = index + 1;
115   VkImage *images = malloc(sizeof(*images) * n_images);
116   VkResult result = wsi_common_get_images(swapchain, &n_images, images);
117
118   if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
119      free(images);
120      return NULL;
121   }
122
123   LVP_FROM_HANDLE(lvp_image, image, images[index]);
124   free(images);
125
126   return image;
127}
128
129static VkResult
130lvp_image_from_swapchain(VkDevice device,
131                         const VkImageCreateInfo *pCreateInfo,
132                         const VkImageSwapchainCreateInfoKHR *swapchain_info,
133                         const VkAllocationCallbacks *pAllocator,
134                         VkImage *pImage)
135{
136   ASSERTED struct lvp_image *swapchain_image = lvp_swapchain_get_image(swapchain_info->swapchain, 0);
137   assert(swapchain_image);
138
139   assert(swapchain_image->vk.image_type == pCreateInfo->imageType);
140
141   VkImageCreateInfo local_create_info;
142   local_create_info = *pCreateInfo;
143   local_create_info.pNext = NULL;
144   /* The following parameters are implictly selected by the wsi code. */
145   local_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
146   local_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
147   local_create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
148
149   assert(!(local_create_info.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT));
150   return lvp_image_create(device, &local_create_info, pAllocator,
151                           pImage);
152}
153
154VKAPI_ATTR VkResult VKAPI_CALL
155lvp_CreateImage(VkDevice device,
156                const VkImageCreateInfo *pCreateInfo,
157                const VkAllocationCallbacks *pAllocator,
158                VkImage *pImage)
159{
160   const VkImageSwapchainCreateInfoKHR *swapchain_info =
161      vk_find_struct_const(pCreateInfo->pNext, IMAGE_SWAPCHAIN_CREATE_INFO_KHR);
162   if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE)
163      return lvp_image_from_swapchain(device, pCreateInfo, swapchain_info,
164                                      pAllocator, pImage);
165   return lvp_image_create(device, pCreateInfo, pAllocator,
166                           pImage);
167}
168
169VKAPI_ATTR void VKAPI_CALL
170lvp_DestroyImage(VkDevice _device, VkImage _image,
171                 const VkAllocationCallbacks *pAllocator)
172{
173   LVP_FROM_HANDLE(lvp_device, device, _device);
174   LVP_FROM_HANDLE(lvp_image, image, _image);
175
176   if (!_image)
177     return;
178   pipe_resource_reference(&image->bo, NULL);
179   vk_image_destroy(&device->vk, pAllocator, &image->vk);
180}
181
182VKAPI_ATTR VkResult VKAPI_CALL
183lvp_CreateImageView(VkDevice _device,
184                    const VkImageViewCreateInfo *pCreateInfo,
185                    const VkAllocationCallbacks *pAllocator,
186                    VkImageView *pView)
187{
188   LVP_FROM_HANDLE(lvp_device, device, _device);
189   LVP_FROM_HANDLE(lvp_image, image, pCreateInfo->image);
190   struct lvp_image_view *view;
191
192   view = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*view), 8,
193                     VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
194   if (view == NULL)
195      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
196
197   vk_object_base_init(&device->vk, &view->base,
198                       VK_OBJECT_TYPE_IMAGE_VIEW);
199   view->view_type = pCreateInfo->viewType;
200   view->format = pCreateInfo->format;
201   view->pformat = lvp_vk_format_to_pipe_format(pCreateInfo->format);
202   view->components = pCreateInfo->components;
203   view->subresourceRange = pCreateInfo->subresourceRange;
204   view->image = image;
205   view->surface = NULL;
206   *pView = lvp_image_view_to_handle(view);
207
208   return VK_SUCCESS;
209}
210
211VKAPI_ATTR void VKAPI_CALL
212lvp_DestroyImageView(VkDevice _device, VkImageView _iview,
213                     const VkAllocationCallbacks *pAllocator)
214{
215   LVP_FROM_HANDLE(lvp_device, device, _device);
216   LVP_FROM_HANDLE(lvp_image_view, iview, _iview);
217
218   if (!_iview)
219     return;
220
221   pipe_surface_reference(&iview->surface, NULL);
222   vk_object_base_finish(&iview->base);
223   vk_free2(&device->vk.alloc, pAllocator, iview);
224}
225
226VKAPI_ATTR void VKAPI_CALL lvp_GetImageSubresourceLayout(
227    VkDevice                                    _device,
228    VkImage                                     _image,
229    const VkImageSubresource*                   pSubresource,
230    VkSubresourceLayout*                        pLayout)
231{
232   LVP_FROM_HANDLE(lvp_device, device, _device);
233   LVP_FROM_HANDLE(lvp_image, image, _image);
234   uint64_t value;
235
236   device->pscreen->resource_get_param(device->pscreen,
237                                       NULL,
238                                       image->bo,
239                                       0,
240                                       pSubresource->arrayLayer,
241                                       pSubresource->mipLevel,
242                                       PIPE_RESOURCE_PARAM_STRIDE,
243                                       0, &value);
244
245   pLayout->rowPitch = value;
246
247   device->pscreen->resource_get_param(device->pscreen,
248                                       NULL,
249                                       image->bo,
250                                       0,
251                                       pSubresource->arrayLayer,
252                                       pSubresource->mipLevel,
253                                       PIPE_RESOURCE_PARAM_OFFSET,
254                                       0, &value);
255
256   pLayout->offset = value;
257
258   device->pscreen->resource_get_param(device->pscreen,
259                                       NULL,
260                                       image->bo,
261                                       0,
262                                       pSubresource->arrayLayer,
263                                       pSubresource->mipLevel,
264                                       PIPE_RESOURCE_PARAM_LAYER_STRIDE,
265                                       0, &value);
266
267   if (image->bo->target == PIPE_TEXTURE_3D) {
268      pLayout->depthPitch = value;
269      pLayout->arrayPitch = 0;
270   } else {
271      pLayout->depthPitch = 0;
272      pLayout->arrayPitch = value;
273   }
274   pLayout->size = image->size;
275
276   switch (pSubresource->aspectMask) {
277   case VK_IMAGE_ASPECT_COLOR_BIT:
278      break;
279   case VK_IMAGE_ASPECT_DEPTH_BIT:
280      break;
281   case VK_IMAGE_ASPECT_STENCIL_BIT:
282      break;
283   default:
284      assert(!"Invalid image aspect");
285   }
286}
287
288VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateBuffer(
289    VkDevice                                    _device,
290    const VkBufferCreateInfo*                   pCreateInfo,
291    const VkAllocationCallbacks*                pAllocator,
292    VkBuffer*                                   pBuffer)
293{
294   LVP_FROM_HANDLE(lvp_device, device, _device);
295   struct lvp_buffer *buffer;
296
297   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
298
299   /* gallium has max 32-bit buffer sizes */
300   if (pCreateInfo->size > UINT32_MAX)
301      return VK_ERROR_OUT_OF_DEVICE_MEMORY;
302
303   buffer = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*buffer), 8,
304                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
305   if (buffer == NULL)
306      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
307
308   vk_object_base_init(&device->vk, &buffer->base, VK_OBJECT_TYPE_BUFFER);
309   buffer->size = pCreateInfo->size;
310   buffer->usage = pCreateInfo->usage;
311   buffer->offset = 0;
312
313   {
314      struct pipe_resource template;
315      memset(&template, 0, sizeof(struct pipe_resource));
316
317      if (pCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
318         template.bind |= PIPE_BIND_CONSTANT_BUFFER;
319
320      template.screen = device->pscreen;
321      template.target = PIPE_BUFFER;
322      template.format = PIPE_FORMAT_R8_UNORM;
323      template.width0 = buffer->size;
324      template.height0 = 1;
325      template.depth0 = 1;
326      template.array_size = 1;
327      if (buffer->usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)
328         template.bind |= PIPE_BIND_SAMPLER_VIEW;
329      if (buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
330         template.bind |= PIPE_BIND_SHADER_BUFFER;
331      if (buffer->usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)
332         template.bind |= PIPE_BIND_SHADER_IMAGE;
333      template.flags = PIPE_RESOURCE_FLAG_DONT_OVER_ALLOCATE;
334      buffer->bo = device->pscreen->resource_create_unbacked(device->pscreen,
335                                                             &template,
336                                                             &buffer->total_size);
337      if (!buffer->bo) {
338         vk_free2(&device->vk.alloc, pAllocator, buffer);
339         return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
340      }
341   }
342   *pBuffer = lvp_buffer_to_handle(buffer);
343
344   return VK_SUCCESS;
345}
346
347VKAPI_ATTR void VKAPI_CALL lvp_DestroyBuffer(
348    VkDevice                                    _device,
349    VkBuffer                                    _buffer,
350    const VkAllocationCallbacks*                pAllocator)
351{
352   LVP_FROM_HANDLE(lvp_device, device, _device);
353   LVP_FROM_HANDLE(lvp_buffer, buffer, _buffer);
354
355   if (!_buffer)
356     return;
357
358   pipe_resource_reference(&buffer->bo, NULL);
359   vk_object_base_finish(&buffer->base);
360   vk_free2(&device->vk.alloc, pAllocator, buffer);
361}
362
363VKAPI_ATTR VkDeviceAddress VKAPI_CALL lvp_GetBufferDeviceAddress(
364   VkDevice                                    device,
365   const VkBufferDeviceAddressInfoKHR*         pInfo)
366{
367   LVP_FROM_HANDLE(lvp_buffer, buffer, pInfo->buffer);
368
369   return (VkDeviceAddress)(uintptr_t)buffer->pmem;
370}
371
372VKAPI_ATTR uint64_t VKAPI_CALL lvp_GetBufferOpaqueCaptureAddress(
373    VkDevice                                    device,
374    const VkBufferDeviceAddressInfoKHR*         pInfo)
375{
376   return 0;
377}
378
379VKAPI_ATTR uint64_t VKAPI_CALL lvp_GetDeviceMemoryOpaqueCaptureAddress(
380    VkDevice                                    device,
381    const VkDeviceMemoryOpaqueCaptureAddressInfoKHR* pInfo)
382{
383   return 0;
384}
385
386VKAPI_ATTR VkResult VKAPI_CALL
387lvp_CreateBufferView(VkDevice _device,
388                     const VkBufferViewCreateInfo *pCreateInfo,
389                     const VkAllocationCallbacks *pAllocator,
390                     VkBufferView *pView)
391{
392   LVP_FROM_HANDLE(lvp_device, device, _device);
393   LVP_FROM_HANDLE(lvp_buffer, buffer, pCreateInfo->buffer);
394   struct lvp_buffer_view *view;
395   view = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*view), 8,
396                     VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
397   if (!view)
398      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
399
400   vk_object_base_init(&device->vk, &view->base,
401                       VK_OBJECT_TYPE_BUFFER_VIEW);
402   view->buffer = buffer;
403   view->format = pCreateInfo->format;
404   view->pformat = lvp_vk_format_to_pipe_format(pCreateInfo->format);
405   view->offset = pCreateInfo->offset;
406   view->range = pCreateInfo->range;
407   *pView = lvp_buffer_view_to_handle(view);
408
409   return VK_SUCCESS;
410}
411
412VKAPI_ATTR void VKAPI_CALL
413lvp_DestroyBufferView(VkDevice _device, VkBufferView bufferView,
414                      const VkAllocationCallbacks *pAllocator)
415{
416   LVP_FROM_HANDLE(lvp_device, device, _device);
417   LVP_FROM_HANDLE(lvp_buffer_view, view, bufferView);
418
419   if (!bufferView)
420     return;
421   vk_object_base_finish(&view->base);
422   vk_free2(&device->vk.alloc, pAllocator, view);
423}
424