| /* |
| * Copyright © 2023 Google, LLC |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| * IN THE SOFTWARE. |
| */ |
| |
| #include "lvp_fuchsia_buffer_collection.h" |
| |
| #include "lvp_fuchsia.h" |
| #include "lvp_fuchsia_memory.h" |
| #include "lvp_private.h" |
| |
| #include "os/fuchsia.h" |
| #include "vk_alloc.h" |
| #include "vk_object.h" |
| #include "vulkan/vulkan_core.h" |
| |
| #include <zircon/syscalls.h> |
| |
| #include <assert.h> |
| |
| #define LVP_LOG_VK_ERROR(ret) \ |
| (ret != 0 ? mesa_loge("%s:%d Returning error %" PRId64, __FILE__, __LINE__, (int64_t)ret), ret : ret) |
| |
| VkResult lvp_fuchsia_get_magma_sysmem_connection(uint64_t* connection_out) |
| { |
| zx_handle_t client_handle = ZX_HANDLE_INVALID; |
| if (!fuchsia_open("/svc/fuchsia.sysmem.Allocator", &client_handle)) { |
| connection_out = 0; |
| return LVP_LOG_VK_ERROR(VK_ERROR_NOT_PERMITTED_KHR); |
| } |
| |
| magma_status_t status = magma_sysmem_connection_import(client_handle, connection_out); |
| if (status != MAGMA_STATUS_OK) { |
| connection_out = 0; |
| return LVP_LOG_VK_ERROR(VK_ERROR_UNKNOWN); |
| } |
| return VK_SUCCESS; |
| } |
| |
| VkResult lvp_CreateBufferCollectionFUCHSIA( |
| VkDevice _device, |
| const VkBufferCollectionCreateInfoFUCHSIA* pCreateInfo, |
| const VkAllocationCallbacks* pAllocator, |
| VkBufferCollectionFUCHSIA* pCollection) |
| { |
| LVP_FROM_HANDLE(lvp_device, device, _device); |
| struct lvp_buffer_collection * bufcol; |
| |
| assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA); |
| |
| magma_sysmem_connection_t sysmem_connection = device->sysmem_connection; |
| if (!sysmem_connection) { |
| return LVP_LOG_VK_ERROR(VK_ERROR_UNKNOWN); |
| } |
| |
| magma_buffer_collection_t magma_buffer_collection; |
| magma_status_t status = magma_sysmem_connection_import_buffer_collection( |
| sysmem_connection, pCreateInfo->collectionToken, &magma_buffer_collection); |
| if (status != MAGMA_STATUS_OK) |
| return LVP_LOG_VK_ERROR(VK_ERROR_INVALID_EXTERNAL_HANDLE); |
| |
| struct lvp_buffer_collection* buffer_collection = |
| vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*buffer_collection), 8, |
| VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); |
| |
| vk_object_base_init(&device->vk, &buffer_collection->base, VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA); |
| |
| buffer_collection->buffer_collection = magma_buffer_collection; |
| buffer_collection->constraints = 0; |
| |
| *pCollection = lvp_buffer_collection_to_handle(buffer_collection); |
| |
| return VK_SUCCESS; |
| } |
| |
| void lvp_DestroyBufferCollectionFUCHSIA( |
| VkDevice vk_device, |
| VkBufferCollectionFUCHSIA vk_collection, |
| const VkAllocationCallbacks* pAllocator) |
| { |
| LVP_FROM_HANDLE(lvp_device, device, vk_device); |
| LVP_FROM_HANDLE(lvp_buffer_collection, buffer_collection, vk_collection); |
| |
| if (!device->sysmem_connection) { |
| mesa_loge("%s:%d lvp_DestroyBufferCollectionFUCHSIA: no sysmem connection.", __FILE__, __LINE__); |
| return; |
| } |
| |
| if (buffer_collection->constraints) { |
| magma_buffer_constraints_release2(buffer_collection->constraints); |
| } |
| |
| magma_buffer_collection_release2(buffer_collection->buffer_collection); |
| vk_free2(&device->vk.alloc, pAllocator, buffer_collection); |
| } |
| |
| static VkFormat sysmem_to_vk_format(uint32_t sysmem_format) |
| { |
| switch (sysmem_format) { |
| case MAGMA_FORMAT_BGRA32: |
| return VK_FORMAT_B8G8R8A8_UNORM; |
| case MAGMA_FORMAT_R8G8B8A8: |
| return VK_FORMAT_R8G8B8A8_UNORM; |
| case MAGMA_FORMAT_NV12: |
| return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; |
| case MAGMA_FORMAT_I420: |
| return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM; |
| case MAGMA_FORMAT_L8: |
| case MAGMA_FORMAT_R8: |
| return VK_FORMAT_R8_UNORM; |
| case MAGMA_FORMAT_R8G8: |
| return VK_FORMAT_R8G8_UNORM; |
| default: |
| return VK_FORMAT_UNDEFINED; |
| } |
| } |
| |
| static VkFormatFeatureFlags |
| get_image_format_features(struct lvp_physical_device *physical_device, VkFormat format, VkImageTiling tiling) |
| { |
| VkFormatProperties3 format_props; |
| lvp_physical_device_get_format_properties(physical_device, format, &format_props); |
| if (tiling == VK_IMAGE_TILING_LINEAR) { |
| return format_props.linearTilingFeatures; |
| } else if (tiling == VK_IMAGE_TILING_OPTIMAL) { |
| return format_props.optimalTilingFeatures; |
| } else { |
| unreachable("unknown VkImageTiling"); |
| return 0; |
| } |
| } |
| |
| VkResult lvp_GetBufferCollectionPropertiesFUCHSIA( |
| VkDevice vk_device, |
| VkBufferCollectionFUCHSIA vk_collection, |
| VkBufferCollectionPropertiesFUCHSIA* pProperties) |
| { |
| LVP_FROM_HANDLE(lvp_device, device, vk_device); |
| LVP_FROM_HANDLE(lvp_buffer_collection, buffer_collection, vk_collection); |
| |
| if (!device->sysmem_connection) |
| return LVP_LOG_VK_ERROR(VK_ERROR_UNKNOWN); |
| |
| magma_collection_info_t collection_info = {0}; |
| magma_status_t status = magma_buffer_collection_get_collection_info( |
| buffer_collection->buffer_collection, |
| &collection_info); |
| if (status != MAGMA_STATUS_OK) |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| |
| uint32_t count = 0; |
| status = magma_collection_info_get_buffer_count(collection_info, &count); |
| if (status != MAGMA_STATUS_OK) { |
| magma_collection_info_release(collection_info); |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| } |
| |
| uint32_t sysmem_format = MAGMA_FORMAT_INVALID; |
| status = magma_collection_info_get_format(collection_info, &sysmem_format); |
| if (status != MAGMA_STATUS_OK) { |
| magma_collection_info_release(collection_info); |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| } |
| |
| pProperties->sysmemPixelFormat = sysmem_format; |
| |
| magma_bool_t has_format_modifier = false; |
| uint64_t format_modifier = 0; |
| status = magma_collection_info_get_format_modifier(collection_info, &has_format_modifier, |
| &format_modifier); |
| if (status != MAGMA_STATUS_OK) { |
| magma_collection_info_release(collection_info); |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| } |
| |
| uint32_t color_space = MAGMA_COLORSPACE_INVALID; |
| magma_collection_info_get_color_space(collection_info, &color_space); |
| // Colorspace may be invalid for non-images, so ignore error. |
| |
| pProperties->sysmemColorSpaceIndex.colorSpace = color_space; |
| pProperties->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_IDENTITY; |
| pProperties->samplerYcbcrConversionComponents.g = VK_COMPONENT_SWIZZLE_IDENTITY; |
| pProperties->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY; |
| pProperties->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY; |
| |
| pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; |
| pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW; |
| pProperties->suggestedXChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; |
| pProperties->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT; |
| |
| switch (color_space) { |
| case MAGMA_COLORSPACE_REC601_NTSC: |
| case MAGMA_COLORSPACE_REC601_PAL: |
| pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601; |
| break; |
| |
| case MAGMA_COLORSPACE_REC601_NTSC_FULL_RANGE: |
| case MAGMA_COLORSPACE_REC601_PAL_FULL_RANGE: |
| pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601; |
| pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; |
| break; |
| |
| case MAGMA_COLORSPACE_REC709: |
| pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709; |
| break; |
| |
| case MAGMA_COLORSPACE_REC2020: |
| pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020; |
| break; |
| |
| case MAGMA_COLORSPACE_SRGB: |
| pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; |
| pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; |
| break; |
| |
| default: |
| pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; |
| pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; |
| break; |
| } |
| |
| pProperties->createInfoIndex = 0; |
| |
| if (buffer_collection->constraints) { |
| magma_bool_t format_valid[MAX_BUFFER_COLLECTION_FORMAT_INDICES]; |
| status = magma_collection_info_get_format_index( |
| collection_info, buffer_collection->constraints, format_valid, |
| MAX_BUFFER_COLLECTION_FORMAT_INDICES); |
| if (status != MAGMA_STATUS_OK) { |
| magma_collection_info_release(collection_info); |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| } |
| |
| // Choose the first valid format for now. |
| for (uint32_t i = 0; i < MAX_BUFFER_COLLECTION_FORMAT_INDICES; i++) { |
| if (format_valid[i]) { |
| pProperties->createInfoIndex = buffer_collection->format_index_input_index_map[i]; |
| break; |
| } |
| } |
| } |
| |
| if (!has_format_modifier) { |
| format_modifier = MAGMA_FORMAT_MODIFIER_LINEAR; |
| } |
| |
| { |
| VkFormat format = sysmem_to_vk_format(sysmem_format); |
| const struct lvp_physical_device* physical_device = device->physical_device; |
| if (format_modifier == MAGMA_FORMAT_MODIFIER_LINEAR) { |
| pProperties->formatFeatures = get_image_format_features(physical_device, |
| format, |
| VK_IMAGE_TILING_LINEAR); |
| } else { |
| pProperties->formatFeatures = get_image_format_features(physical_device, |
| format, |
| VK_IMAGE_TILING_OPTIMAL); |
| } |
| } |
| |
| magma_collection_info_release(collection_info); |
| |
| pProperties->bufferCount = count; |
| |
| if (pProperties->bufferCount < 1) { |
| pProperties->memoryTypeBits = 0u; |
| } else { |
| struct lvp_physical_device* pdevice = device->physical_device; |
| |
| /* Lavapipe supports exactly one memory type. */ |
| pProperties->memoryTypeBits = 1; |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult lvp_SetBufferCollectionBufferConstraintsFUCHSIA( |
| VkDevice vk_device, |
| VkBufferCollectionFUCHSIA vk_collection, |
| const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) |
| { |
| LVP_FROM_HANDLE(lvp_device, device, vk_device); |
| LVP_FROM_HANDLE(lvp_buffer_collection, buffer_collection, vk_collection); |
| |
| magma_sysmem_connection_t sysmem_connection = device->sysmem_connection; |
| if (!sysmem_connection) |
| return LVP_LOG_VK_ERROR(VK_ERROR_UNKNOWN); |
| |
| magma_buffer_format_constraints_t format_constraints = { |
| .count = pBufferConstraintsInfo->bufferCollectionConstraints.minBufferCount, |
| .usage = 0, |
| .secure_permitted = false, |
| .secure_required = false, |
| /* TODO(https://fxbug.dev/330572161): only CPU domain is supported. In order to support |
| RAM domain, Lavapipe would need to perform cache clean and invalidate operations on |
| VK_QUEUE_FAMILY_EXTERNAL and VK_QUEUE_FAMILY_FOREIGN. */ |
| .ram_domain_supported = false, |
| .cpu_domain_supported = true, |
| .min_size_bytes = pBufferConstraintsInfo->createInfo.size, |
| .options = MAGMA_BUFFER_FORMAT_CONSTRAINT_OPTIONS_EXTRA_COUNTS, |
| .min_buffer_count_for_camping = |
| pBufferConstraintsInfo->bufferCollectionConstraints.minBufferCountForCamping, |
| .min_buffer_count_for_shared_slack = |
| pBufferConstraintsInfo->bufferCollectionConstraints.minBufferCountForSharedSlack, |
| .min_buffer_count_for_dedicated_slack = |
| pBufferConstraintsInfo->bufferCollectionConstraints.minBufferCountForDedicatedSlack, |
| .max_buffer_count = pBufferConstraintsInfo->bufferCollectionConstraints.maxBufferCount}; |
| |
| magma_sysmem_buffer_constraints_t constraints = {0}; |
| magma_status_t status = magma_sysmem_connection_create_buffer_constraints(sysmem_connection, |
| &format_constraints, |
| &constraints); |
| if (status != MAGMA_STATUS_OK) |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| |
| status = |
| magma_buffer_collection_set_constraints2(buffer_collection->buffer_collection, constraints); |
| |
| magma_buffer_constraints_release2(constraints); |
| |
| if (status != MAGMA_STATUS_OK) |
| return LVP_LOG_VK_ERROR(VK_ERROR_FORMAT_NOT_SUPPORTED); |
| |
| return VK_SUCCESS; |
| } |
| |
| static VkResult get_image_format_constraints( |
| VkDevice vk_device, VkFormat format, const VkImageCreateInfo* image_create_info, |
| bool aux_buffer, const VkImageFormatConstraintsInfoFUCHSIA* format_constraints, |
| magma_image_format_constraints_t* image_constraints_out) |
| { |
| LVP_FROM_HANDLE(lvp_device, device, vk_device); |
| |
| /* TODO(https://fxbug.dev/332422422): Revisit these values. */ |
| const uint32_t kBytesPerRowDivisor = 4; |
| const uint32_t kMinBytesPerRow = 16; |
| |
| assert(image_create_info->extent.width); |
| magma_image_format_constraints_t image_constraints = {.width = image_create_info->extent.width, |
| .height = image_create_info->extent.height, |
| .layers = 1, |
| .bytes_per_row_divisor = kBytesPerRowDivisor, |
| .min_bytes_per_row = kMinBytesPerRow}; |
| |
| bool is_yuv_format = false; |
| switch (format) { |
| case VK_FORMAT_B8G8R8A8_SINT: |
| case VK_FORMAT_B8G8R8A8_UNORM: |
| case VK_FORMAT_B8G8R8A8_SRGB: |
| case VK_FORMAT_B8G8R8A8_SNORM: |
| case VK_FORMAT_B8G8R8A8_SSCALED: |
| case VK_FORMAT_B8G8R8A8_USCALED: |
| image_constraints.image_format = MAGMA_FORMAT_BGRA32; |
| break; |
| case VK_FORMAT_R8G8B8A8_SINT: |
| case VK_FORMAT_R8G8B8A8_UNORM: |
| case VK_FORMAT_R8G8B8A8_SRGB: |
| case VK_FORMAT_R8G8B8A8_SNORM: |
| case VK_FORMAT_R8G8B8A8_SSCALED: |
| case VK_FORMAT_R8G8B8A8_USCALED: |
| image_constraints.image_format = MAGMA_FORMAT_R8G8B8A8; |
| break; |
| case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: |
| image_constraints.image_format = MAGMA_FORMAT_NV12; |
| is_yuv_format = true; |
| break; |
| case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: |
| image_constraints.image_format = MAGMA_FORMAT_I420; |
| is_yuv_format = true; |
| break; |
| case VK_FORMAT_R8_UNORM: |
| image_constraints.image_format = MAGMA_FORMAT_R8; |
| if (format_constraints && format_constraints->sysmemPixelFormat) { |
| if (format_constraints->sysmemPixelFormat == MAGMA_FORMAT_L8) { |
| image_constraints.image_format = MAGMA_FORMAT_L8; |
| } else if (format_constraints->sysmemPixelFormat != MAGMA_FORMAT_R8) { |
| return VK_ERROR_FORMAT_NOT_SUPPORTED; |
| } |
| } |
| break; |
| case VK_FORMAT_R8G8_UNORM: |
| image_constraints.image_format = MAGMA_FORMAT_R8G8; |
| break; |
| case VK_FORMAT_R5G6B5_UNORM_PACK16: |
| image_constraints.image_format = MAGMA_FORMAT_RGB565; |
| break; |
| default: |
| return VK_ERROR_FORMAT_NOT_SUPPORTED; |
| } |
| |
| image_constraints.has_format_modifier = false; |
| assert(!aux_buffer); |
| |
| *image_constraints_out = image_constraints; |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult lvp_SetBufferCollectionImageConstraintsFUCHSIA( |
| VkDevice vk_device, |
| VkBufferCollectionFUCHSIA vk_collection, |
| const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo) |
| { |
| LVP_FROM_HANDLE(lvp_device, device, vk_device); |
| LVP_FROM_HANDLE(lvp_buffer_collection, collection, vk_collection); |
| |
| // Can't set constraints twice. |
| if (collection->constraints) |
| return LVP_LOG_VK_ERROR(VK_ERROR_INITIALIZATION_FAILED); |
| |
| const magma_sysmem_connection_t sysmem_connection = device->sysmem_connection; |
| if (!sysmem_connection) |
| return LVP_LOG_VK_ERROR(VK_ERROR_UNKNOWN); |
| |
| if (pImageConstraintsInfo->formatConstraintsCount < 1) { |
| assert(!(pImageConstraintsInfo->formatConstraintsCount < 1)); |
| return LVP_LOG_VK_ERROR(VK_ERROR_FORMAT_NOT_SUPPORTED); |
| } |
| |
| const bool have_format_constraints = (pImageConstraintsInfo->pFormatConstraints != NULL); |
| |
| // Secure formats not supported. |
| for (uint32_t i = 0; i < pImageConstraintsInfo->formatConstraintsCount; ++i) { |
| bool secure_required = |
| (pImageConstraintsInfo->pFormatConstraints[i].imageCreateInfo.flags & |
| VK_IMAGE_CREATE_PROTECTED_BIT); |
| |
| if (secure_required) { |
| assert(!secure_required); |
| return LVP_LOG_VK_ERROR(VK_ERROR_FORMAT_NOT_SUPPORTED); |
| } |
| } |
| |
| magma_sysmem_buffer_constraints_t buffer_constraints; |
| magma_status_t status = MAGMA_STATUS_OK; |
| |
| // Create the buffer constraints. |
| { |
| magma_buffer_format_constraints_t format_constraints = { |
| .count = pImageConstraintsInfo->bufferCollectionConstraints.minBufferCount, |
| .usage = 0, |
| .secure_permitted = false, |
| .secure_required = false, |
| /* TODO(https://fxbug.dev/330572161): only CPU domain is supported. In order to support |
| RAM domain, Lavapipe would need to perform cache clean and invalidate operations on |
| VK_QUEUE_FAMILY_EXTERNAL and VK_QUEUE_FAMILY_FOREIGN. */ |
| .ram_domain_supported = false, |
| .cpu_domain_supported = true, |
| .min_size_bytes = 0, |
| .options = MAGMA_BUFFER_FORMAT_CONSTRAINT_OPTIONS_EXTRA_COUNTS, |
| .min_buffer_count_for_camping = |
| pImageConstraintsInfo->bufferCollectionConstraints.minBufferCountForCamping, |
| .min_buffer_count_for_shared_slack = |
| pImageConstraintsInfo->bufferCollectionConstraints.minBufferCountForSharedSlack, |
| .min_buffer_count_for_dedicated_slack = |
| pImageConstraintsInfo->bufferCollectionConstraints.minBufferCountForDedicatedSlack, |
| .max_buffer_count = pImageConstraintsInfo->bufferCollectionConstraints.maxBufferCount}; |
| |
| status = magma_sysmem_connection_create_buffer_constraints(sysmem_connection, |
| &format_constraints, |
| &buffer_constraints); |
| if (status != MAGMA_STATUS_OK) |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| } |
| |
| uint32_t format_index = 0; |
| |
| // Set format slots for each image info. |
| for (uint32_t i = 0; i < pImageConstraintsInfo->formatConstraintsCount; ++i) { |
| const VkImageCreateInfo* pCreateInfo = |
| &pImageConstraintsInfo->pFormatConstraints[i].imageCreateInfo; |
| VkFormat format = pCreateInfo->format; |
| |
| const struct lvp_physical_device* physical_device = device->physical_device; |
| const VkFormatFeatureFlags linear_flags = |
| get_image_format_features(physical_device, format, VK_IMAGE_TILING_LINEAR); |
| const VkFormatFeatureFlags optimal_flags = |
| get_image_format_features(physical_device, format, VK_IMAGE_TILING_OPTIMAL); |
| |
| const VkImageFormatConstraintsInfoFUCHSIA* format_constraints = |
| have_format_constraints ? &pImageConstraintsInfo->pFormatConstraints[i] : NULL; |
| |
| const uint32_t color_space_count = |
| format_constraints ? format_constraints->colorSpaceCount : 0; |
| uint32_t color_spaces[color_space_count]; |
| |
| for (uint32_t j = 0; j < color_space_count; ++j) { |
| color_spaces[j] = format_constraints->pColorSpaces[j].colorSpace; |
| } |
| |
| magma_image_format_constraints_t image_constraints = {}; |
| bool image_constraints_valid = false; |
| |
| status = get_image_format_constraints(vk_device, format, pCreateInfo, |
| /*aux_buffer*/ false, format_constraints, |
| &image_constraints); |
| if (status != VK_SUCCESS) |
| continue; |
| |
| image_constraints_valid = |
| !format_constraints || !(~linear_flags & format_constraints->requiredFormatFeatures); |
| |
| if (!image_constraints_valid) |
| continue; |
| |
| // Currently every vulkan format maps to only 1 sysmem format, so ensure the client is |
| // using the same format. |
| if (format_constraints && format_constraints->sysmemPixelFormat && |
| (format_constraints->sysmemPixelFormat != image_constraints.image_format)) { |
| continue; |
| } |
| |
| collection->format_index_input_index_map[format_index] = i; |
| |
| status = magma_buffer_constraints_set_format2(buffer_constraints, format_index, |
| &image_constraints); |
| if (status != MAGMA_STATUS_OK) { |
| magma_buffer_constraints_release2(buffer_constraints); |
| return LVP_LOG_VK_ERROR(VK_ERROR_FORMAT_NOT_SUPPORTED); |
| } |
| |
| if (color_space_count) { |
| magma_buffer_constraints_set_colorspaces2(buffer_constraints, format_index, |
| color_space_count, color_spaces); |
| } |
| |
| format_index += 1; |
| assert(format_index < MAX_BUFFER_COLLECTION_FORMAT_INDICES); |
| if (format_index >= MAX_BUFFER_COLLECTION_FORMAT_INDICES) { |
| magma_buffer_constraints_release2(buffer_constraints); |
| return LVP_LOG_VK_ERROR(VK_ERROR_OUT_OF_HOST_MEMORY); |
| } |
| } |
| |
| if (format_index == 0) { |
| magma_buffer_constraints_release2(buffer_constraints); |
| return LVP_LOG_VK_ERROR(VK_ERROR_FORMAT_NOT_SUPPORTED); |
| } |
| |
| status = magma_buffer_collection_set_constraints2(collection->buffer_collection, |
| buffer_constraints); |
| if (status != MAGMA_STATUS_OK) { |
| magma_buffer_constraints_release2(buffer_constraints); |
| return LVP_LOG_VK_ERROR(VK_ERROR_FORMAT_NOT_SUPPORTED); |
| } |
| |
| collection->constraints = buffer_constraints; |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult |
| fuchsia_allocate_memory_from_buffer_collection( |
| const struct lvp_device* device, |
| const struct lvp_buffer_collection* buffer_collection, |
| uint32_t index, |
| uint64_t alloc_size, |
| struct lvp_device_memory* memory_out) |
| { |
| { |
| magma_collection_info_t collection_info; |
| magma_status_t status = magma_buffer_collection_get_collection_info( |
| buffer_collection->buffer_collection, &collection_info); |
| if (status != MAGMA_STATUS_OK) |
| return LVP_LOG_VK_ERROR(VK_ERROR_UNKNOWN); |
| |
| uint32_t coherency_domain; |
| status = magma_collection_info_get_coherency_domain(collection_info, &coherency_domain); |
| magma_collection_info_release(collection_info); |
| |
| if (status != MAGMA_STATUS_OK) |
| return LVP_LOG_VK_ERROR(VK_ERROR_FORMAT_NOT_SUPPORTED); |
| |
| /* TODO(https://fxbug.dev/330572161): only CPU domain is supported. In order to support |
| RAM domain, Lavapipe would need to perform cache clean and invalidate operations on |
| VK_QUEUE_FAMILY_EXTERNAL and VK_QUEUE_FAMILY_FOREIGN. */ |
| assert(coherency_domain == MAGMA_COHERENCY_DOMAIN_CPU); |
| } |
| |
| uint32_t vmo_handle; |
| { |
| uint32_t offset; |
| if (magma_buffer_collection_get_buffer_handle(buffer_collection->buffer_collection, index, |
| &vmo_handle, &offset) != MAGMA_STATUS_OK) { |
| return LVP_LOG_VK_ERROR(VK_ERROR_UNKNOWN); |
| } |
| } |
| |
| VkResult error = lvp_fuchsia_import_vmo(vmo_handle, alloc_size, memory_out); |
| if (error != VK_SUCCESS) { |
| return LVP_LOG_VK_ERROR(error); |
| } |
| |
| return VK_SUCCESS; |
| } |