/* * Copyright 2019 Google LLC * SPDX-License-Identifier: MIT * * based in part on anv and radv which are: * Copyright © 2015 Intel Corporation * Copyright © 2016 Red Hat. * Copyright © 2016 Bas Nieuwenhuizen */ #include "vn_image.h" #include "venus-protocol/vn_protocol_driver_image.h" #include "venus-protocol/vn_protocol_driver_image_view.h" #include "venus-protocol/vn_protocol_driver_sampler.h" #include "venus-protocol/vn_protocol_driver_sampler_ycbcr_conversion.h" #include "vn_android.h" #include "vn_device.h" #include "vn_device_memory.h" #include "vn_wsi.h" static void vn_image_init_memory_requirements(struct vn_image *img, struct vn_device *dev, const VkImageCreateInfo *create_info) { uint32_t plane_count = 1; if (create_info->flags & VK_IMAGE_CREATE_DISJOINT_BIT) { /* TODO VkDrmFormatModifierPropertiesEXT::drmFormatModifierPlaneCount */ assert(create_info->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT); switch (create_info->format) { case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: plane_count = 2; break; case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: plane_count = 3; break; default: plane_count = 1; break; } } assert(plane_count <= ARRAY_SIZE(img->requirements)); /* TODO add a per-device cache for the requirements */ for (uint32_t i = 0; i < plane_count; i++) { img->requirements[i].memory.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; img->requirements[i].memory.pNext = &img->requirements[i].dedicated; img->requirements[i].dedicated.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS; img->requirements[i].dedicated.pNext = NULL; } VkDevice dev_handle = vn_device_to_handle(dev); VkImage img_handle = vn_image_to_handle(img); if (plane_count == 1) { vn_call_vkGetImageMemoryRequirements2( dev->instance, dev_handle, &(VkImageMemoryRequirementsInfo2){ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, .image = img_handle, }, &img->requirements[0].memory); /* AHB backed image requires dedicated allocation */ if (img->deferred_info) { img->requirements[0].dedicated.prefersDedicatedAllocation = VK_TRUE; img->requirements[0].dedicated.requiresDedicatedAllocation = VK_TRUE; } } else { for (uint32_t i = 0; i < plane_count; i++) { vn_call_vkGetImageMemoryRequirements2( dev->instance, dev_handle, &(VkImageMemoryRequirementsInfo2){ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, .pNext = &(VkImagePlaneMemoryRequirementsInfo){ .sType = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, .planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT << i, }, .image = img_handle, }, &img->requirements[i].memory); } } } static VkResult vn_image_deferred_info_init(struct vn_image *img, const VkImageCreateInfo *create_info, const VkAllocationCallbacks *alloc) { struct vn_image_create_deferred_info *info = NULL; VkBaseOutStructure *dst = NULL; info = vk_zalloc(alloc, sizeof(*info), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!info) return VK_ERROR_OUT_OF_HOST_MEMORY; info->create = *create_info; dst = (void *)&info->create; vk_foreach_struct_const(src, create_info->pNext) { void *pnext = NULL; switch (src->sType) { case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: { /* 12.3. Images * * If viewFormatCount is zero, pViewFormats is ignored and the image * is created as if the VkImageFormatListCreateInfo structure were * not included in the pNext chain of VkImageCreateInfo. */ if (!((const VkImageFormatListCreateInfo *)src)->viewFormatCount) break; memcpy(&info->list, src, sizeof(info->list)); pnext = &info->list; /* need a deep copy for view formats array */ const size_t size = sizeof(VkFormat) * info->list.viewFormatCount; VkFormat *view_formats = vk_zalloc( alloc, size, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!view_formats) { vk_free(alloc, info); return VK_ERROR_OUT_OF_HOST_MEMORY; } memcpy(view_formats, ((const VkImageFormatListCreateInfo *)src)->pViewFormats, size); info->list.pViewFormats = view_formats; } break; case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO: memcpy(&info->stencil, src, sizeof(info->stencil)); pnext = &info->stencil; break; case VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID: /* we should have translated the external format */ assert(create_info->format != VK_FORMAT_UNDEFINED); info->from_external_format = ((const VkExternalFormatANDROID *)src)->externalFormat; break; default: break; } if (pnext) { dst->pNext = pnext; dst = pnext; } } dst->pNext = NULL; img->deferred_info = info; return VK_SUCCESS; } static void vn_image_deferred_info_fini(struct vn_image *img, const VkAllocationCallbacks *alloc) { if (!img->deferred_info) return; if (img->deferred_info->list.pViewFormats) vk_free(alloc, (void *)img->deferred_info->list.pViewFormats); vk_free(alloc, img->deferred_info); } static VkResult vn_image_init(struct vn_device *dev, const VkImageCreateInfo *create_info, struct vn_image *img) { VkDevice device = vn_device_to_handle(dev); VkImage image = vn_image_to_handle(img); VkResult result = VK_SUCCESS; img->sharing_mode = create_info->sharingMode; /* TODO async */ result = vn_call_vkCreateImage(dev->instance, device, create_info, NULL, &image); if (result != VK_SUCCESS) return result; vn_image_init_memory_requirements(img, dev, create_info); return VK_SUCCESS; } VkResult vn_image_create(struct vn_device *dev, const VkImageCreateInfo *create_info, const VkAllocationCallbacks *alloc, struct vn_image **out_img) { struct vn_image *img = NULL; VkResult result = VK_SUCCESS; img = vk_zalloc(alloc, sizeof(*img), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!img) return VK_ERROR_OUT_OF_HOST_MEMORY; vn_object_base_init(&img->base, VK_OBJECT_TYPE_IMAGE, &dev->base); result = vn_image_init(dev, create_info, img); if (result != VK_SUCCESS) { vn_object_base_fini(&img->base); vk_free(alloc, img); return result; } *out_img = img; return VK_SUCCESS; } VkResult vn_image_init_deferred(struct vn_device *dev, const VkImageCreateInfo *create_info, struct vn_image *img) { VkResult result = vn_image_init(dev, create_info, img); img->deferred_info->initialized = result == VK_SUCCESS; return result; } VkResult vn_image_create_deferred(struct vn_device *dev, const VkImageCreateInfo *create_info, const VkAllocationCallbacks *alloc, struct vn_image **out_img) { struct vn_image *img = NULL; VkResult result = VK_SUCCESS; img = vk_zalloc(alloc, sizeof(*img), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!img) return VK_ERROR_OUT_OF_HOST_MEMORY; vn_object_base_init(&img->base, VK_OBJECT_TYPE_IMAGE, &dev->base); result = vn_image_deferred_info_init(img, create_info, alloc); if (result != VK_SUCCESS) { vn_object_base_fini(&img->base); vk_free(alloc, img); return result; } *out_img = img; return VK_SUCCESS; } /* image commands */ VkResult vn_CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) { VN_TRACE_FUNC(); struct vn_device *dev = vn_device_from_handle(device); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; struct vn_image *img; VkResult result; const struct wsi_image_create_info *wsi_info = vn_wsi_find_wsi_image_create_info(pCreateInfo); const VkNativeBufferANDROID *anb_info = vn_android_find_native_buffer(pCreateInfo); const VkExternalMemoryImageCreateInfo *external_info = vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_IMAGE_CREATE_INFO); const bool ahb_info = external_info && external_info->handleTypes == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; #ifdef ANDROID /* VkImageSwapchainCreateInfoKHR is not useful at all */ const VkImageSwapchainCreateInfoKHR *swapchain_info = NULL; #else const VkImageSwapchainCreateInfoKHR *swapchain_info = vk_find_struct_const( pCreateInfo->pNext, IMAGE_SWAPCHAIN_CREATE_INFO_KHR); if (swapchain_info && !swapchain_info->swapchain) swapchain_info = NULL; #endif if (wsi_info) { result = vn_wsi_create_image(dev, pCreateInfo, wsi_info, alloc, &img); } else if (anb_info) { result = vn_android_image_from_anb(dev, pCreateInfo, anb_info, alloc, &img); } else if (ahb_info) { result = vn_android_image_from_ahb(dev, pCreateInfo, alloc, &img); } else if (swapchain_info) { result = vn_wsi_create_image_from_swapchain( dev, pCreateInfo, swapchain_info, alloc, &img); } else { result = vn_image_create(dev, pCreateInfo, alloc, &img); } if (result != VK_SUCCESS) return vn_error(dev->instance, result); *pImage = vn_image_to_handle(img); return VK_SUCCESS; } void vn_DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { VN_TRACE_FUNC(); struct vn_device *dev = vn_device_from_handle(device); struct vn_image *img = vn_image_from_handle(image); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; if (!img) return; if (img->wsi.memory && img->wsi.memory_owned) { VkDeviceMemory mem_handle = vn_device_memory_to_handle(img->wsi.memory); vn_FreeMemory(device, mem_handle, pAllocator); } /* must not ask renderer to destroy uninitialized deferred image */ if (!img->deferred_info || img->deferred_info->initialized) vn_async_vkDestroyImage(dev->instance, device, image, NULL); vn_image_deferred_info_fini(img, alloc); vn_object_base_fini(&img->base); vk_free(alloc, img); } void vn_GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements) { const struct vn_image *img = vn_image_from_handle(pInfo->image); union { VkBaseOutStructure *pnext; VkMemoryRequirements2 *two; VkMemoryDedicatedRequirements *dedicated; } u = { .two = pMemoryRequirements }; uint32_t plane = 0; const VkImagePlaneMemoryRequirementsInfo *plane_info = vk_find_struct_const(pInfo->pNext, IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO); if (plane_info) { switch (plane_info->planeAspect) { case VK_IMAGE_ASPECT_PLANE_1_BIT: plane = 1; break; case VK_IMAGE_ASPECT_PLANE_2_BIT: plane = 2; break; default: plane = 0; break; } } while (u.pnext) { switch (u.pnext->sType) { case VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2: u.two->memoryRequirements = img->requirements[plane].memory.memoryRequirements; break; case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: u.dedicated->prefersDedicatedAllocation = img->requirements[plane].dedicated.prefersDedicatedAllocation; u.dedicated->requiresDedicatedAllocation = img->requirements[plane].dedicated.requiresDedicatedAllocation; break; default: break; } u.pnext = u.pnext->pNext; } } void vn_GetImageSparseMemoryRequirements2( VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements) { struct vn_device *dev = vn_device_from_handle(device); /* TODO per-device cache */ vn_call_vkGetImageSparseMemoryRequirements2(dev->instance, device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); } static void vn_image_bind_wsi_memory(struct vn_image *img, struct vn_device_memory *mem) { assert(img->wsi.is_wsi && !img->wsi.memory); img->wsi.memory = mem; } VkResult vn_BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos) { struct vn_device *dev = vn_device_from_handle(device); const VkAllocationCallbacks *alloc = &dev->base.base.alloc; VkBindImageMemoryInfo *local_infos = NULL; for (uint32_t i = 0; i < bindInfoCount; i++) { const VkBindImageMemoryInfo *info = &pBindInfos[i]; struct vn_image *img = vn_image_from_handle(info->image); struct vn_device_memory *mem = vn_device_memory_from_handle(info->memory); /* no bind info fixup needed */ if (mem && !mem->base_memory) { if (img->wsi.is_wsi) vn_image_bind_wsi_memory(img, mem); continue; } if (!mem) { #ifdef ANDROID /* TODO handle VkNativeBufferANDROID when we bump up * VN_ANDROID_NATIVE_BUFFER_SPEC_VERSION */ unreachable("VkBindImageMemoryInfo with no memory"); #else const VkBindImageMemorySwapchainInfoKHR *swapchain_info = vk_find_struct_const(info->pNext, BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR); assert(img->wsi.is_wsi && swapchain_info); struct vn_image *swapchain_img = vn_image_from_handle(wsi_common_get_image( swapchain_info->swapchain, swapchain_info->imageIndex)); mem = swapchain_img->wsi.memory; #endif } if (img->wsi.is_wsi) vn_image_bind_wsi_memory(img, mem); if (!local_infos) { const size_t size = sizeof(*local_infos) * bindInfoCount; local_infos = vk_alloc(alloc, size, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!local_infos) return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY); memcpy(local_infos, pBindInfos, size); } /* If mem is suballocated, mem->base_memory is non-NULL and we must * patch it in. If VkBindImageMemorySwapchainInfoKHR is given, we've * looked mem up above and also need to patch it in. */ local_infos[i].memory = vn_device_memory_to_handle( mem->base_memory ? mem->base_memory : mem); local_infos[i].memoryOffset += mem->base_offset; } if (local_infos) pBindInfos = local_infos; vn_async_vkBindImageMemory2(dev->instance, device, bindInfoCount, pBindInfos); vk_free(alloc, local_infos); return VK_SUCCESS; } VkResult vn_GetImageDrmFormatModifierPropertiesEXT( VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT *pProperties) { struct vn_device *dev = vn_device_from_handle(device); /* TODO local cache */ return vn_call_vkGetImageDrmFormatModifierPropertiesEXT( dev->instance, device, image, pProperties); } void vn_GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout) { struct vn_device *dev = vn_device_from_handle(device); struct vn_image *img = vn_image_from_handle(image); /* override aspect mask for wsi/ahb images with tiling modifier */ VkImageSubresource local_subresource; if ((img->wsi.is_wsi && img->wsi.tiling_override == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) || img->deferred_info) { VkImageAspectFlags aspect = pSubresource->aspectMask; switch (aspect) { case VK_IMAGE_ASPECT_COLOR_BIT: case VK_IMAGE_ASPECT_DEPTH_BIT: case VK_IMAGE_ASPECT_STENCIL_BIT: case VK_IMAGE_ASPECT_PLANE_0_BIT: aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT; break; case VK_IMAGE_ASPECT_PLANE_1_BIT: aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT; break; case VK_IMAGE_ASPECT_PLANE_2_BIT: aspect = VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT; break; default: break; } /* only handle supported aspect override */ if (aspect != pSubresource->aspectMask) { local_subresource = *pSubresource; local_subresource.aspectMask = aspect; pSubresource = &local_subresource; } } /* TODO local cache */ vn_call_vkGetImageSubresourceLayout(dev->instance, device, image, pSubresource, pLayout); } /* image view commands */ VkResult vn_CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView) { struct vn_device *dev = vn_device_from_handle(device); struct vn_image *img = vn_image_from_handle(pCreateInfo->image); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; VkImageViewCreateInfo local_info; if (img->deferred_info && img->deferred_info->from_external_format) { assert(pCreateInfo->format == VK_FORMAT_UNDEFINED); local_info = *pCreateInfo; local_info.format = img->deferred_info->create.format; pCreateInfo = &local_info; assert(pCreateInfo->format != VK_FORMAT_UNDEFINED); } struct vn_image_view *view = vk_zalloc(alloc, sizeof(*view), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!view) return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY); vn_object_base_init(&view->base, VK_OBJECT_TYPE_IMAGE_VIEW, &dev->base); view->image = img; VkImageView view_handle = vn_image_view_to_handle(view); vn_async_vkCreateImageView(dev->instance, device, pCreateInfo, NULL, &view_handle); *pView = view_handle; return VK_SUCCESS; } void vn_DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) { struct vn_device *dev = vn_device_from_handle(device); struct vn_image_view *view = vn_image_view_from_handle(imageView); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; if (!view) return; vn_async_vkDestroyImageView(dev->instance, device, imageView, NULL); vn_object_base_fini(&view->base); vk_free(alloc, view); } /* sampler commands */ VkResult vn_CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) { struct vn_device *dev = vn_device_from_handle(device); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; struct vn_sampler *sampler = vk_zalloc(alloc, sizeof(*sampler), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!sampler) return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY); vn_object_base_init(&sampler->base, VK_OBJECT_TYPE_SAMPLER, &dev->base); VkSampler sampler_handle = vn_sampler_to_handle(sampler); vn_async_vkCreateSampler(dev->instance, device, pCreateInfo, NULL, &sampler_handle); *pSampler = sampler_handle; return VK_SUCCESS; } void vn_DestroySampler(VkDevice device, VkSampler _sampler, const VkAllocationCallbacks *pAllocator) { struct vn_device *dev = vn_device_from_handle(device); struct vn_sampler *sampler = vn_sampler_from_handle(_sampler); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; if (!sampler) return; vn_async_vkDestroySampler(dev->instance, device, _sampler, NULL); vn_object_base_fini(&sampler->base); vk_free(alloc, sampler); } /* sampler YCbCr conversion commands */ VkResult vn_CreateSamplerYcbcrConversion( VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion) { struct vn_device *dev = vn_device_from_handle(device); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; const VkExternalFormatANDROID *ext_info = vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_FORMAT_ANDROID); VkSamplerYcbcrConversionCreateInfo local_info; if (ext_info && ext_info->externalFormat) { assert(pCreateInfo->format == VK_FORMAT_UNDEFINED); local_info = *pCreateInfo; local_info.format = vn_android_drm_format_to_vk_format(ext_info->externalFormat); local_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; local_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; local_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; local_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; pCreateInfo = &local_info; assert(pCreateInfo->format != VK_FORMAT_UNDEFINED); } struct vn_sampler_ycbcr_conversion *conv = vk_zalloc(alloc, sizeof(*conv), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!conv) return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY); vn_object_base_init(&conv->base, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, &dev->base); VkSamplerYcbcrConversion conv_handle = vn_sampler_ycbcr_conversion_to_handle(conv); vn_async_vkCreateSamplerYcbcrConversion(dev->instance, device, pCreateInfo, NULL, &conv_handle); *pYcbcrConversion = conv_handle; return VK_SUCCESS; } void vn_DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks *pAllocator) { struct vn_device *dev = vn_device_from_handle(device); struct vn_sampler_ycbcr_conversion *conv = vn_sampler_ycbcr_conversion_from_handle(ycbcrConversion); const VkAllocationCallbacks *alloc = pAllocator ? pAllocator : &dev->base.base.alloc; if (!conv) return; vn_async_vkDestroySamplerYcbcrConversion(dev->instance, device, ycbcrConversion, NULL); vn_object_base_fini(&conv->base); vk_free(alloc, conv); } void vn_GetDeviceImageMemoryRequirements( VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements) { struct vn_device *dev = vn_device_from_handle(device); /* TODO per-device cache */ vn_call_vkGetDeviceImageMemoryRequirements(dev->instance, device, pInfo, pMemoryRequirements); } void vn_GetDeviceImageSparseMemoryRequirements( VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements) { struct vn_device *dev = vn_device_from_handle(device); /* TODO per-device cache */ vn_call_vkGetDeviceImageSparseMemoryRequirements( dev->instance, device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); }