diff --git a/src/panfrost/vulkan/meson.build b/src/panfrost/vulkan/meson.build index d5813ac0b65..c0bb04e5e04 100644 --- a/src/panfrost/vulkan/meson.build +++ b/src/panfrost/vulkan/meson.build @@ -42,10 +42,10 @@ libpanvk_files = files( 'panvk_device_memory.c', 'panvk_descriptor_set.c', 'panvk_event.c', - 'panvk_formats.c', 'panvk_image.c', 'panvk_instance.c', 'panvk_mempool.c', + 'panvk_physical_device.c', 'panvk_pipeline.c', 'panvk_private.h', 'panvk_query.c', diff --git a/src/panfrost/vulkan/panvk_cmd_buffer.c b/src/panfrost/vulkan/panvk_cmd_buffer.c index 9eaaaee4c25..58112dc632e 100644 --- a/src/panfrost/vulkan/panvk_cmd_buffer.c +++ b/src/panfrost/vulkan/panvk_cmd_buffer.c @@ -28,6 +28,7 @@ #include "panvk_buffer.h" #include "panvk_cmd_pool.h" +#include "panvk_physical_device.h" #include "panvk_pipeline.h" #include "panvk_pipeline_layout.h" #include "panvk_private.h" diff --git a/src/panfrost/vulkan/panvk_device.c b/src/panfrost/vulkan/panvk_device.c index 75e660df9e8..7d8b12adcfd 100644 --- a/src/panfrost/vulkan/panvk_device.c +++ b/src/panfrost/vulkan/panvk_device.c @@ -29,6 +29,7 @@ #include "panvk_device_memory.h" #include "panvk_image.h" #include "panvk_instance.h" +#include "panvk_physical_device.h" #include "panvk_private.h" #include "panvk_queue.h" @@ -65,705 +66,6 @@ #include #endif -static int -panvk_device_get_cache_uuid(uint16_t family, void *uuid) -{ - uint32_t mesa_timestamp; - uint16_t f = family; - - if (!disk_cache_get_function_timestamp(panvk_device_get_cache_uuid, - &mesa_timestamp)) - return -1; - - memset(uuid, 0, VK_UUID_SIZE); - memcpy(uuid, &mesa_timestamp, 4); - memcpy((char *)uuid + 4, &f, 2); - snprintf((char *)uuid + 6, VK_UUID_SIZE - 10, "pan"); - return 0; -} - -static void -panvk_get_driver_uuid(void *uuid) -{ - memset(uuid, 0, VK_UUID_SIZE); - snprintf(uuid, VK_UUID_SIZE, "panfrost"); -} - -static void -panvk_get_device_uuid(void *uuid) -{ - memset(uuid, 0, VK_UUID_SIZE); -} - -#define PANVK_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION) - -static void -panvk_get_device_extensions(const struct panvk_physical_device *device, - struct vk_device_extension_table *ext) -{ - *ext = (struct vk_device_extension_table){ - .KHR_copy_commands2 = true, - .KHR_shader_expect_assume = true, - .KHR_storage_buffer_storage_class = true, - .KHR_descriptor_update_template = true, -#ifdef PANVK_USE_WSI_PLATFORM - .KHR_swapchain = true, -#endif - .KHR_synchronization2 = true, - .KHR_variable_pointers = true, - .EXT_custom_border_color = true, - .EXT_index_type_uint8 = true, - .EXT_vertex_attribute_divisor = true, - }; -} - -static void -panvk_get_features(const struct panvk_physical_device *device, - struct vk_features *features) -{ - *features = (struct vk_features){ - /* Vulkan 1.0 */ - .robustBufferAccess = true, - .fullDrawIndexUint32 = true, - .independentBlend = true, - .logicOp = true, - .wideLines = true, - .largePoints = true, - .textureCompressionETC2 = true, - .textureCompressionASTC_LDR = true, - .shaderUniformBufferArrayDynamicIndexing = true, - .shaderSampledImageArrayDynamicIndexing = true, - .shaderStorageBufferArrayDynamicIndexing = true, - .shaderStorageImageArrayDynamicIndexing = true, - - /* Vulkan 1.1 */ - .storageBuffer16BitAccess = false, - .uniformAndStorageBuffer16BitAccess = false, - .storagePushConstant16 = false, - .storageInputOutput16 = false, - .multiview = false, - .multiviewGeometryShader = false, - .multiviewTessellationShader = false, - .variablePointersStorageBuffer = true, - .variablePointers = true, - .protectedMemory = false, - .samplerYcbcrConversion = false, - .shaderDrawParameters = false, - - /* Vulkan 1.2 */ - .samplerMirrorClampToEdge = false, - .drawIndirectCount = false, - .storageBuffer8BitAccess = false, - .uniformAndStorageBuffer8BitAccess = false, - .storagePushConstant8 = false, - .shaderBufferInt64Atomics = false, - .shaderSharedInt64Atomics = false, - .shaderFloat16 = false, - .shaderInt8 = false, - - .descriptorIndexing = false, - .shaderInputAttachmentArrayDynamicIndexing = false, - .shaderUniformTexelBufferArrayDynamicIndexing = false, - .shaderStorageTexelBufferArrayDynamicIndexing = false, - .shaderUniformBufferArrayNonUniformIndexing = false, - .shaderSampledImageArrayNonUniformIndexing = false, - .shaderStorageBufferArrayNonUniformIndexing = false, - .shaderStorageImageArrayNonUniformIndexing = false, - .shaderInputAttachmentArrayNonUniformIndexing = false, - .shaderUniformTexelBufferArrayNonUniformIndexing = false, - .shaderStorageTexelBufferArrayNonUniformIndexing = false, - .descriptorBindingUniformBufferUpdateAfterBind = false, - .descriptorBindingSampledImageUpdateAfterBind = false, - .descriptorBindingStorageImageUpdateAfterBind = false, - .descriptorBindingStorageBufferUpdateAfterBind = false, - .descriptorBindingUniformTexelBufferUpdateAfterBind = false, - .descriptorBindingStorageTexelBufferUpdateAfterBind = false, - .descriptorBindingUpdateUnusedWhilePending = false, - .descriptorBindingPartiallyBound = false, - .descriptorBindingVariableDescriptorCount = false, - .runtimeDescriptorArray = false, - - .samplerFilterMinmax = false, - .scalarBlockLayout = false, - .imagelessFramebuffer = false, - .uniformBufferStandardLayout = false, - .shaderSubgroupExtendedTypes = false, - .separateDepthStencilLayouts = false, - .hostQueryReset = false, - .timelineSemaphore = false, - .bufferDeviceAddress = true, - .bufferDeviceAddressCaptureReplay = false, - .bufferDeviceAddressMultiDevice = false, - .vulkanMemoryModel = false, - .vulkanMemoryModelDeviceScope = false, - .vulkanMemoryModelAvailabilityVisibilityChains = false, - .shaderOutputViewportIndex = false, - .shaderOutputLayer = false, - .subgroupBroadcastDynamicId = false, - - /* Vulkan 1.3 */ - .robustImageAccess = false, - .inlineUniformBlock = false, - .descriptorBindingInlineUniformBlockUpdateAfterBind = false, - .pipelineCreationCacheControl = false, - .privateData = true, - .shaderDemoteToHelperInvocation = false, - .shaderTerminateInvocation = false, - .subgroupSizeControl = false, - .computeFullSubgroups = false, - .synchronization2 = true, - .textureCompressionASTC_HDR = false, - .shaderZeroInitializeWorkgroupMemory = false, - .dynamicRendering = false, - .shaderIntegerDotProduct = false, - .maintenance4 = false, - - /* VK_EXT_index_type_uint8 */ - .indexTypeUint8 = true, - - /* VK_EXT_vertex_attribute_divisor */ - .vertexAttributeInstanceRateDivisor = true, - .vertexAttributeInstanceRateZeroDivisor = true, - - /* VK_EXT_depth_clip_enable */ - .depthClipEnable = true, - - /* VK_EXT_4444_formats */ - .formatA4R4G4B4 = true, - .formatA4B4G4R4 = true, - - /* VK_EXT_custom_border_color */ - .customBorderColors = true, - .customBorderColorWithoutFormat = true, - - /* VK_KHR_shader_expect_assume */ - .shaderExpectAssume = true, - }; -} - -void -panvk_physical_device_finish(struct panvk_physical_device *device) -{ - panvk_wsi_finish(device); - - pan_kmod_dev_destroy(device->kmod.dev); - if (device->master_fd != -1) - close(device->master_fd); - - vk_physical_device_finish(&device->vk); -} - -VkResult -panvk_physical_device_init(struct panvk_physical_device *device, - struct panvk_instance *instance, - drmDevicePtr drm_device) -{ - const char *path = drm_device->nodes[DRM_NODE_RENDER]; - VkResult result = VK_SUCCESS; - drmVersionPtr version; - int fd; - int master_fd = -1; - - if (!getenv("PAN_I_WANT_A_BROKEN_VULKAN_DRIVER")) { - return vk_errorf( - instance, VK_ERROR_INCOMPATIBLE_DRIVER, - "WARNING: panvk is not a conformant vulkan implementation, " - "pass PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 if you know what you're doing."); - } - - fd = open(path, O_RDWR | O_CLOEXEC); - if (fd < 0) { - return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, - "failed to open device %s", path); - } - - version = drmGetVersion(fd); - if (!version) { - close(fd); - return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, - "failed to query kernel driver version for device %s", - path); - } - - if (strcmp(version->name, "panfrost")) { - drmFreeVersion(version); - close(fd); - return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, - "device %s does not use the panfrost kernel driver", - path); - } - - drmFreeVersion(version); - - if (instance->debug_flags & PANVK_DEBUG_STARTUP) - vk_logi(VK_LOG_NO_OBJS(instance), "Found compatible device '%s'.", path); - - struct vk_device_extension_table supported_extensions; - panvk_get_device_extensions(device, &supported_extensions); - - struct vk_features supported_features; - panvk_get_features(device, &supported_features); - - struct vk_physical_device_dispatch_table dispatch_table; - vk_physical_device_dispatch_table_from_entrypoints( - &dispatch_table, &panvk_physical_device_entrypoints, true); - vk_physical_device_dispatch_table_from_entrypoints( - &dispatch_table, &wsi_physical_device_entrypoints, false); - - result = - vk_physical_device_init(&device->vk, &instance->vk, &supported_extensions, - &supported_features, NULL, &dispatch_table); - - if (result != VK_SUCCESS) { - vk_error(instance, result); - goto fail; - } - - if (instance->vk.enabled_extensions.KHR_display) { - master_fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC); - if (master_fd >= 0) { - /* TODO: free master_fd is accel is not working? */ - } - } - - device->master_fd = master_fd; - - device->kmod.dev = pan_kmod_dev_create(fd, PAN_KMOD_DEV_FLAG_OWNS_FD, - &instance->kmod.allocator); - pan_kmod_dev_query_props(device->kmod.dev, &device->kmod.props); - - unsigned arch = pan_arch(device->kmod.props.gpu_prod_id); - - device->model = panfrost_get_model(device->kmod.props.gpu_prod_id, - device->kmod.props.gpu_variant); - device->formats.all = panfrost_format_table(arch); - device->formats.blendable = panfrost_blendable_format_table(arch); - - if (arch <= 5 || arch >= 8) { - result = vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, - "%s not supported", device->model->name); - goto fail; - } - - memset(device->name, 0, sizeof(device->name)); - sprintf(device->name, "%s", device->model->name); - - if (panvk_device_get_cache_uuid(device->kmod.props.gpu_prod_id, - device->cache_uuid)) { - result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, - "cannot generate UUID"); - goto fail_close_device; - } - - vk_warn_non_conformant_implementation("panvk"); - - panvk_get_driver_uuid(&device->device_uuid); - panvk_get_device_uuid(&device->device_uuid); - - device->drm_syncobj_type = vk_drm_syncobj_get_type(device->kmod.dev->fd); - /* We don't support timelines in the uAPI yet and we don't want it getting - * suddenly turned on by vk_drm_syncobj_get_type() without us adding panvk - * code for it first. - */ - device->drm_syncobj_type.features &= ~VK_SYNC_FEATURE_TIMELINE; - - device->sync_types[0] = &device->drm_syncobj_type; - device->sync_types[1] = NULL; - device->vk.supported_sync_types = device->sync_types; - - result = panvk_wsi_init(device); - if (result != VK_SUCCESS) { - vk_error(instance, result); - goto fail_close_device; - } - - return VK_SUCCESS; - -fail_close_device: - pan_kmod_dev_destroy(device->kmod.dev); -fail: - if (fd != -1) - close(fd); - if (master_fd != -1) - close(master_fd); - return result; -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2 *pProperties) -{ - VK_FROM_HANDLE(panvk_physical_device, pdevice, physicalDevice); - - /* HW supports MSAA 4, 8 and 16, but we limit ourselves to MSAA 4 for now. */ - VkSampleCountFlags sample_counts = - VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT; - - const VkPhysicalDeviceLimits limits = { - /* Maximum texture dimension is 2^16. */ - .maxImageDimension1D = (1 << 16), - .maxImageDimension2D = (1 << 16), - .maxImageDimension3D = (1 << 16), - .maxImageDimensionCube = (1 << 16), - .maxImageArrayLayers = (1 << 16), - - /* Currently limited by the 1D texture size, which is 2^16. - * TODO: If we expose buffer views as 2D textures, we can increase the - * limit. - */ - .maxTexelBufferElements = (1 << 16), - - /* Each uniform entry is 16-byte and the number of entries is encoded in a - * 12-bit field, with the minus(1) modifier, which gives 2^20. - */ - .maxUniformBufferRange = 1 << 20, - - /* Storage buffer access is lowered to globals, so there's no limit here, - * except for the SW-descriptor we use to encode storage buffer - * descriptors, where the size is a 32-bit field. - */ - .maxStorageBufferRange = UINT32_MAX, - - /* 128 bytes of push constants, so we're aligned with the minimum Vulkan - * requirements. - */ - .maxPushConstantsSize = 128, - - /* There's no HW limit here. Should we advertize something smaller? */ - .maxMemoryAllocationCount = UINT32_MAX, - - /* Again, no hardware limit, but most drivers seem to advertive 64k. */ - .maxSamplerAllocationCount = 64 * 1024, - - /* A cache line. */ - .bufferImageGranularity = 64, - - /* Sparse binding not supported yet. */ - .sparseAddressSpaceSize = 0, - - /* Software limit. Pick the minimum required by Vulkan, because Bifrost - * GPUs don't have unified descriptor tables, which forces us to - * agregatte all descriptors from all sets and dispatch them to per-type - * descriptor tables emitted at draw/dispatch time. - * The more sets we support the more copies we are likely to have to do - * at draw time. - */ - .maxBoundDescriptorSets = 4, - - /* MALI_RENDERER_STATE::sampler_count is 16-bit. */ - .maxPerStageDescriptorSamplers = UINT16_MAX, - .maxDescriptorSetSamplers = UINT16_MAX, - - /* MALI_RENDERER_STATE::uniform_buffer_count is 8-bit. We reserve 32 slots - * for our internal UBOs. - */ - .maxPerStageDescriptorUniformBuffers = UINT8_MAX - 32, - .maxDescriptorSetUniformBuffers = UINT8_MAX - 32, - - /* SSBOs are limited by the size of a uniform buffer which contains our - * panvk_ssbo_desc objects. - * panvk_ssbo_desc is 16-byte, and each uniform entry in the Mali UBO is - * 16-byte too. The number of entries is encoded in a 12-bit field, with - * a minus(1) modifier, which gives a maximum of 2^12 SSBO - * descriptors. - */ - .maxPerStageDescriptorStorageBuffers = 1 << 12, - .maxDescriptorSetStorageBuffers = 1 << 12, - - /* MALI_RENDERER_STATE::sampler_count is 16-bit. */ - .maxPerStageDescriptorSampledImages = UINT16_MAX, - .maxDescriptorSetSampledImages = UINT16_MAX, - - /* MALI_ATTRIBUTE::buffer_index is 9-bit, and each image takes two - * MALI_ATTRIBUTE_BUFFER slots, which gives a maximum of (1 << 8) images. - */ - .maxPerStageDescriptorStorageImages = 1 << 8, - .maxDescriptorSetStorageImages = 1 << 8, - - /* A maximum of 8 color render targets, and one depth-stencil render - * target. - */ - .maxPerStageDescriptorInputAttachments = 9, - .maxDescriptorSetInputAttachments = 9, - - /* Could be the sum of all maxPerStageXxx values, but we limit ourselves - * to 2^16 to make things simpler. - */ - .maxPerStageResources = 1 << 16, - - /* Software limits to keep VkCommandBuffer tracking sane. */ - .maxDescriptorSetUniformBuffersDynamic = 16, - .maxDescriptorSetStorageBuffersDynamic = 8, - - /* Software limit to keep VkCommandBuffer tracking sane. The HW supports - * up to 2^9 vertex attributes. - */ - .maxVertexInputAttributes = 16, - .maxVertexInputBindings = 16, - - /* MALI_ATTRIBUTE::offset is 32-bit. */ - .maxVertexInputAttributeOffset = UINT32_MAX, - - /* MALI_ATTRIBUTE_BUFFER::stride is 32-bit. */ - .maxVertexInputBindingStride = UINT32_MAX, - - /* 32 vec4 varyings. */ - .maxVertexOutputComponents = 128, - - /* Tesselation shaders not supported. */ - .maxTessellationGenerationLevel = 0, - .maxTessellationPatchSize = 0, - .maxTessellationControlPerVertexInputComponents = 0, - .maxTessellationControlPerVertexOutputComponents = 0, - .maxTessellationControlPerPatchOutputComponents = 0, - .maxTessellationControlTotalOutputComponents = 0, - .maxTessellationEvaluationInputComponents = 0, - .maxTessellationEvaluationOutputComponents = 0, - - /* Geometry shaders not supported. */ - .maxGeometryShaderInvocations = 0, - .maxGeometryInputComponents = 0, - .maxGeometryOutputComponents = 0, - .maxGeometryOutputVertices = 0, - .maxGeometryTotalOutputComponents = 0, - - /* 32 vec4 varyings. */ - .maxFragmentInputComponents = 128, - - /* 8 render targets. */ - .maxFragmentOutputAttachments = 8, - - /* We don't support dual source blending yet. */ - .maxFragmentDualSrcAttachments = 0, - - /* 8 render targets, 2^12 storage buffers and 2^8 storage images (see - * above). - */ - .maxFragmentCombinedOutputResources = 8 + (1 << 12) + (1 << 8), - - /* MALI_LOCAL_STORAGE::wls_size_{base,scale} allows us to have up to - * (7 << 30) bytes of shared memory, but we cap it to 32K as it doesn't - * really make sense to expose this amount of memory, especially since - * it's backed by global memory anyway. - */ - .maxComputeSharedMemorySize = 32768, - - /* Software limit to meet Vulkan 1.0 requirements. We split the - * dispatch in several jobs if it's too big. - */ - .maxComputeWorkGroupCount = {65535, 65535, 65535}, - - /* We have 10 bits to encode the local-size, and there's a minus(1) - * modifier, so, a size of 1 takes no bit. - */ - .maxComputeWorkGroupInvocations = 1 << 10, - .maxComputeWorkGroupSize = {1 << 10, 1 << 10, 1 << 10}, - - /* 8-bit subpixel precision. */ - .subPixelPrecisionBits = 8, - .subTexelPrecisionBits = 8, - .mipmapPrecisionBits = 8, - - /* Software limit. */ - .maxDrawIndexedIndexValue = UINT32_MAX, - - /* Make it one for now. */ - .maxDrawIndirectCount = 1, - - .maxSamplerLodBias = 255, - .maxSamplerAnisotropy = 16, - .maxViewports = 1, - - /* Same as the framebuffer limit. */ - .maxViewportDimensions = {(1 << 14), (1 << 14)}, - - /* Encoded in a 16-bit signed integer. */ - .viewportBoundsRange = {INT16_MIN, INT16_MAX}, - .viewportSubPixelBits = 0, - - /* Align on a page. */ - .minMemoryMapAlignment = 4096, - - /* Some compressed texture formats require 128-byte alignment. */ - .minTexelBufferOffsetAlignment = 64, - - /* Always aligned on a uniform slot (vec4). */ - .minUniformBufferOffsetAlignment = 16, - - /* Lowered to global accesses, which happen at the 32-bit granularity. */ - .minStorageBufferOffsetAlignment = 4, - - /* Signed 4-bit value. */ - .minTexelOffset = -8, - .maxTexelOffset = 7, - .minTexelGatherOffset = -8, - .maxTexelGatherOffset = 7, - .minInterpolationOffset = -0.5, - .maxInterpolationOffset = 0.5, - .subPixelInterpolationOffsetBits = 8, - - .maxFramebufferWidth = (1 << 14), - .maxFramebufferHeight = (1 << 14), - .maxFramebufferLayers = 256, - .framebufferColorSampleCounts = sample_counts, - .framebufferDepthSampleCounts = sample_counts, - .framebufferStencilSampleCounts = sample_counts, - .framebufferNoAttachmentsSampleCounts = sample_counts, - .maxColorAttachments = 8, - .sampledImageColorSampleCounts = sample_counts, - .sampledImageIntegerSampleCounts = VK_SAMPLE_COUNT_1_BIT, - .sampledImageDepthSampleCounts = sample_counts, - .sampledImageStencilSampleCounts = sample_counts, - .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT, - .maxSampleMaskWords = 1, - .timestampComputeAndGraphics = false, - .timestampPeriod = 0, - .maxClipDistances = 0, - .maxCullDistances = 0, - .maxCombinedClipAndCullDistances = 0, - .discreteQueuePriorities = 1, - .pointSizeRange = {0.125, 4095.9375}, - .lineWidthRange = {0.0, 7.9921875}, - .pointSizeGranularity = (1.0 / 16.0), - .lineWidthGranularity = (1.0 / 128.0), - .strictLines = false, - .standardSampleLocations = true, - .optimalBufferCopyOffsetAlignment = 64, - .optimalBufferCopyRowPitchAlignment = 64, - .nonCoherentAtomSize = 64, - }; - - pProperties->properties = (VkPhysicalDeviceProperties){ - .apiVersion = PANVK_API_VERSION, - .driverVersion = vk_get_driver_version(), - - /* Arm vendor ID. */ - .vendorID = 0x13b5, - - /* Collect arch_major, arch_minor, arch_rev and product_major, - * as done by the Arm driver. - */ - .deviceID = pdevice->kmod.props.gpu_prod_id << 16, - .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, - .limits = limits, - .sparseProperties = {0}, - }; - - strcpy(pProperties->properties.deviceName, pdevice->name); - memcpy(pProperties->properties.pipelineCacheUUID, pdevice->cache_uuid, - VK_UUID_SIZE); - - VkPhysicalDeviceVulkan11Properties core_1_1 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES, - .deviceLUIDValid = false, - .pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - .maxMultiviewViewCount = 0, - .maxMultiviewInstanceIndex = 0, - .protectedNoFault = false, - /* Make sure everything is addressable by a signed 32-bit int, and - * our largest descriptors are 96 bytes. */ - .maxPerSetDescriptors = (1ull << 31) / 96, - /* Our buffer size fields allow only this much */ - .maxMemoryAllocationSize = 0xFFFFFFFFull, - }; - memcpy(core_1_1.driverUUID, pdevice->driver_uuid, VK_UUID_SIZE); - memcpy(core_1_1.deviceUUID, pdevice->device_uuid, VK_UUID_SIZE); - - const VkPhysicalDeviceVulkan12Properties core_1_2 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES, - }; - - const VkPhysicalDeviceVulkan13Properties core_1_3 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES, - }; - - vk_foreach_struct(ext, pProperties->pNext) { - if (vk_get_physical_device_core_1_1_property_ext(ext, &core_1_1)) - continue; - if (vk_get_physical_device_core_1_2_property_ext(ext, &core_1_2)) - continue; - if (vk_get_physical_device_core_1_3_property_ext(ext, &core_1_3)) - continue; - - switch (ext->sType) { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: { - VkPhysicalDevicePushDescriptorPropertiesKHR *properties = - (VkPhysicalDevicePushDescriptorPropertiesKHR *)ext; - properties->maxPushDescriptors = 0; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: { - VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *properties = - (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext; - /* We will have to restrict this a bit for multiview */ - properties->maxVertexAttribDivisor = UINT32_MAX; - break; - } - default: - break; - } - } -} - -static const VkQueueFamilyProperties panvk_queue_family_properties = { - .queueFlags = - VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, - .queueCount = 1, - .timestampValidBits = 0, - .minImageTransferGranularity = {1, 1, 1}, -}; - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceQueueFamilyProperties2( - VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, - VkQueueFamilyProperties2 *pQueueFamilyProperties) -{ - VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out, pQueueFamilyProperties, - pQueueFamilyPropertyCount); - - vk_outarray_append_typed(VkQueueFamilyProperties2, &out, p) - { - p->queueFamilyProperties = panvk_queue_family_properties; - } -} - -static uint64_t -panvk_get_system_heap_size() -{ - struct sysinfo info; - sysinfo(&info); - - uint64_t total_ram = (uint64_t)info.totalram * info.mem_unit; - - /* We don't want to burn too much ram with the GPU. If the user has 4GiB - * or less, we use at most half. If they have more than 4GiB, we use 3/4. - */ - uint64_t available_ram; - if (total_ram <= 4ull * 1024 * 1024 * 1024) - available_ram = total_ram / 2; - else - available_ram = total_ram * 3 / 4; - - return available_ram; -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceMemoryProperties2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) -{ - pMemoryProperties->memoryProperties = (VkPhysicalDeviceMemoryProperties){ - .memoryHeapCount = 1, - .memoryHeaps[0].size = panvk_get_system_heap_size(), - .memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, - .memoryTypeCount = 1, - .memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - .memoryTypes[0].heapIndex = 0, - }; -} - struct panvk_priv_bo * panvk_priv_bo_create(struct panvk_device *dev, size_t size, uint32_t flags, const struct VkAllocationCallbacks *alloc, @@ -864,78 +166,3 @@ panvk_priv_bo_destroy(struct panvk_priv_bo *priv_bo, pan_kmod_bo_put(priv_bo->bo); vk_free2(&dev->vk.alloc, alloc, priv_bo); } - -#define DEVICE_PER_ARCH_FUNCS(_ver) \ - VkResult panvk_v##_ver##_create_device( \ - struct panvk_physical_device *physical_device, \ - const VkDeviceCreateInfo *pCreateInfo, \ - const VkAllocationCallbacks *pAllocator, VkDevice *pDevice); \ - \ - void panvk_v##_ver##_destroy_device( \ - struct panvk_device *device, const VkAllocationCallbacks *pAllocator) - -DEVICE_PER_ARCH_FUNCS(6); -DEVICE_PER_ARCH_FUNCS(7); - -VKAPI_ATTR VkResult VKAPI_CALL -panvk_CreateDevice(VkPhysicalDevice physicalDevice, - const VkDeviceCreateInfo *pCreateInfo, - const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) -{ - VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); - unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id); - VkResult result = VK_ERROR_INITIALIZATION_FAILED; - - panvk_arch_dispatch_ret(arch, create_device, result, physical_device, - pCreateInfo, pAllocator, pDevice); - - return result; -} - -VKAPI_ATTR void VKAPI_CALL -panvk_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator) -{ - VK_FROM_HANDLE(panvk_device, device, _device); - struct panvk_physical_device *physical_device = - to_panvk_physical_device(device->vk.physical); - unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id); - - panvk_arch_dispatch(arch, destroy_device, device, pAllocator); -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceExternalSemaphoreProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, - VkExternalSemaphoreProperties *pExternalSemaphoreProperties) -{ - if ((pExternalSemaphoreInfo->handleType == - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT || - pExternalSemaphoreInfo->handleType == - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)) { - pExternalSemaphoreProperties->exportFromImportedHandleTypes = - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; - pExternalSemaphoreProperties->compatibleHandleTypes = - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; - pExternalSemaphoreProperties->externalSemaphoreFeatures = - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; - } else { - pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; - pExternalSemaphoreProperties->compatibleHandleTypes = 0; - pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; - } -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceExternalFenceProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, - VkExternalFenceProperties *pExternalFenceProperties) -{ - pExternalFenceProperties->exportFromImportedHandleTypes = 0; - pExternalFenceProperties->compatibleHandleTypes = 0; - pExternalFenceProperties->externalFenceFeatures = 0; -} diff --git a/src/panfrost/vulkan/panvk_formats.c b/src/panfrost/vulkan/panvk_formats.c deleted file mode 100644 index 45d32d04f0b..00000000000 --- a/src/panfrost/vulkan/panvk_formats.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Copyright © 2021 Collabora Ltd. - * - * Derived from tu_formats.c which is: - * Copyright © 2016 Red Hat. - * Copyright © 2016 Bas Nieuwenhuizen - * - * 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 "panvk_private.h" - -#include "panfrost/lib/pan_texture.h" -#include "util/format_r11g11b10f.h" -#include "util/format_srgb.h" -#include "util/half_float.h" -#include "vk_format.h" -#include "vk_util.h" - -static void -get_format_properties(struct panvk_physical_device *physical_device, - VkFormat format, VkFormatProperties *out_properties) -{ - VkFormatFeatureFlags tex = 0, buffer = 0; - enum pipe_format pfmt = vk_format_to_pipe_format(format); - const struct panfrost_format fmt = physical_device->formats.all[pfmt]; - - if (!pfmt || !fmt.hw) - goto end; - - /* 3byte formats are not supported by the buffer <-> image copy helpers. */ - if (util_format_get_blocksize(pfmt) == 3) - goto end; - - /* We don't support compressed formats yet: this is causing trouble when - * doing a vkCmdCopyImage() between a compressed and a non-compressed format - * on a tiled/AFBC resource. - */ - if (util_format_is_compressed(pfmt)) - goto end; - - buffer |= - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT; - - if (fmt.bind & PAN_BIND_VERTEX_BUFFER) - buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT; - - if (fmt.bind & PAN_BIND_SAMPLER_VIEW) { - tex |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | - VK_FORMAT_FEATURE_TRANSFER_DST_BIT | - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT | - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT; - - /* Integer formats only support nearest filtering */ - if (!util_format_is_scaled(pfmt) && !util_format_is_pure_integer(pfmt)) - tex |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; - - buffer |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; - - tex |= VK_FORMAT_FEATURE_BLIT_SRC_BIT; - } - - /* SNORM rendering isn't working yet, disable */ - if (fmt.bind & PAN_BIND_RENDER_TARGET && !util_format_is_snorm(pfmt)) { - tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | - VK_FORMAT_FEATURE_BLIT_DST_BIT; - - tex |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; - buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT; - - /* Can always blend via blend shaders */ - tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; - } - - if (fmt.bind & PAN_BIND_DEPTH_STENCIL) - tex |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; - -end: - out_properties->linearTilingFeatures = tex; - out_properties->optimalTilingFeatures = tex; - out_properties->bufferFeatures = buffer; -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties *pFormatProperties) -{ - VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); - - get_format_properties(physical_device, format, pFormatProperties); -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2 *pFormatProperties) -{ - VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); - - get_format_properties(physical_device, format, - &pFormatProperties->formatProperties); - - VkDrmFormatModifierPropertiesListEXT *list = vk_find_struct( - pFormatProperties->pNext, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT); - if (list) { - VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierPropertiesEXT, out, - list->pDrmFormatModifierProperties, - &list->drmFormatModifierCount); - - vk_outarray_append_typed(VkDrmFormatModifierProperties2EXT, &out, - mod_props) - { - mod_props->drmFormatModifier = DRM_FORMAT_MOD_LINEAR; - mod_props->drmFormatModifierPlaneCount = 1; - } - } -} - -static VkResult -get_image_format_properties(struct panvk_physical_device *physical_device, - const VkPhysicalDeviceImageFormatInfo2 *info, - VkImageFormatProperties *pImageFormatProperties, - VkFormatFeatureFlags *p_feature_flags) -{ - VkFormatProperties format_props; - VkFormatFeatureFlags format_feature_flags; - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArraySize; - VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT; - enum pipe_format format = vk_format_to_pipe_format(info->format); - - get_format_properties(physical_device, info->format, &format_props); - - switch (info->tiling) { - case VK_IMAGE_TILING_LINEAR: - format_feature_flags = format_props.linearTilingFeatures; - break; - - case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: - /* The only difference between optimal and linear is currently whether - * depth/stencil attachments are allowed on depth/stencil formats. - * There's no reason to allow importing depth/stencil textures, so just - * disallow it and then this annoying edge case goes away. - * - * TODO: If anyone cares, we could enable this by looking at the - * modifier and checking if it's LINEAR or not. - */ - if (util_format_is_depth_or_stencil(format)) - goto unsupported; - - assert(format_props.optimalTilingFeatures == - format_props.linearTilingFeatures); - FALLTHROUGH; - case VK_IMAGE_TILING_OPTIMAL: - format_feature_flags = format_props.optimalTilingFeatures; - break; - default: - unreachable("bad VkPhysicalDeviceImageFormatInfo2"); - } - - if (format_feature_flags == 0) - goto unsupported; - - if (info->type != VK_IMAGE_TYPE_2D && - util_format_is_depth_or_stencil(format)) - goto unsupported; - - switch (info->type) { - default: - unreachable("bad vkimage type"); - case VK_IMAGE_TYPE_1D: - maxExtent.width = 16384; - maxExtent.height = 1; - maxExtent.depth = 1; - maxMipLevels = 15; /* log2(maxWidth) + 1 */ - maxArraySize = 2048; - break; - case VK_IMAGE_TYPE_2D: - maxExtent.width = 16384; - maxExtent.height = 16384; - maxExtent.depth = 1; - maxMipLevels = 15; /* log2(maxWidth) + 1 */ - maxArraySize = 2048; - break; - case VK_IMAGE_TYPE_3D: - maxExtent.width = 2048; - maxExtent.height = 2048; - maxExtent.depth = 2048; - maxMipLevels = 12; /* log2(maxWidth) + 1 */ - maxArraySize = 1; - break; - } - - if (info->tiling == VK_IMAGE_TILING_OPTIMAL && - info->type == VK_IMAGE_TYPE_2D && - (format_feature_flags & - (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && - !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && - !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) { - sampleCounts |= VK_SAMPLE_COUNT_4_BIT; - } - - if (info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) { - if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { - goto unsupported; - } - } - - if (info->usage & VK_IMAGE_USAGE_STORAGE_BIT) { - if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { - goto unsupported; - } - } - - if (info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { - if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { - goto unsupported; - } - } - - if (info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - if (!(format_feature_flags & - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - goto unsupported; - } - } - - *pImageFormatProperties = (VkImageFormatProperties){ - .maxExtent = maxExtent, - .maxMipLevels = maxMipLevels, - .maxArrayLayers = maxArraySize, - .sampleCounts = sampleCounts, - - /* FINISHME: Accurately calculate - * VkImageFormatProperties::maxResourceSize. - */ - .maxResourceSize = UINT32_MAX, - }; - - if (p_feature_flags) - *p_feature_flags = format_feature_flags; - - return VK_SUCCESS; -unsupported: - *pImageFormatProperties = (VkImageFormatProperties){ - .maxExtent = {0, 0, 0}, - .maxMipLevels = 0, - .maxArrayLayers = 0, - .sampleCounts = 0, - .maxResourceSize = 0, - }; - - return VK_ERROR_FORMAT_NOT_SUPPORTED; -} - -VKAPI_ATTR VkResult VKAPI_CALL -panvk_GetPhysicalDeviceImageFormatProperties( - VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, - VkImageTiling tiling, VkImageUsageFlags usage, - VkImageCreateFlags createFlags, - VkImageFormatProperties *pImageFormatProperties) -{ - VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); - - const VkPhysicalDeviceImageFormatInfo2 info = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - .pNext = NULL, - .format = format, - .type = type, - .tiling = tiling, - .usage = usage, - .flags = createFlags, - }; - - return get_image_format_properties(physical_device, &info, - pImageFormatProperties, NULL); -} - -static VkResult -panvk_get_external_image_format_properties( - const struct panvk_physical_device *physical_device, - const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, - VkExternalMemoryHandleTypeFlagBits handleType, - VkExternalMemoryProperties *external_properties) -{ - VkExternalMemoryFeatureFlagBits flags = 0; - VkExternalMemoryHandleTypeFlags export_flags = 0; - VkExternalMemoryHandleTypeFlags compat_flags = 0; - - /* From the Vulkan 1.1.98 spec: - * - * If handleType is not compatible with the format, type, tiling, - * usage, and flags specified in VkPhysicalDeviceImageFormatInfo2, - * then vkGetPhysicalDeviceImageFormatProperties2 returns - * VK_ERROR_FORMAT_NOT_SUPPORTED. - */ - switch (handleType) { - case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: - case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: - switch (pImageFormatInfo->type) { - case VK_IMAGE_TYPE_2D: - flags = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; - compat_flags = export_flags = - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - break; - default: - return vk_errorf( - physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, - "VkExternalMemoryTypeFlagBits(0x%x) unsupported for VkImageType(%d)", - handleType, pImageFormatInfo->type); - } - break; - case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: - flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; - compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; - break; - default: - return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, - "VkExternalMemoryTypeFlagBits(0x%x) unsupported", - handleType); - } - - *external_properties = (VkExternalMemoryProperties){ - .externalMemoryFeatures = flags, - .exportFromImportedHandleTypes = export_flags, - .compatibleHandleTypes = compat_flags, - }; - - return VK_SUCCESS; -} - -VKAPI_ATTR VkResult VKAPI_CALL -panvk_GetPhysicalDeviceImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2 *base_info, - VkImageFormatProperties2 *base_props) -{ - VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); - const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL; - const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL; - VkExternalImageFormatProperties *external_props = NULL; - VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL; - VkFormatFeatureFlags format_feature_flags; - VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL; - VkResult result; - - result = get_image_format_properties(physical_device, base_info, - &base_props->imageFormatProperties, - &format_feature_flags); - if (result != VK_SUCCESS) - return result; - - /* Extract input structs */ - vk_foreach_struct_const(s, base_info->pNext) { - switch (s->sType) { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: - external_info = (const void *)s; - break; - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT: - image_view_info = (const void *)s; - break; - default: - break; - } - } - - /* Extract output structs */ - vk_foreach_struct(s, base_props->pNext) { - switch (s->sType) { - case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: - external_props = (void *)s; - break; - case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: - cubic_props = (void *)s; - break; - case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: - ycbcr_props = (void *)s; - break; - default: - break; - } - } - - /* From the Vulkan 1.0.42 spec: - * - * If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will - * behave as if VkPhysicalDeviceExternalImageFormatInfo was not - * present and VkExternalImageFormatProperties will be ignored. - */ - if (external_info && external_info->handleType != 0) { - result = panvk_get_external_image_format_properties( - physical_device, base_info, external_info->handleType, - &external_props->externalMemoryProperties); - if (result != VK_SUCCESS) - goto fail; - } - - if (cubic_props) { - /* note: blob only allows cubic filtering for 2D and 2D array views - * its likely we can enable it for 1D and CUBE, needs testing however - */ - if ((image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D || - image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) && - (format_feature_flags & - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT)) { - cubic_props->filterCubic = true; - cubic_props->filterCubicMinmax = true; - } else { - cubic_props->filterCubic = false; - cubic_props->filterCubicMinmax = false; - } - } - - if (ycbcr_props) - ycbcr_props->combinedImageSamplerDescriptorCount = 1; - - return VK_SUCCESS; - -fail: - if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) { - /* From the Vulkan 1.0.42 spec: - * - * If the combination of parameters to - * vkGetPhysicalDeviceImageFormatProperties2 is not supported by - * the implementation for use in vkCreateImage, then all members of - * imageFormatProperties will be filled with zero. - */ - base_props->imageFormatProperties = (VkImageFormatProperties){}; - } - - return result; -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceSparseImageFormatProperties( - VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, - VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, - uint32_t *pNumProperties, VkSparseImageFormatProperties *pProperties) -{ - /* Sparse images are not yet supported. */ - *pNumProperties = 0; -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceSparseImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, - uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties) -{ - /* Sparse images are not yet supported. */ - *pPropertyCount = 0; -} - -VKAPI_ATTR void VKAPI_CALL -panvk_GetPhysicalDeviceExternalBufferProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, - VkExternalBufferProperties *pExternalBufferProperties) -{ - panvk_stub(); -} diff --git a/src/panfrost/vulkan/panvk_image.c b/src/panfrost/vulkan/panvk_image.c index dd4e80b50e4..529a4bf62c0 100644 --- a/src/panfrost/vulkan/panvk_image.c +++ b/src/panfrost/vulkan/panvk_image.c @@ -31,6 +31,7 @@ #include "panvk_device_memory.h" #include "panvk_image.h" #include "panvk_instance.h" +#include "panvk_physical_device.h" #include "panvk_private.h" #include "drm-uapi/drm_fourcc.h" diff --git a/src/panfrost/vulkan/panvk_instance.c b/src/panfrost/vulkan/panvk_instance.c index 5a39270f082..e8eacb58cac 100644 --- a/src/panfrost/vulkan/panvk_instance.c +++ b/src/panfrost/vulkan/panvk_instance.c @@ -14,6 +14,7 @@ #include "panvk_entrypoints.h" #include "panvk_instance.h" +#include "panvk_physical_device.h" #include "panvk_private.h" static const struct debug_control panvk_debug_options[] = { diff --git a/src/panfrost/vulkan/panvk_physical_device.c b/src/panfrost/vulkan/panvk_physical_device.c new file mode 100644 index 00000000000..cd0532c6e94 --- /dev/null +++ b/src/panfrost/vulkan/panvk_physical_device.c @@ -0,0 +1,1250 @@ +/* + * Copyright © 2021 Collabora Ltd. + * + * Derived from tu_device.c which is: + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * Copyright © 2015 Intel Corporation + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include "util/disk_cache.h" + +#include "vk_drm_syncobj.h" +#include "vk_format.h" +#include "vk_log.h" +#include "vk_util.h" + +#include "panvk_physical_device.h" +#include "panvk_private.h" + +#include "pan_format.h" +#include "pan_props.h" + +#include "genxml/gen_macros.h" + +#define MAX_VIEWPORTS 1 +#define MAX_PUSH_DESCRIPTORS 32 + +static int +get_cache_uuid(uint16_t family, void *uuid) +{ + uint32_t mesa_timestamp; + uint16_t f = family; + + if (!disk_cache_get_function_timestamp(get_cache_uuid, &mesa_timestamp)) + return -1; + + memset(uuid, 0, VK_UUID_SIZE); + memcpy(uuid, &mesa_timestamp, 4); + memcpy((char *)uuid + 4, &f, 2); + snprintf((char *)uuid + 6, VK_UUID_SIZE - 10, "pan"); + return 0; +} + +static void +get_driver_uuid(void *uuid) +{ + memset(uuid, 0, VK_UUID_SIZE); + snprintf(uuid, VK_UUID_SIZE, "panfrost"); +} + +static void +get_device_uuid(void *uuid) +{ + memset(uuid, 0, VK_UUID_SIZE); +} + +static void +get_device_extensions(const struct panvk_physical_device *device, + struct vk_device_extension_table *ext) +{ + *ext = (struct vk_device_extension_table){ + .KHR_copy_commands2 = true, + .KHR_shader_expect_assume = true, + .KHR_storage_buffer_storage_class = true, + .KHR_descriptor_update_template = true, +#ifdef PANVK_USE_WSI_PLATFORM + .KHR_swapchain = true, +#endif + .KHR_synchronization2 = true, + .KHR_variable_pointers = true, + .EXT_custom_border_color = true, + .EXT_index_type_uint8 = true, + .EXT_vertex_attribute_divisor = true, + }; +} + +static void +get_features(const struct panvk_physical_device *device, + struct vk_features *features) +{ + *features = (struct vk_features){ + /* Vulkan 1.0 */ + .robustBufferAccess = true, + .fullDrawIndexUint32 = true, + .independentBlend = true, + .logicOp = true, + .wideLines = true, + .largePoints = true, + .textureCompressionETC2 = true, + .textureCompressionASTC_LDR = true, + .shaderUniformBufferArrayDynamicIndexing = true, + .shaderSampledImageArrayDynamicIndexing = true, + .shaderStorageBufferArrayDynamicIndexing = true, + .shaderStorageImageArrayDynamicIndexing = true, + + /* Vulkan 1.1 */ + .storageBuffer16BitAccess = false, + .uniformAndStorageBuffer16BitAccess = false, + .storagePushConstant16 = false, + .storageInputOutput16 = false, + .multiview = false, + .multiviewGeometryShader = false, + .multiviewTessellationShader = false, + .variablePointersStorageBuffer = true, + .variablePointers = true, + .protectedMemory = false, + .samplerYcbcrConversion = false, + .shaderDrawParameters = false, + + /* Vulkan 1.2 */ + .samplerMirrorClampToEdge = false, + .drawIndirectCount = false, + .storageBuffer8BitAccess = false, + .uniformAndStorageBuffer8BitAccess = false, + .storagePushConstant8 = false, + .shaderBufferInt64Atomics = false, + .shaderSharedInt64Atomics = false, + .shaderFloat16 = false, + .shaderInt8 = false, + + .descriptorIndexing = false, + .shaderInputAttachmentArrayDynamicIndexing = false, + .shaderUniformTexelBufferArrayDynamicIndexing = false, + .shaderStorageTexelBufferArrayDynamicIndexing = false, + .shaderUniformBufferArrayNonUniformIndexing = false, + .shaderSampledImageArrayNonUniformIndexing = false, + .shaderStorageBufferArrayNonUniformIndexing = false, + .shaderStorageImageArrayNonUniformIndexing = false, + .shaderInputAttachmentArrayNonUniformIndexing = false, + .shaderUniformTexelBufferArrayNonUniformIndexing = false, + .shaderStorageTexelBufferArrayNonUniformIndexing = false, + .descriptorBindingUniformBufferUpdateAfterBind = false, + .descriptorBindingSampledImageUpdateAfterBind = false, + .descriptorBindingStorageImageUpdateAfterBind = false, + .descriptorBindingStorageBufferUpdateAfterBind = false, + .descriptorBindingUniformTexelBufferUpdateAfterBind = false, + .descriptorBindingStorageTexelBufferUpdateAfterBind = false, + .descriptorBindingUpdateUnusedWhilePending = false, + .descriptorBindingPartiallyBound = false, + .descriptorBindingVariableDescriptorCount = false, + .runtimeDescriptorArray = false, + + .samplerFilterMinmax = false, + .scalarBlockLayout = false, + .imagelessFramebuffer = false, + .uniformBufferStandardLayout = false, + .shaderSubgroupExtendedTypes = false, + .separateDepthStencilLayouts = false, + .hostQueryReset = false, + .timelineSemaphore = false, + .bufferDeviceAddress = true, + .bufferDeviceAddressCaptureReplay = false, + .bufferDeviceAddressMultiDevice = false, + .vulkanMemoryModel = false, + .vulkanMemoryModelDeviceScope = false, + .vulkanMemoryModelAvailabilityVisibilityChains = false, + .shaderOutputViewportIndex = false, + .shaderOutputLayer = false, + .subgroupBroadcastDynamicId = false, + + /* Vulkan 1.3 */ + .robustImageAccess = false, + .inlineUniformBlock = false, + .descriptorBindingInlineUniformBlockUpdateAfterBind = false, + .pipelineCreationCacheControl = false, + .privateData = true, + .shaderDemoteToHelperInvocation = false, + .shaderTerminateInvocation = false, + .subgroupSizeControl = false, + .computeFullSubgroups = false, + .synchronization2 = true, + .textureCompressionASTC_HDR = false, + .shaderZeroInitializeWorkgroupMemory = false, + .dynamicRendering = false, + .shaderIntegerDotProduct = false, + .maintenance4 = false, + + /* VK_EXT_index_type_uint8 */ + .indexTypeUint8 = true, + + /* VK_EXT_vertex_attribute_divisor */ + .vertexAttributeInstanceRateDivisor = true, + .vertexAttributeInstanceRateZeroDivisor = true, + + /* VK_EXT_depth_clip_enable */ + .depthClipEnable = true, + + /* VK_EXT_4444_formats */ + .formatA4R4G4B4 = true, + .formatA4B4G4R4 = true, + + /* VK_EXT_custom_border_color */ + .customBorderColors = true, + .customBorderColorWithoutFormat = true, + + /* VK_KHR_shader_expect_assume */ + .shaderExpectAssume = true, + }; +} + +void +panvk_physical_device_finish(struct panvk_physical_device *device) +{ + panvk_wsi_finish(device); + + pan_kmod_dev_destroy(device->kmod.dev); + if (device->master_fd != -1) + close(device->master_fd); + + vk_physical_device_finish(&device->vk); +} + +VkResult +panvk_physical_device_init(struct panvk_physical_device *device, + struct panvk_instance *instance, + drmDevicePtr drm_device) +{ + const char *path = drm_device->nodes[DRM_NODE_RENDER]; + VkResult result = VK_SUCCESS; + drmVersionPtr version; + int fd; + int master_fd = -1; + + if (!getenv("PAN_I_WANT_A_BROKEN_VULKAN_DRIVER")) { + return vk_errorf( + instance, VK_ERROR_INCOMPATIBLE_DRIVER, + "WARNING: panvk is not a conformant vulkan implementation, " + "pass PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 if you know what you're doing."); + } + + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) { + return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, + "failed to open device %s", path); + } + + version = drmGetVersion(fd); + if (!version) { + close(fd); + return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, + "failed to query kernel driver version for device %s", + path); + } + + if (strcmp(version->name, "panfrost")) { + drmFreeVersion(version); + close(fd); + return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, + "device %s does not use the panfrost kernel driver", + path); + } + + drmFreeVersion(version); + + if (instance->debug_flags & PANVK_DEBUG_STARTUP) + vk_logi(VK_LOG_NO_OBJS(instance), "Found compatible device '%s'.", path); + + struct vk_device_extension_table supported_extensions; + get_device_extensions(device, &supported_extensions); + + struct vk_features supported_features; + get_features(device, &supported_features); + + struct vk_physical_device_dispatch_table dispatch_table; + vk_physical_device_dispatch_table_from_entrypoints( + &dispatch_table, &panvk_physical_device_entrypoints, true); + vk_physical_device_dispatch_table_from_entrypoints( + &dispatch_table, &wsi_physical_device_entrypoints, false); + + result = + vk_physical_device_init(&device->vk, &instance->vk, &supported_extensions, + &supported_features, NULL, &dispatch_table); + + if (result != VK_SUCCESS) { + vk_error(instance, result); + goto fail; + } + + if (instance->vk.enabled_extensions.KHR_display) { + master_fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC); + if (master_fd >= 0) { + /* TODO: free master_fd is accel is not working? */ + } + } + + device->master_fd = master_fd; + + device->kmod.dev = pan_kmod_dev_create(fd, PAN_KMOD_DEV_FLAG_OWNS_FD, + &instance->kmod.allocator); + pan_kmod_dev_query_props(device->kmod.dev, &device->kmod.props); + + unsigned arch = pan_arch(device->kmod.props.gpu_prod_id); + + device->model = panfrost_get_model(device->kmod.props.gpu_prod_id, + device->kmod.props.gpu_variant); + device->formats.all = panfrost_format_table(arch); + device->formats.blendable = panfrost_blendable_format_table(arch); + + if (arch <= 5 || arch >= 8) { + result = vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, + "%s not supported", device->model->name); + goto fail; + } + + memset(device->name, 0, sizeof(device->name)); + sprintf(device->name, "%s", device->model->name); + + if (get_cache_uuid(device->kmod.props.gpu_prod_id, device->cache_uuid)) { + result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, + "cannot generate UUID"); + goto fail_close_device; + } + + vk_warn_non_conformant_implementation("panvk"); + + get_driver_uuid(&device->device_uuid); + get_device_uuid(&device->device_uuid); + + device->drm_syncobj_type = vk_drm_syncobj_get_type(device->kmod.dev->fd); + /* We don't support timelines in the uAPI yet and we don't want it getting + * suddenly turned on by vk_drm_syncobj_get_type() without us adding panvk + * code for it first. + */ + device->drm_syncobj_type.features &= ~VK_SYNC_FEATURE_TIMELINE; + + device->sync_types[0] = &device->drm_syncobj_type; + device->sync_types[1] = NULL; + device->vk.supported_sync_types = device->sync_types; + + result = panvk_wsi_init(device); + if (result != VK_SUCCESS) { + vk_error(instance, result); + goto fail_close_device; + } + + return VK_SUCCESS; + +fail_close_device: + pan_kmod_dev_destroy(device->kmod.dev); +fail: + if (fd != -1) + close(fd); + if (master_fd != -1) + close(master_fd); + return result; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2 *pProperties) +{ + VK_FROM_HANDLE(panvk_physical_device, pdevice, physicalDevice); + + /* HW supports MSAA 4, 8 and 16, but we limit ourselves to MSAA 4 for now. */ + VkSampleCountFlags sample_counts = + VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT; + + const VkPhysicalDeviceLimits limits = { + /* Maximum texture dimension is 2^16. */ + .maxImageDimension1D = (1 << 16), + .maxImageDimension2D = (1 << 16), + .maxImageDimension3D = (1 << 16), + .maxImageDimensionCube = (1 << 16), + .maxImageArrayLayers = (1 << 16), + + /* Currently limited by the 1D texture size, which is 2^16. + * TODO: If we expose buffer views as 2D textures, we can increase the + * limit. + */ + .maxTexelBufferElements = (1 << 16), + + /* Each uniform entry is 16-byte and the number of entries is encoded in a + * 12-bit field, with the minus(1) modifier, which gives 2^20. + */ + .maxUniformBufferRange = 1 << 20, + + /* Storage buffer access is lowered to globals, so there's no limit here, + * except for the SW-descriptor we use to encode storage buffer + * descriptors, where the size is a 32-bit field. + */ + .maxStorageBufferRange = UINT32_MAX, + + /* 128 bytes of push constants, so we're aligned with the minimum Vulkan + * requirements. + */ + .maxPushConstantsSize = 128, + + /* There's no HW limit here. Should we advertize something smaller? */ + .maxMemoryAllocationCount = UINT32_MAX, + + /* Again, no hardware limit, but most drivers seem to advertive 64k. */ + .maxSamplerAllocationCount = 64 * 1024, + + /* A cache line. */ + .bufferImageGranularity = 64, + + /* Sparse binding not supported yet. */ + .sparseAddressSpaceSize = 0, + + /* Software limit. Pick the minimum required by Vulkan, because Bifrost + * GPUs don't have unified descriptor tables, which forces us to + * agregatte all descriptors from all sets and dispatch them to per-type + * descriptor tables emitted at draw/dispatch time. + * The more sets we support the more copies we are likely to have to do + * at draw time. + */ + .maxBoundDescriptorSets = 4, + + /* MALI_RENDERER_STATE::sampler_count is 16-bit. */ + .maxPerStageDescriptorSamplers = UINT16_MAX, + .maxDescriptorSetSamplers = UINT16_MAX, + + /* MALI_RENDERER_STATE::uniform_buffer_count is 8-bit. We reserve 32 slots + * for our internal UBOs. + */ + .maxPerStageDescriptorUniformBuffers = UINT8_MAX - 32, + .maxDescriptorSetUniformBuffers = UINT8_MAX - 32, + + /* SSBOs are limited by the size of a uniform buffer which contains our + * panvk_ssbo_desc objects. + * panvk_ssbo_desc is 16-byte, and each uniform entry in the Mali UBO is + * 16-byte too. The number of entries is encoded in a 12-bit field, with + * a minus(1) modifier, which gives a maximum of 2^12 SSBO + * descriptors. + */ + .maxPerStageDescriptorStorageBuffers = 1 << 12, + .maxDescriptorSetStorageBuffers = 1 << 12, + + /* MALI_RENDERER_STATE::sampler_count is 16-bit. */ + .maxPerStageDescriptorSampledImages = UINT16_MAX, + .maxDescriptorSetSampledImages = UINT16_MAX, + + /* MALI_ATTRIBUTE::buffer_index is 9-bit, and each image takes two + * MALI_ATTRIBUTE_BUFFER slots, which gives a maximum of (1 << 8) images. + */ + .maxPerStageDescriptorStorageImages = 1 << 8, + .maxDescriptorSetStorageImages = 1 << 8, + + /* A maximum of 8 color render targets, and one depth-stencil render + * target. + */ + .maxPerStageDescriptorInputAttachments = 9, + .maxDescriptorSetInputAttachments = 9, + + /* Could be the sum of all maxPerStageXxx values, but we limit ourselves + * to 2^16 to make things simpler. + */ + .maxPerStageResources = 1 << 16, + + /* Software limits to keep VkCommandBuffer tracking sane. */ + .maxDescriptorSetUniformBuffersDynamic = 16, + .maxDescriptorSetStorageBuffersDynamic = 8, + + /* Software limit to keep VkCommandBuffer tracking sane. The HW supports + * up to 2^9 vertex attributes. + */ + .maxVertexInputAttributes = 16, + .maxVertexInputBindings = 16, + + /* MALI_ATTRIBUTE::offset is 32-bit. */ + .maxVertexInputAttributeOffset = UINT32_MAX, + + /* MALI_ATTRIBUTE_BUFFER::stride is 32-bit. */ + .maxVertexInputBindingStride = UINT32_MAX, + + /* 32 vec4 varyings. */ + .maxVertexOutputComponents = 128, + + /* Tesselation shaders not supported. */ + .maxTessellationGenerationLevel = 0, + .maxTessellationPatchSize = 0, + .maxTessellationControlPerVertexInputComponents = 0, + .maxTessellationControlPerVertexOutputComponents = 0, + .maxTessellationControlPerPatchOutputComponents = 0, + .maxTessellationControlTotalOutputComponents = 0, + .maxTessellationEvaluationInputComponents = 0, + .maxTessellationEvaluationOutputComponents = 0, + + /* Geometry shaders not supported. */ + .maxGeometryShaderInvocations = 0, + .maxGeometryInputComponents = 0, + .maxGeometryOutputComponents = 0, + .maxGeometryOutputVertices = 0, + .maxGeometryTotalOutputComponents = 0, + + /* 32 vec4 varyings. */ + .maxFragmentInputComponents = 128, + + /* 8 render targets. */ + .maxFragmentOutputAttachments = 8, + + /* We don't support dual source blending yet. */ + .maxFragmentDualSrcAttachments = 0, + + /* 8 render targets, 2^12 storage buffers and 2^8 storage images (see + * above). + */ + .maxFragmentCombinedOutputResources = 8 + (1 << 12) + (1 << 8), + + /* MALI_LOCAL_STORAGE::wls_size_{base,scale} allows us to have up to + * (7 << 30) bytes of shared memory, but we cap it to 32K as it doesn't + * really make sense to expose this amount of memory, especially since + * it's backed by global memory anyway. + */ + .maxComputeSharedMemorySize = 32768, + + /* Software limit to meet Vulkan 1.0 requirements. We split the + * dispatch in several jobs if it's too big. + */ + .maxComputeWorkGroupCount = {65535, 65535, 65535}, + + /* We have 10 bits to encode the local-size, and there's a minus(1) + * modifier, so, a size of 1 takes no bit. + */ + .maxComputeWorkGroupInvocations = 1 << 10, + .maxComputeWorkGroupSize = {1 << 10, 1 << 10, 1 << 10}, + + /* 8-bit subpixel precision. */ + .subPixelPrecisionBits = 8, + .subTexelPrecisionBits = 8, + .mipmapPrecisionBits = 8, + + /* Software limit. */ + .maxDrawIndexedIndexValue = UINT32_MAX, + + /* Make it one for now. */ + .maxDrawIndirectCount = 1, + + .maxSamplerLodBias = 255, + .maxSamplerAnisotropy = 16, + .maxViewports = 1, + + /* Same as the framebuffer limit. */ + .maxViewportDimensions = {(1 << 14), (1 << 14)}, + + /* Encoded in a 16-bit signed integer. */ + .viewportBoundsRange = {INT16_MIN, INT16_MAX}, + .viewportSubPixelBits = 0, + + /* Align on a page. */ + .minMemoryMapAlignment = 4096, + + /* Some compressed texture formats require 128-byte alignment. */ + .minTexelBufferOffsetAlignment = 64, + + /* Always aligned on a uniform slot (vec4). */ + .minUniformBufferOffsetAlignment = 16, + + /* Lowered to global accesses, which happen at the 32-bit granularity. */ + .minStorageBufferOffsetAlignment = 4, + + /* Signed 4-bit value. */ + .minTexelOffset = -8, + .maxTexelOffset = 7, + .minTexelGatherOffset = -8, + .maxTexelGatherOffset = 7, + .minInterpolationOffset = -0.5, + .maxInterpolationOffset = 0.5, + .subPixelInterpolationOffsetBits = 8, + + .maxFramebufferWidth = (1 << 14), + .maxFramebufferHeight = (1 << 14), + .maxFramebufferLayers = 256, + .framebufferColorSampleCounts = sample_counts, + .framebufferDepthSampleCounts = sample_counts, + .framebufferStencilSampleCounts = sample_counts, + .framebufferNoAttachmentsSampleCounts = sample_counts, + .maxColorAttachments = 8, + .sampledImageColorSampleCounts = sample_counts, + .sampledImageIntegerSampleCounts = VK_SAMPLE_COUNT_1_BIT, + .sampledImageDepthSampleCounts = sample_counts, + .sampledImageStencilSampleCounts = sample_counts, + .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT, + .maxSampleMaskWords = 1, + .timestampComputeAndGraphics = false, + .timestampPeriod = 0, + .maxClipDistances = 0, + .maxCullDistances = 0, + .maxCombinedClipAndCullDistances = 0, + .discreteQueuePriorities = 1, + .pointSizeRange = {0.125, 4095.9375}, + .lineWidthRange = {0.0, 7.9921875}, + .pointSizeGranularity = (1.0 / 16.0), + .lineWidthGranularity = (1.0 / 128.0), + .strictLines = false, + .standardSampleLocations = true, + .optimalBufferCopyOffsetAlignment = 64, + .optimalBufferCopyRowPitchAlignment = 64, + .nonCoherentAtomSize = 64, + }; + + pProperties->properties = (VkPhysicalDeviceProperties){ + .apiVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION), + .driverVersion = vk_get_driver_version(), + + /* Arm vendor ID. */ + .vendorID = 0x13b5, + + /* Collect arch_major, arch_minor, arch_rev and product_major, + * as done by the Arm driver. + */ + .deviceID = pdevice->kmod.props.gpu_prod_id << 16, + .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, + .limits = limits, + .sparseProperties = {0}, + }; + + strcpy(pProperties->properties.deviceName, pdevice->name); + memcpy(pProperties->properties.pipelineCacheUUID, pdevice->cache_uuid, + VK_UUID_SIZE); + + VkPhysicalDeviceVulkan11Properties core_1_1 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES, + .deviceLUIDValid = false, + .pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, + .maxMultiviewViewCount = 0, + .maxMultiviewInstanceIndex = 0, + .protectedNoFault = false, + /* Make sure everything is addressable by a signed 32-bit int, and + * our largest descriptors are 96 bytes. */ + .maxPerSetDescriptors = (1ull << 31) / 96, + /* Our buffer size fields allow only this much */ + .maxMemoryAllocationSize = 0xFFFFFFFFull, + }; + memcpy(core_1_1.driverUUID, pdevice->driver_uuid, VK_UUID_SIZE); + memcpy(core_1_1.deviceUUID, pdevice->device_uuid, VK_UUID_SIZE); + + const VkPhysicalDeviceVulkan12Properties core_1_2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES, + }; + + const VkPhysicalDeviceVulkan13Properties core_1_3 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES, + }; + + vk_foreach_struct(ext, pProperties->pNext) { + if (vk_get_physical_device_core_1_1_property_ext(ext, &core_1_1)) + continue; + if (vk_get_physical_device_core_1_2_property_ext(ext, &core_1_2)) + continue; + if (vk_get_physical_device_core_1_3_property_ext(ext, &core_1_3)) + continue; + + switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: { + VkPhysicalDevicePushDescriptorPropertiesKHR *properties = + (VkPhysicalDevicePushDescriptorPropertiesKHR *)ext; + properties->maxPushDescriptors = 0; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: { + VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *properties = + (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext; + /* We will have to restrict this a bit for multiview */ + properties->maxVertexAttribDivisor = UINT32_MAX; + break; + } + default: + break; + } + } +} + +static const VkQueueFamilyProperties panvk_queue_family_properties = { + .queueFlags = + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, + .queueCount = 1, + .timestampValidBits = 0, + .minImageTransferGranularity = {1, 1, 1}, +}; + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, + VkQueueFamilyProperties2 *pQueueFamilyProperties) +{ + VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out, pQueueFamilyProperties, + pQueueFamilyPropertyCount); + + vk_outarray_append_typed(VkQueueFamilyProperties2, &out, p) + { + p->queueFamilyProperties = panvk_queue_family_properties; + } +} + +static uint64_t +get_system_heap_size() +{ + struct sysinfo info; + sysinfo(&info); + + uint64_t total_ram = (uint64_t)info.totalram * info.mem_unit; + + /* We don't want to burn too much ram with the GPU. If the user has 4GiB + * or less, we use at most half. If they have more than 4GiB, we use 3/4. + */ + uint64_t available_ram; + if (total_ram <= 4ull * 1024 * 1024 * 1024) + available_ram = total_ram / 2; + else + available_ram = total_ram * 3 / 4; + + return available_ram; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) +{ + pMemoryProperties->memoryProperties = (VkPhysicalDeviceMemoryProperties){ + .memoryHeapCount = 1, + .memoryHeaps[0].size = get_system_heap_size(), + .memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + .memoryTypeCount = 1, + .memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + .memoryTypes[0].heapIndex = 0, + }; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceExternalSemaphoreProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, + VkExternalSemaphoreProperties *pExternalSemaphoreProperties) +{ + if ((pExternalSemaphoreInfo->handleType == + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT || + pExternalSemaphoreInfo->handleType == + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)) { + pExternalSemaphoreProperties->exportFromImportedHandleTypes = + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; + pExternalSemaphoreProperties->compatibleHandleTypes = + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; + pExternalSemaphoreProperties->externalSemaphoreFeatures = + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; + } else { + pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; + pExternalSemaphoreProperties->compatibleHandleTypes = 0; + pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; + } +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceExternalFenceProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, + VkExternalFenceProperties *pExternalFenceProperties) +{ + pExternalFenceProperties->exportFromImportedHandleTypes = 0; + pExternalFenceProperties->compatibleHandleTypes = 0; + pExternalFenceProperties->externalFenceFeatures = 0; +} + +#define DEVICE_PER_ARCH_FUNCS(_ver) \ + VkResult panvk_v##_ver##_create_device( \ + struct panvk_physical_device *physical_device, \ + const VkDeviceCreateInfo *pCreateInfo, \ + const VkAllocationCallbacks *pAllocator, VkDevice *pDevice); \ + \ + void panvk_v##_ver##_destroy_device( \ + struct panvk_device *device, const VkAllocationCallbacks *pAllocator) + +DEVICE_PER_ARCH_FUNCS(6); +DEVICE_PER_ARCH_FUNCS(7); + +VKAPI_ATTR VkResult VKAPI_CALL +panvk_CreateDevice(VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) +{ + VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); + unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id); + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + + panvk_arch_dispatch_ret(arch, create_device, result, physical_device, + pCreateInfo, pAllocator, pDevice); + + return result; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(panvk_device, device, _device); + struct panvk_physical_device *physical_device = + to_panvk_physical_device(device->vk.physical); + unsigned arch = pan_arch(physical_device->kmod.props.gpu_prod_id); + + panvk_arch_dispatch(arch, destroy_device, device, pAllocator); +} + +static void +get_format_properties(struct panvk_physical_device *physical_device, + VkFormat format, VkFormatProperties *out_properties) +{ + VkFormatFeatureFlags tex = 0, buffer = 0; + enum pipe_format pfmt = vk_format_to_pipe_format(format); + const struct panfrost_format fmt = physical_device->formats.all[pfmt]; + + if (!pfmt || !fmt.hw) + goto end; + + /* 3byte formats are not supported by the buffer <-> image copy helpers. */ + if (util_format_get_blocksize(pfmt) == 3) + goto end; + + /* We don't support compressed formats yet: this is causing trouble when + * doing a vkCmdCopyImage() between a compressed and a non-compressed format + * on a tiled/AFBC resource. + */ + if (util_format_is_compressed(pfmt)) + goto end; + + buffer |= + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT; + + if (fmt.bind & PAN_BIND_VERTEX_BUFFER) + buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT; + + if (fmt.bind & PAN_BIND_SAMPLER_VIEW) { + tex |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + VK_FORMAT_FEATURE_TRANSFER_DST_BIT | + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT | + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT; + + /* Integer formats only support nearest filtering */ + if (!util_format_is_scaled(pfmt) && !util_format_is_pure_integer(pfmt)) + tex |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; + + buffer |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; + + tex |= VK_FORMAT_FEATURE_BLIT_SRC_BIT; + } + + /* SNORM rendering isn't working yet, disable */ + if (fmt.bind & PAN_BIND_RENDER_TARGET && !util_format_is_snorm(pfmt)) { + tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | + VK_FORMAT_FEATURE_BLIT_DST_BIT; + + tex |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT; + + /* Can always blend via blend shaders */ + tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; + } + + if (fmt.bind & PAN_BIND_DEPTH_STENCIL) + tex |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + +end: + out_properties->linearTilingFeatures = tex; + out_properties->optimalTilingFeatures = tex; + out_properties->bufferFeatures = buffer; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties *pFormatProperties) +{ + VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); + + get_format_properties(physical_device, format, pFormatProperties); +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties2 *pFormatProperties) +{ + VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); + + get_format_properties(physical_device, format, + &pFormatProperties->formatProperties); + + VkDrmFormatModifierPropertiesListEXT *list = vk_find_struct( + pFormatProperties->pNext, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT); + if (list) { + VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierPropertiesEXT, out, + list->pDrmFormatModifierProperties, + &list->drmFormatModifierCount); + + vk_outarray_append_typed(VkDrmFormatModifierProperties2EXT, &out, + mod_props) + { + mod_props->drmFormatModifier = DRM_FORMAT_MOD_LINEAR; + mod_props->drmFormatModifierPlaneCount = 1; + } + } +} + +static VkResult +get_image_format_properties(struct panvk_physical_device *physical_device, + const VkPhysicalDeviceImageFormatInfo2 *info, + VkImageFormatProperties *pImageFormatProperties, + VkFormatFeatureFlags *p_feature_flags) +{ + VkFormatProperties format_props; + VkFormatFeatureFlags format_feature_flags; + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArraySize; + VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT; + enum pipe_format format = vk_format_to_pipe_format(info->format); + + get_format_properties(physical_device, info->format, &format_props); + + switch (info->tiling) { + case VK_IMAGE_TILING_LINEAR: + format_feature_flags = format_props.linearTilingFeatures; + break; + + case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: + /* The only difference between optimal and linear is currently whether + * depth/stencil attachments are allowed on depth/stencil formats. + * There's no reason to allow importing depth/stencil textures, so just + * disallow it and then this annoying edge case goes away. + * + * TODO: If anyone cares, we could enable this by looking at the + * modifier and checking if it's LINEAR or not. + */ + if (util_format_is_depth_or_stencil(format)) + goto unsupported; + + assert(format_props.optimalTilingFeatures == + format_props.linearTilingFeatures); + FALLTHROUGH; + case VK_IMAGE_TILING_OPTIMAL: + format_feature_flags = format_props.optimalTilingFeatures; + break; + default: + unreachable("bad VkPhysicalDeviceImageFormatInfo2"); + } + + if (format_feature_flags == 0) + goto unsupported; + + if (info->type != VK_IMAGE_TYPE_2D && + util_format_is_depth_or_stencil(format)) + goto unsupported; + + switch (info->type) { + default: + unreachable("bad vkimage type"); + case VK_IMAGE_TYPE_1D: + maxExtent.width = 16384; + maxExtent.height = 1; + maxExtent.depth = 1; + maxMipLevels = 15; /* log2(maxWidth) + 1 */ + maxArraySize = 2048; + break; + case VK_IMAGE_TYPE_2D: + maxExtent.width = 16384; + maxExtent.height = 16384; + maxExtent.depth = 1; + maxMipLevels = 15; /* log2(maxWidth) + 1 */ + maxArraySize = 2048; + break; + case VK_IMAGE_TYPE_3D: + maxExtent.width = 2048; + maxExtent.height = 2048; + maxExtent.depth = 2048; + maxMipLevels = 12; /* log2(maxWidth) + 1 */ + maxArraySize = 1; + break; + } + + if (info->tiling == VK_IMAGE_TILING_OPTIMAL && + info->type == VK_IMAGE_TYPE_2D && + (format_feature_flags & + (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && + !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && + !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) { + sampleCounts |= VK_SAMPLE_COUNT_4_BIT; + } + + if (info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) { + if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { + goto unsupported; + } + } + + if (info->usage & VK_IMAGE_USAGE_STORAGE_BIT) { + if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { + goto unsupported; + } + } + + if (info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { + if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { + goto unsupported; + } + } + + if (info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + if (!(format_feature_flags & + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + goto unsupported; + } + } + + *pImageFormatProperties = (VkImageFormatProperties){ + .maxExtent = maxExtent, + .maxMipLevels = maxMipLevels, + .maxArrayLayers = maxArraySize, + .sampleCounts = sampleCounts, + + /* FINISHME: Accurately calculate + * VkImageFormatProperties::maxResourceSize. + */ + .maxResourceSize = UINT32_MAX, + }; + + if (p_feature_flags) + *p_feature_flags = format_feature_flags; + + return VK_SUCCESS; +unsupported: + *pImageFormatProperties = (VkImageFormatProperties){ + .maxExtent = {0, 0, 0}, + .maxMipLevels = 0, + .maxArrayLayers = 0, + .sampleCounts = 0, + .maxResourceSize = 0, + }; + + return VK_ERROR_FORMAT_NOT_SUPPORTED; +} + +VKAPI_ATTR VkResult VKAPI_CALL +panvk_GetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, + VkImageTiling tiling, VkImageUsageFlags usage, + VkImageCreateFlags createFlags, + VkImageFormatProperties *pImageFormatProperties) +{ + VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); + + const VkPhysicalDeviceImageFormatInfo2 info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .pNext = NULL, + .format = format, + .type = type, + .tiling = tiling, + .usage = usage, + .flags = createFlags, + }; + + return get_image_format_properties(physical_device, &info, + pImageFormatProperties, NULL); +} + +static VkResult +panvk_get_external_image_format_properties( + const struct panvk_physical_device *physical_device, + const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, + VkExternalMemoryHandleTypeFlagBits handleType, + VkExternalMemoryProperties *external_properties) +{ + VkExternalMemoryFeatureFlagBits flags = 0; + VkExternalMemoryHandleTypeFlags export_flags = 0; + VkExternalMemoryHandleTypeFlags compat_flags = 0; + + /* From the Vulkan 1.1.98 spec: + * + * If handleType is not compatible with the format, type, tiling, + * usage, and flags specified in VkPhysicalDeviceImageFormatInfo2, + * then vkGetPhysicalDeviceImageFormatProperties2 returns + * VK_ERROR_FORMAT_NOT_SUPPORTED. + */ + switch (handleType) { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + switch (pImageFormatInfo->type) { + case VK_IMAGE_TYPE_2D: + flags = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + compat_flags = export_flags = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + break; + default: + return vk_errorf( + physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, + "VkExternalMemoryTypeFlagBits(0x%x) unsupported for VkImageType(%d)", + handleType, pImageFormatInfo->type); + } + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; + break; + default: + return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, + "VkExternalMemoryTypeFlagBits(0x%x) unsupported", + handleType); + } + + *external_properties = (VkExternalMemoryProperties){ + .externalMemoryFeatures = flags, + .exportFromImportedHandleTypes = export_flags, + .compatibleHandleTypes = compat_flags, + }; + + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult VKAPI_CALL +panvk_GetPhysicalDeviceImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceImageFormatInfo2 *base_info, + VkImageFormatProperties2 *base_props) +{ + VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); + const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL; + const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL; + VkExternalImageFormatProperties *external_props = NULL; + VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL; + VkFormatFeatureFlags format_feature_flags; + VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL; + VkResult result; + + result = get_image_format_properties(physical_device, base_info, + &base_props->imageFormatProperties, + &format_feature_flags); + if (result != VK_SUCCESS) + return result; + + /* Extract input structs */ + vk_foreach_struct_const(s, base_info->pNext) { + switch (s->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: + external_info = (const void *)s; + break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT: + image_view_info = (const void *)s; + break; + default: + break; + } + } + + /* Extract output structs */ + vk_foreach_struct(s, base_props->pNext) { + switch (s->sType) { + case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: + external_props = (void *)s; + break; + case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: + cubic_props = (void *)s; + break; + case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: + ycbcr_props = (void *)s; + break; + default: + break; + } + } + + /* From the Vulkan 1.0.42 spec: + * + * If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will + * behave as if VkPhysicalDeviceExternalImageFormatInfo was not + * present and VkExternalImageFormatProperties will be ignored. + */ + if (external_info && external_info->handleType != 0) { + result = panvk_get_external_image_format_properties( + physical_device, base_info, external_info->handleType, + &external_props->externalMemoryProperties); + if (result != VK_SUCCESS) + goto fail; + } + + if (cubic_props) { + /* note: blob only allows cubic filtering for 2D and 2D array views + * its likely we can enable it for 1D and CUBE, needs testing however + */ + if ((image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D || + image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) && + (format_feature_flags & + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT)) { + cubic_props->filterCubic = true; + cubic_props->filterCubicMinmax = true; + } else { + cubic_props->filterCubic = false; + cubic_props->filterCubicMinmax = false; + } + } + + if (ycbcr_props) + ycbcr_props->combinedImageSamplerDescriptorCount = 1; + + return VK_SUCCESS; + +fail: + if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) { + /* From the Vulkan 1.0.42 spec: + * + * If the combination of parameters to + * vkGetPhysicalDeviceImageFormatProperties2 is not supported by + * the implementation for use in vkCreateImage, then all members of + * imageFormatProperties will be filled with zero. + */ + base_props->imageFormatProperties = (VkImageFormatProperties){}; + } + + return result; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, + VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, + uint32_t *pNumProperties, VkSparseImageFormatProperties *pProperties) +{ + /* Sparse images are not yet supported. */ + *pNumProperties = 0; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceSparseImageFormatProperties2( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, + uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties) +{ + /* Sparse images are not yet supported. */ + *pPropertyCount = 0; +} + +VKAPI_ATTR void VKAPI_CALL +panvk_GetPhysicalDeviceExternalBufferProperties( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, + VkExternalBufferProperties *pExternalBufferProperties) +{ + panvk_stub(); +} diff --git a/src/panfrost/vulkan/panvk_physical_device.h b/src/panfrost/vulkan/panvk_physical_device.h new file mode 100644 index 00000000000..a8d49bee44b --- /dev/null +++ b/src/panfrost/vulkan/panvk_physical_device.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2021 Collabora Ltd. + * SPDX-License-Identifier: MIT + */ + +#ifndef PANVK_PHYSICAL_DEVICE_H +#define PANVK_PHYSICAL_DEVICE_H + +#include + +#include "panvk_instance.h" + +#include "vk_physical_device.h" +#include "vk_sync.h" +#include "wsi_common.h" + +#include "lib/kmod/pan_kmod.h" + +struct panfrost_model; +struct pan_blendable_format; +struct panfrost_format; +struct panvk_instance; + +struct panvk_physical_device { + struct vk_physical_device vk; + + struct { + struct pan_kmod_dev *dev; + struct pan_kmod_dev_props props; + } kmod; + + const struct panfrost_model *model; + struct { + const struct pan_blendable_format *blendable; + const struct panfrost_format *all; + } formats; + + char name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; + uint8_t driver_uuid[VK_UUID_SIZE]; + uint8_t device_uuid[VK_UUID_SIZE]; + uint8_t cache_uuid[VK_UUID_SIZE]; + + struct vk_sync_type drm_syncobj_type; + const struct vk_sync_type *sync_types[2]; + + struct wsi_device wsi_device; + + int master_fd; +}; + +VK_DEFINE_HANDLE_CASTS(panvk_physical_device, vk.base, VkPhysicalDevice, + VK_OBJECT_TYPE_PHYSICAL_DEVICE) + +static inline struct panvk_physical_device * +to_panvk_physical_device(struct vk_physical_device *phys_dev) +{ + return container_of(phys_dev, struct panvk_physical_device, vk); +} + +VkResult panvk_physical_device_init(struct panvk_physical_device *device, + struct panvk_instance *instance, + drmDevicePtr drm_device); + +void panvk_physical_device_finish(struct panvk_physical_device *device); + +#endif diff --git a/src/panfrost/vulkan/panvk_private.h b/src/panfrost/vulkan/panvk_private.h index 4e79e16f290..c7b6344c94d 100644 --- a/src/panfrost/vulkan/panvk_private.h +++ b/src/panfrost/vulkan/panvk_private.h @@ -72,6 +72,7 @@ #include "panvk_instance.h" #include "panvk_macros.h" #include "panvk_mempool.h" +#include "panvk_physical_device.h" #include "panvk_pipeline.h" #include "panvk_pipeline_layout.h" #include "panvk_shader.h" @@ -187,52 +188,9 @@ struct panvk_meta { } copy; }; -struct panvk_physical_device { - struct vk_physical_device vk; - - struct { - struct pan_kmod_dev *dev; - struct pan_kmod_dev_props props; - } kmod; - - const struct panfrost_model *model; - struct { - const struct pan_blendable_format *blendable; - const struct panfrost_format *all; - } formats; - - char name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; - uint8_t driver_uuid[VK_UUID_SIZE]; - uint8_t device_uuid[VK_UUID_SIZE]; - uint8_t cache_uuid[VK_UUID_SIZE]; - - struct vk_sync_type drm_syncobj_type; - const struct vk_sync_type *sync_types[2]; - - struct wsi_device wsi_device; - - int master_fd; -}; - -static inline struct panvk_physical_device * -to_panvk_physical_device(struct vk_physical_device *phys_dev) -{ - return container_of(phys_dev, struct panvk_physical_device, vk); -} - VkResult panvk_wsi_init(struct panvk_physical_device *physical_device); void panvk_wsi_finish(struct panvk_physical_device *physical_device); -uint32_t panvk_physical_device_api_version(struct panvk_physical_device *dev); -bool -panvk_physical_device_extension_supported(struct panvk_physical_device *dev, - const char *name); - -void panvk_physical_device_finish(struct panvk_physical_device *device); -VkResult panvk_physical_device_init(struct panvk_physical_device *device, - struct panvk_instance *instance, - drmDevicePtr drm_device); - #define PANVK_MAX_QUEUE_FAMILIES 1 struct panvk_device { @@ -446,8 +404,6 @@ void panvk_cmd_preload_fb_after_batch_split(struct panvk_cmd_buffer *cmdbuf); VK_DEFINE_HANDLE_CASTS(panvk_cmd_buffer, vk.base, VkCommandBuffer, VK_OBJECT_TYPE_COMMAND_BUFFER) VK_DEFINE_HANDLE_CASTS(panvk_device, vk.base, VkDevice, VK_OBJECT_TYPE_DEVICE) -VK_DEFINE_HANDLE_CASTS(panvk_physical_device, vk.base, VkPhysicalDevice, - VK_OBJECT_TYPE_PHYSICAL_DEVICE) #ifdef PAN_ARCH #include "panvk_vX_cmd_buffer.h" diff --git a/src/panfrost/vulkan/panvk_vX_cmd_buffer.c b/src/panfrost/vulkan/panvk_vX_cmd_buffer.c index 9d59713cc15..878b3069e4e 100644 --- a/src/panfrost/vulkan/panvk_vX_cmd_buffer.c +++ b/src/panfrost/vulkan/panvk_vX_cmd_buffer.c @@ -34,6 +34,7 @@ #include "panvk_image.h" #include "panvk_image_view.h" #include "panvk_instance.h" +#include "panvk_physical_device.h" #include "panvk_pipeline.h" #include "panvk_pipeline_layout.h" #include "panvk_private.h" diff --git a/src/panfrost/vulkan/panvk_vX_device.c b/src/panfrost/vulkan/panvk_vX_device.c index 910cdb18edd..f31e5afd18c 100644 --- a/src/panfrost/vulkan/panvk_vX_device.c +++ b/src/panfrost/vulkan/panvk_vX_device.c @@ -14,6 +14,7 @@ #include "panvk_instance.h" #include "panvk_macros.h" +#include "panvk_physical_device.h" #include "panvk_private.h" #include "panvk_queue.h" diff --git a/src/panfrost/vulkan/panvk_vX_meta_blit.c b/src/panfrost/vulkan/panvk_vX_meta_blit.c index 42c1539e0a7..7f7adffafcb 100644 --- a/src/panfrost/vulkan/panvk_vX_meta_blit.c +++ b/src/panfrost/vulkan/panvk_vX_meta_blit.c @@ -27,6 +27,7 @@ #include "pan_props.h" #include "panvk_image.h" +#include "panvk_physical_device.h" #include "panvk_private.h" static void diff --git a/src/panfrost/vulkan/panvk_vX_meta_clear.c b/src/panfrost/vulkan/panvk_vX_meta_clear.c index 93ee5067b54..e50d2367841 100644 --- a/src/panfrost/vulkan/panvk_vX_meta_clear.c +++ b/src/panfrost/vulkan/panvk_vX_meta_clear.c @@ -28,6 +28,7 @@ #include "pan_shader.h" #include "panvk_image.h" +#include "panvk_physical_device.h" #include "panvk_private.h" #include "panvk_vX_meta.h" diff --git a/src/panfrost/vulkan/panvk_vX_meta_copy.c b/src/panfrost/vulkan/panvk_vX_meta_copy.c index 935389af429..2bdb9533cb3 100644 --- a/src/panfrost/vulkan/panvk_vX_meta_copy.c +++ b/src/panfrost/vulkan/panvk_vX_meta_copy.c @@ -30,6 +30,7 @@ #include "panvk_buffer.h" #include "panvk_image.h" +#include "panvk_physical_device.h" #include "panvk_private.h" static mali_ptr diff --git a/src/panfrost/vulkan/panvk_vX_queue.c b/src/panfrost/vulkan/panvk_vX_queue.c index 49a6f31c280..bbcb2e15734 100644 --- a/src/panfrost/vulkan/panvk_vX_queue.c +++ b/src/panfrost/vulkan/panvk_vX_queue.c @@ -17,6 +17,7 @@ #include "panvk_image.h" #include "panvk_image_view.h" #include "panvk_instance.h" +#include "panvk_physical_device.h" #include "panvk_private.h" #include "panvk_queue.h" diff --git a/src/panfrost/vulkan/panvk_vX_shader.c b/src/panfrost/vulkan/panvk_vX_shader.c index 60c450738d6..7bf7af8d84f 100644 --- a/src/panfrost/vulkan/panvk_vX_shader.c +++ b/src/panfrost/vulkan/panvk_vX_shader.c @@ -30,6 +30,7 @@ #include "genxml/gen_macros.h" #include "panvk_instance.h" +#include "panvk_physical_device.h" #include "panvk_pipeline_layout.h" #include "panvk_private.h" #include "panvk_shader.h" diff --git a/src/panfrost/vulkan/panvk_wsi.c b/src/panfrost/vulkan/panvk_wsi.c index 575aa0395bc..44348b67604 100644 --- a/src/panfrost/vulkan/panvk_wsi.c +++ b/src/panfrost/vulkan/panvk_wsi.c @@ -26,6 +26,7 @@ */ #include "panvk_instance.h" +#include "panvk_physical_device.h" #include "panvk_private.h" #include "vk_util.h"