};
}
-VkResult pvr_EnumerateInstanceVersion(uint32_t *pApiVersion)
-{
- *pApiVersion = PVR_API_VERSION;
- return VK_SUCCESS;
-}
-
-VkResult
-pvr_EnumerateInstanceExtensionProperties(const char *pLayerName,
- uint32_t *pPropertyCount,
- VkExtensionProperties *pProperties)
-{
- if (pLayerName)
- return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
-
- return vk_enumerate_instance_extension_properties(&pvr_instance_extensions,
- pPropertyCount,
- pProperties);
-}
-
-static void pvr_physical_device_destroy(struct vk_physical_device *vk_pdevice)
-{
- struct pvr_physical_device *pdevice =
- container_of(vk_pdevice, struct pvr_physical_device, vk);
-
- /* Be careful here. The device might not have been initialized. This can
- * happen since initialization is done in vkEnumeratePhysicalDevices() but
- * finish is done in vkDestroyInstance(). Make sure that you check for NULL
- * before freeing or that the freeing functions accept NULL pointers.
- */
-
- if (pdevice->compiler)
- ralloc_free(pdevice->compiler);
-
- pvr_wsi_finish(pdevice);
-
- free(pdevice->name);
-
- if (pdevice->ws)
- pvr_winsys_destroy(pdevice->ws);
-
- vk_free(&pdevice->vk.instance->alloc, pdevice->render_path);
- vk_free(&pdevice->vk.instance->alloc, pdevice->display_path);
-
- vk_physical_device_finish(&pdevice->vk);
-
- vk_free(&pdevice->vk.instance->alloc, pdevice);
-}
-
-void pvr_DestroyInstance(VkInstance _instance,
- const VkAllocationCallbacks *pAllocator)
-{
- PVR_FROM_HANDLE(pvr_instance, instance, _instance);
-
- if (!instance)
- return;
-
- VG(VALGRIND_DESTROY_MEMPOOL(instance));
-
- vk_instance_finish(&instance->vk);
- vk_free(&instance->vk.alloc, instance);
-}
-
static VkResult
pvr_physical_device_init_uuids(struct pvr_physical_device *pdevice)
{
return VK_SUCCESS;
}
-static uint64_t pvr_compute_heap_size(void)
+struct pvr_descriptor_limits {
+ uint32_t max_per_stage_resources;
+ uint32_t max_per_stage_samplers;
+ uint32_t max_per_stage_uniform_buffers;
+ uint32_t max_per_stage_storage_buffers;
+ uint32_t max_per_stage_sampled_images;
+ uint32_t max_per_stage_storage_images;
+ uint32_t max_per_stage_input_attachments;
+};
+
+static const struct pvr_descriptor_limits *
+pvr_get_physical_device_descriptor_limits(
+ const struct pvr_device_info *dev_info,
+ const struct pvr_device_runtime_info *dev_runtime_info)
{
- /* Query the total ram from the system */
- uint64_t total_ram;
- if (!os_get_total_physical_memory(&total_ram))
- return 0;
+ enum pvr_descriptor_cs_level {
+ /* clang-format off */
+ CS4096, /* 6XT and some XE cores with large CS. */
+ CS2560, /* Mid range Rogue XE cores. */
+ CS2048, /* Low end Rogue XE cores. */
+ CS1536, /* Ultra-low-end 9XEP. */
+ CS680, /* lower limits for older devices. */
+ CS408, /* 7XE. */
+ /* clang-format on */
+ };
- /* 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 * 1024ULL * 1024ULL * 1024ULL)
- available_ram = total_ram / 2U;
- else
- available_ram = total_ram * 3U / 4U;
+ static const struct pvr_descriptor_limits descriptor_limits[] = {
+ [CS4096] = { 1160U, 256U, 192U, 144U, 256U, 256U, 8U, },
+ [CS2560] = { 648U, 128U, 128U, 128U, 128U, 128U, 8U, },
+ [CS2048] = { 584U, 128U, 96U, 64U, 128U, 128U, 8U, },
+ [CS1536] = { 456U, 64U, 96U, 64U, 128U, 64U, 8U, },
+ [CS680] = { 224U, 32U, 64U, 36U, 48U, 8U, 8U, },
+ [CS408] = { 128U, 16U, 40U, 28U, 16U, 8U, 8U, },
+ };
- return available_ram;
+ const uint32_t common_size =
+ pvr_calc_fscommon_size_and_tiles_in_flight(dev_info,
+ dev_runtime_info,
+ UINT32_MAX,
+ 1);
+ enum pvr_descriptor_cs_level cs_level;
+
+ if (common_size >= 2048) {
+ cs_level = CS2048;
+ } else if (common_size >= 1526) {
+ cs_level = CS1536;
+ } else if (common_size >= 680) {
+ cs_level = CS680;
+ } else if (common_size >= 408) {
+ cs_level = CS408;
+ } else {
+ mesa_loge("This core appears to have a very limited amount of shared "
+ "register space and may not meet the Vulkan spec limits.");
+ abort();
+ }
+
+ return &descriptor_limits[cs_level];
}
-static VkResult pvr_physical_device_init(struct pvr_physical_device *pdevice,
- struct pvr_instance *instance,
- drmDevicePtr drm_render_device,
- drmDevicePtr drm_display_device)
+static void
+pvr_get_physical_device_properties_1_1(struct pvr_physical_device *pdevice,
+ VkPhysicalDeviceVulkan11Properties *p)
{
- struct vk_physical_device_dispatch_table dispatch_table;
- struct vk_device_extension_table supported_extensions;
- struct vk_features supported_features;
- struct pvr_winsys *ws;
- char *display_path;
- char *render_path;
- VkResult result;
+ assert(p->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES);
+}
- if (!getenv("PVR_I_WANT_A_BROKEN_VULKAN_DRIVER")) {
- return vk_errorf(instance,
- VK_ERROR_INCOMPATIBLE_DRIVER,
- "WARNING: powervr is not a conformant Vulkan "
- "implementation. Pass "
- "PVR_I_WANT_A_BROKEN_VULKAN_DRIVER=1 if you know "
- "what you're doing.");
- }
+static void
+pvr_get_physical_device_properties_1_2(struct pvr_physical_device *pdevice,
+ VkPhysicalDeviceVulkan12Properties *p)
+{
+ assert(p->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES);
- render_path = vk_strdup(&instance->vk.alloc,
- drm_render_device->nodes[DRM_NODE_RENDER],
- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
- if (!render_path) {
- result = VK_ERROR_OUT_OF_HOST_MEMORY;
- goto err_out;
- }
+ /* VK_KHR_driver_properties */
+ p->driverID = VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA;
+ memset(p->driverName, 0, sizeof(p->driverName));
+ snprintf(p->driverName,
+ VK_MAX_DRIVER_NAME_SIZE,
+ "Imagination open-source Mesa driver");
+ memset(p->driverInfo, 0, sizeof(p->driverInfo));
+ snprintf(p->driverInfo,
+ VK_MAX_DRIVER_INFO_SIZE,
+ ("Mesa " PACKAGE_VERSION MESA_GIT_SHA1));
+ p->conformanceVersion = (VkConformanceVersion){
+ .major = 1,
+ .minor = 3,
+ .subminor = 4,
+ .patch = 1,
+ };
- if (instance->vk.enabled_extensions.KHR_display) {
- display_path = vk_strdup(&instance->vk.alloc,
- drm_display_device->nodes[DRM_NODE_PRIMARY],
- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
- if (!display_path) {
- result = VK_ERROR_OUT_OF_HOST_MEMORY;
- goto err_vk_free_render_path;
- }
- } else {
- display_path = NULL;
- }
+ /* VK_KHR_timeline_semaphore */
+ p->maxTimelineSemaphoreValueDifference = UINT64_MAX;
+}
- result =
- pvr_winsys_create(render_path, display_path, &instance->vk.alloc, &ws);
- if (result != VK_SUCCESS)
- goto err_vk_free_display_path;
+static void
+pvr_get_physical_device_properties_1_3(struct pvr_physical_device *pdevice,
+ VkPhysicalDeviceVulkan13Properties *p)
+{
+ assert(p->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES);
+}
- pdevice->instance = instance;
- pdevice->render_path = render_path;
- pdevice->display_path = display_path;
- pdevice->ws = ws;
+void pvr_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties *pProperties)
+{
+ PVR_FROM_HANDLE(pvr_physical_device, pdevice, physicalDevice);
+ const struct pvr_device_info *const dev_info = &pdevice->dev_info;
- result = ws->ops->device_info_init(ws,
- &pdevice->dev_info,
- &pdevice->dev_runtime_info);
- if (result != VK_SUCCESS)
- goto err_pvr_winsys_destroy;
+ const struct pvr_descriptor_limits *descriptor_limits =
+ pvr_get_physical_device_descriptor_limits(dev_info,
+ &pdevice->dev_runtime_info);
- pvr_physical_device_get_supported_extensions(&supported_extensions);
- pvr_physical_device_get_supported_features(&pdevice->dev_info,
- &supported_features);
+ /* Default value based on the minimum value found in all existing cores. */
+ const uint32_t max_multisample =
+ PVR_GET_FEATURE_VALUE(dev_info, max_multisample, 4);
- vk_physical_device_dispatch_table_from_entrypoints(
- &dispatch_table,
- &pvr_physical_device_entrypoints,
- true);
+ /* Default value based on the minimum value found in all existing cores. */
+ const uint32_t uvs_banks = PVR_GET_FEATURE_VALUE(dev_info, uvs_banks, 2);
- vk_physical_device_dispatch_table_from_entrypoints(
- &dispatch_table,
- &wsi_physical_device_entrypoints,
- false);
+ /* Default value based on the minimum value found in all existing cores. */
+ const uint32_t uvs_pba_entries =
+ PVR_GET_FEATURE_VALUE(dev_info, uvs_pba_entries, 160);
- result = vk_physical_device_init(&pdevice->vk,
- &instance->vk,
- &supported_extensions,
- &supported_features,
- NULL,
- &dispatch_table);
- if (result != VK_SUCCESS)
- goto err_pvr_winsys_destroy;
+ /* Default value based on the minimum value found in all existing cores. */
+ const uint32_t num_user_clip_planes =
+ PVR_GET_FEATURE_VALUE(dev_info, num_user_clip_planes, 8);
- pdevice->vk.supported_sync_types = ws->sync_types;
+ const uint32_t sub_pixel_precision =
+ PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format) ? 4U : 8U;
- result = pvr_physical_device_init_uuids(pdevice);
- if (result != VK_SUCCESS)
- goto err_vk_physical_device_finish;
-
- if (asprintf(&pdevice->name,
- "Imagination PowerVR %s %s",
- pdevice->dev_info.ident.series_name,
- pdevice->dev_info.ident.public_name) < 0) {
- result = vk_errorf(instance,
- VK_ERROR_OUT_OF_HOST_MEMORY,
- "Unable to allocate memory to store device name");
- goto err_vk_physical_device_finish;
- }
-
- /* Setup available memory heaps and types */
- pdevice->memory.memoryHeapCount = 1;
- pdevice->memory.memoryHeaps[0].size = pvr_compute_heap_size();
- pdevice->memory.memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
+ const uint32_t max_render_size = rogue_get_render_size_max(dev_info);
- pdevice->memory.memoryTypeCount = 1;
- pdevice->memory.memoryTypes[0].propertyFlags =
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
- pdevice->memory.memoryTypes[0].heapIndex = 0;
+ const uint32_t max_sample_bits = ((max_multisample << 1) - 1);
- result = pvr_wsi_init(pdevice);
- if (result != VK_SUCCESS) {
- vk_error(instance, result);
- goto err_free_name;
- }
+ const uint32_t max_user_vertex_components =
+ ((uvs_banks <= 8U) && (uvs_pba_entries == 160U)) ? 64U : 128U;
- pdevice->compiler = rogue_compiler_create(&pdevice->dev_info);
- if (!pdevice->compiler) {
- result = vk_errorf(instance,
- VK_ERROR_INITIALIZATION_FAILED,
- "Failed to initialize Rogue compiler");
- goto err_wsi_finish;
- }
+ /* The workgroup invocations are limited by the case where we have a compute
+ * barrier - each slot has a fixed number of invocations, the whole workgroup
+ * may need to span multiple slots. As each slot will WAIT at the barrier
+ * until the last invocation completes, all have to be schedulable at the
+ * same time.
+ *
+ * Typically all Rogue cores have 16 slots. Some of the smallest cores are
+ * reduced to 14.
+ *
+ * The compute barrier slot exhaustion scenario can be tested with:
+ * dEQP-VK.memory_model.message_passing*u32.coherent.fence_fence
+ * .atomicwrite*guard*comp
+ */
- return VK_SUCCESS;
+ /* Default value based on the minimum value found in all existing cores. */
+ const uint32_t usc_slots = PVR_GET_FEATURE_VALUE(dev_info, usc_slots, 14);
-err_wsi_finish:
- pvr_wsi_finish(pdevice);
+ /* Default value based on the minimum value found in all existing cores. */
+ const uint32_t max_instances_per_pds_task =
+ PVR_GET_FEATURE_VALUE(dev_info, max_instances_per_pds_task, 32U);
-err_free_name:
- free(pdevice->name);
+ const uint32_t max_compute_work_group_invocations =
+ (usc_slots * max_instances_per_pds_task >= 512U) ? 512U : 384U;
-err_vk_physical_device_finish:
- vk_physical_device_finish(&pdevice->vk);
+ VkPhysicalDeviceLimits limits = {
+ .maxImageDimension1D = max_render_size,
+ .maxImageDimension2D = max_render_size,
+ .maxImageDimension3D = PVR_MAX_TEXTURE_EXTENT_Z,
+ .maxImageDimensionCube = max_render_size,
+ .maxImageArrayLayers = PVR_MAX_ARRAY_LAYERS,
+ .maxTexelBufferElements = 64U * 1024U,
+ .maxUniformBufferRange = 128U * 1024U * 1024U,
+ .maxStorageBufferRange = 128U * 1024U * 1024U,
+ .maxPushConstantsSize = PVR_MAX_PUSH_CONSTANTS_SIZE,
+ .maxMemoryAllocationCount = UINT32_MAX,
+ .maxSamplerAllocationCount = UINT32_MAX,
+ .bufferImageGranularity = 1U,
+ .sparseAddressSpaceSize = 256ULL * 1024ULL * 1024ULL * 1024ULL,
-err_pvr_winsys_destroy:
- pvr_winsys_destroy(ws);
+ /* Maximum number of descriptor sets that can be bound at the same time.
+ */
+ .maxBoundDescriptorSets = PVR_MAX_DESCRIPTOR_SETS,
-err_vk_free_display_path:
- vk_free(&instance->vk.alloc, display_path);
+ .maxPerStageResources = descriptor_limits->max_per_stage_resources,
+ .maxPerStageDescriptorSamplers =
+ descriptor_limits->max_per_stage_samplers,
+ .maxPerStageDescriptorUniformBuffers =
+ descriptor_limits->max_per_stage_uniform_buffers,
+ .maxPerStageDescriptorStorageBuffers =
+ descriptor_limits->max_per_stage_storage_buffers,
+ .maxPerStageDescriptorSampledImages =
+ descriptor_limits->max_per_stage_sampled_images,
+ .maxPerStageDescriptorStorageImages =
+ descriptor_limits->max_per_stage_storage_images,
+ .maxPerStageDescriptorInputAttachments =
+ descriptor_limits->max_per_stage_input_attachments,
-err_vk_free_render_path:
- vk_free(&instance->vk.alloc, render_path);
+ .maxDescriptorSetSamplers = 256U,
+ .maxDescriptorSetUniformBuffers = 256U,
+ .maxDescriptorSetUniformBuffersDynamic =
+ PVR_MAX_DESCRIPTOR_SET_UNIFORM_DYNAMIC_BUFFERS,
+ .maxDescriptorSetStorageBuffers = 256U,
+ .maxDescriptorSetStorageBuffersDynamic =
+ PVR_MAX_DESCRIPTOR_SET_STORAGE_DYNAMIC_BUFFERS,
+ .maxDescriptorSetSampledImages = 256U,
+ .maxDescriptorSetStorageImages = 256U,
+ .maxDescriptorSetInputAttachments = 256U,
-err_out:
- return result;
-}
+ /* Vertex Shader Limits */
+ .maxVertexInputAttributes = PVR_MAX_VERTEX_INPUT_BINDINGS,
+ .maxVertexInputBindings = PVR_MAX_VERTEX_INPUT_BINDINGS,
+ .maxVertexInputAttributeOffset = 0xFFFF,
+ .maxVertexInputBindingStride = 1024U * 1024U * 1024U * 2U,
+ .maxVertexOutputComponents = max_user_vertex_components,
-static VkResult pvr_get_drm_devices(void *const obj,
- drmDevicePtr *const devices,
- const int max_devices,
- int *const num_devices_out)
-{
- int ret = drmGetDevices2(0, devices, max_devices);
- if (ret < 0) {
- return vk_errorf(obj,
- VK_ERROR_INITIALIZATION_FAILED,
- "Failed to enumerate drm devices (errno %d: %s)",
- -ret,
- strerror(-ret));
- }
+ /* Tessellation Limits */
+ .maxTessellationGenerationLevel = 0,
+ .maxTessellationPatchSize = 0,
+ .maxTessellationControlPerVertexInputComponents = 0,
+ .maxTessellationControlPerVertexOutputComponents = 0,
+ .maxTessellationControlPerPatchOutputComponents = 0,
+ .maxTessellationControlTotalOutputComponents = 0,
+ .maxTessellationEvaluationInputComponents = 0,
+ .maxTessellationEvaluationOutputComponents = 0,
- if (num_devices_out)
- *num_devices_out = ret;
+ /* Geometry Shader Limits */
+ .maxGeometryShaderInvocations = 0,
+ .maxGeometryInputComponents = 0,
+ .maxGeometryOutputComponents = 0,
+ .maxGeometryOutputVertices = 0,
+ .maxGeometryTotalOutputComponents = 0,
- return VK_SUCCESS;
-}
+ /* Fragment Shader Limits */
+ .maxFragmentInputComponents = max_user_vertex_components,
+ .maxFragmentOutputAttachments = PVR_MAX_COLOR_ATTACHMENTS,
+ .maxFragmentDualSrcAttachments = 0,
+ .maxFragmentCombinedOutputResources =
+ descriptor_limits->max_per_stage_storage_buffers +
+ descriptor_limits->max_per_stage_storage_images +
+ PVR_MAX_COLOR_ATTACHMENTS,
-static bool
-pvr_drm_device_compatible(const struct pvr_drm_device_info *const info,
- drmDevice *const drm_dev)
-{
- char **const compatible = drm_dev->deviceinfo.platform->compatible;
+ /* Compute Shader Limits */
+ .maxComputeSharedMemorySize = 16U * 1024U,
+ .maxComputeWorkGroupCount = { 64U * 1024U, 64U * 1024U, 64U * 1024U },
+ .maxComputeWorkGroupInvocations = max_compute_work_group_invocations,
+ .maxComputeWorkGroupSize = { max_compute_work_group_invocations,
+ max_compute_work_group_invocations,
+ 64U },
- for (char **compat = compatible; *compat; compat++) {
- if (strncmp(*compat, info->name, info->len) == 0)
- return true;
- }
+ /* Rasterization Limits */
+ .subPixelPrecisionBits = sub_pixel_precision,
+ .subTexelPrecisionBits = 8U,
+ .mipmapPrecisionBits = 8U,
- return false;
-}
+ .maxDrawIndexedIndexValue = UINT32_MAX,
+ .maxDrawIndirectCount = 2U * 1024U * 1024U * 1024U,
+ .maxSamplerLodBias = 16.0f,
+ .maxSamplerAnisotropy = 1.0f,
+ .maxViewports = PVR_MAX_VIEWPORTS,
-static const struct pvr_drm_device_config *
-pvr_drm_device_get_config(drmDevice *const drm_dev)
-{
- for (size_t i = 0U; i < ARRAY_SIZE(pvr_drm_configs); i++) {
- if (pvr_drm_device_compatible(&pvr_drm_configs[i].render, drm_dev))
- return &pvr_drm_configs[i];
- }
+ .maxViewportDimensions[0] = max_render_size,
+ .maxViewportDimensions[1] = max_render_size,
+ .viewportBoundsRange[0] = -(int32_t)(2U * max_render_size),
+ .viewportBoundsRange[1] = 2U * max_render_size,
- return NULL;
-}
+ .viewportSubPixelBits = 0,
+ .minMemoryMapAlignment = 64U,
+ .minTexelBufferOffsetAlignment = 16U,
+ .minUniformBufferOffsetAlignment = 4U,
+ .minStorageBufferOffsetAlignment = 4U,
-static void
-pvr_physical_device_dump_info(const struct pvr_physical_device *pdevice,
- char *const *comp_display,
- char *const *comp_render)
-{
- drmVersionPtr version_display, version_render;
- struct pvr_device_dump_info info;
+ .minTexelOffset = -8,
+ .maxTexelOffset = 7U,
+ .minTexelGatherOffset = -8,
+ .maxTexelGatherOffset = 7,
+ .minInterpolationOffset = -0.5,
+ .maxInterpolationOffset = 0.5,
+ .subPixelInterpolationOffsetBits = 4U,
- version_display = drmGetVersion(pdevice->ws->display_fd);
- if (!version_display)
- return;
+ .maxFramebufferWidth = max_render_size,
+ .maxFramebufferHeight = max_render_size,
+ .maxFramebufferLayers = PVR_MAX_FRAMEBUFFER_LAYERS,
- version_render = drmGetVersion(pdevice->ws->render_fd);
- if (!version_render) {
- drmFreeVersion(version_display);
- return;
- }
+ .framebufferColorSampleCounts = max_sample_bits,
+ .framebufferDepthSampleCounts = max_sample_bits,
+ .framebufferStencilSampleCounts = max_sample_bits,
+ .framebufferNoAttachmentsSampleCounts = max_sample_bits,
+ .maxColorAttachments = PVR_MAX_COLOR_ATTACHMENTS,
+ .sampledImageColorSampleCounts = max_sample_bits,
+ .sampledImageIntegerSampleCounts = max_sample_bits,
+ .sampledImageDepthSampleCounts = max_sample_bits,
+ .sampledImageStencilSampleCounts = max_sample_bits,
+ .storageImageSampleCounts = max_sample_bits,
+ .maxSampleMaskWords = 1U,
+ .timestampComputeAndGraphics = false,
+ .timestampPeriod = 0.0f,
+ .maxClipDistances = num_user_clip_planes,
+ .maxCullDistances = num_user_clip_planes,
+ .maxCombinedClipAndCullDistances = num_user_clip_planes,
+ .discreteQueuePriorities = 2U,
+ .pointSizeRange[0] = 1.0f,
+ .pointSizeRange[1] = 511.0f,
+ .pointSizeGranularity = 0.0625f,
+ .lineWidthRange[0] = 1.0f / 16.0f,
+ .lineWidthRange[1] = 16.0f,
+ .lineWidthGranularity = 1.0f / 16.0f,
+ .strictLines = false,
+ .standardSampleLocations = true,
+ .optimalBufferCopyOffsetAlignment = 4U,
+ .optimalBufferCopyRowPitchAlignment = 4U,
+ .nonCoherentAtomSize = 1U,
+ };
- info.device_info = &pdevice->dev_info;
- info.device_runtime_info = &pdevice->dev_runtime_info;
- info.drm_display.patchlevel = version_display->version_patchlevel;
- info.drm_display.major = version_display->version_major;
- info.drm_display.minor = version_display->version_minor;
- info.drm_display.name = version_display->name;
- info.drm_display.date = version_display->date;
- info.drm_display.comp = comp_display;
- info.drm_render.patchlevel = version_render->version_patchlevel;
- info.drm_render.major = version_render->version_major;
- info.drm_render.minor = version_render->version_minor;
- info.drm_render.name = version_render->name;
- info.drm_render.date = version_render->date;
- info.drm_render.comp = comp_render;
+ *pProperties = (VkPhysicalDeviceProperties){
+ .apiVersion = PVR_API_VERSION,
+ .driverVersion = vk_get_driver_version(),
+ .vendorID = VK_VENDOR_ID_IMAGINATION,
+ .deviceID = dev_info->ident.device_id,
+ .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
+ .limits = limits,
+ .sparseProperties = { 0 },
+ };
- pvr_dump_physical_device_info(&info);
+ snprintf(pProperties->deviceName,
+ sizeof(pProperties->deviceName),
+ "%s",
+ pdevice->name);
- drmFreeVersion(version_display);
- drmFreeVersion(version_render);
+ memcpy(pProperties->pipelineCacheUUID,
+ pdevice->pipeline_cache_uuid,
+ VK_UUID_SIZE);
}
-static VkResult
-pvr_physical_device_enumerate(struct vk_instance *const vk_instance)
+void pvr_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2 *pProperties)
{
- struct pvr_instance *const instance =
- container_of(vk_instance, struct pvr_instance, vk);
-
- const struct pvr_drm_device_config *config = NULL;
-
- drmDevicePtr drm_display_device = NULL;
- drmDevicePtr drm_render_device = NULL;
- struct pvr_physical_device *pdevice;
- drmDevicePtr *drm_devices;
- int num_drm_devices = 0;
- VkResult result;
+ PVR_FROM_HANDLE(pvr_physical_device, pdevice, physicalDevice);
- result = pvr_get_drm_devices(instance, NULL, 0, &num_drm_devices);
- if (result != VK_SUCCESS)
- goto out;
+ VkPhysicalDeviceVulkan11Properties core_1_1 = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES,
+ };
- if (num_drm_devices == 0) {
- result = VK_SUCCESS;
- goto out;
- }
+ VkPhysicalDeviceVulkan12Properties core_1_2 = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES,
+ };
- drm_devices = vk_alloc(&vk_instance->alloc,
- sizeof(*drm_devices) * num_drm_devices,
- 8,
- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
- if (!drm_devices) {
- result = vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
- goto out;
- }
+ VkPhysicalDeviceVulkan13Properties core_1_3 = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES,
+ };
- result = pvr_get_drm_devices(instance, drm_devices, num_drm_devices, NULL);
- if (result != VK_SUCCESS)
- goto out_free_drm_device_ptrs;
+ pvr_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
+ pvr_get_physical_device_properties_1_1(pdevice, &core_1_1);
+ pvr_get_physical_device_properties_1_2(pdevice, &core_1_2);
+ pvr_get_physical_device_properties_1_3(pdevice, &core_1_3);
- /* First search for our render node... */
- for (int i = 0; i < num_drm_devices; i++) {
- drmDevice *const drm_dev = drm_devices[i];
+ vk_foreach_struct (ext, pProperties->pNext) {
+ if (vk_get_physical_device_core_1_1_property_ext(ext, &core_1_1))
+ continue;
- if (drm_dev->bustype != DRM_BUS_PLATFORM)
+ if (vk_get_physical_device_core_1_2_property_ext(ext, &core_1_2))
continue;
- if (!(drm_dev->available_nodes & BITFIELD_BIT(DRM_NODE_RENDER)))
+ if (vk_get_physical_device_core_1_3_property_ext(ext, &core_1_3))
continue;
- config = pvr_drm_device_get_config(drm_dev);
- if (config) {
- drm_render_device = drm_dev;
+ switch (ext->sType) {
+ default: {
+ pvr_debug_ignored_stype(ext->sType);
break;
}
+ }
}
+}
- if (!config) {
- result = VK_SUCCESS;
- goto out_free_drm_devices;
- }
-
- mesa_logd("Found compatible render device '%s'.",
- drm_render_device->nodes[DRM_NODE_RENDER]);
+VkResult pvr_EnumerateInstanceVersion(uint32_t *pApiVersion)
+{
+ *pApiVersion = PVR_API_VERSION;
+ return VK_SUCCESS;
+}
- /* ...then find the compatible display node. */
- for (int i = 0; i < num_drm_devices; i++) {
- drmDevice *const drm_dev = drm_devices[i];
+VkResult
+pvr_EnumerateInstanceExtensionProperties(const char *pLayerName,
+ uint32_t *pPropertyCount,
+ VkExtensionProperties *pProperties)
+{
+ if (pLayerName)
+ return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
- if (!(drm_dev->available_nodes & BITFIELD_BIT(DRM_NODE_PRIMARY)))
- continue;
+ return vk_enumerate_instance_extension_properties(&pvr_instance_extensions,
+ pPropertyCount,
+ pProperties);
+}
- if (pvr_drm_device_compatible(&config->display, drm_dev)) {
- drm_display_device = drm_dev;
- break;
- }
- }
+static void pvr_physical_device_destroy(struct vk_physical_device *vk_pdevice)
+{
+ struct pvr_physical_device *pdevice =
+ container_of(vk_pdevice, struct pvr_physical_device, vk);
- if (!drm_display_device) {
- mesa_loge("Render device '%s' has no compatible display device.",
- drm_render_device->nodes[DRM_NODE_RENDER]);
- result = VK_SUCCESS;
- goto out_free_drm_devices;
- }
+ /* Be careful here. The device might not have been initialized. This can
+ * happen since initialization is done in vkEnumeratePhysicalDevices() but
+ * finish is done in vkDestroyInstance(). Make sure that you check for NULL
+ * before freeing or that the freeing functions accept NULL pointers.
+ */
- mesa_logd("Found compatible display device '%s'.",
- drm_display_device->nodes[DRM_NODE_PRIMARY]);
+ if (pdevice->compiler)
+ ralloc_free(pdevice->compiler);
- pdevice = vk_alloc(&vk_instance->alloc,
- sizeof(*pdevice),
- 8,
- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
- if (!pdevice) {
- result = vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
- goto out_free_drm_devices;
- }
+ pvr_wsi_finish(pdevice);
- result = pvr_physical_device_init(pdevice,
- instance,
- drm_render_device,
- drm_display_device);
- if (result != VK_SUCCESS) {
- if (result == VK_ERROR_INCOMPATIBLE_DRIVER)
- result = VK_SUCCESS;
+ free(pdevice->name);
- goto err_free_pdevice;
- }
+ if (pdevice->ws)
+ pvr_winsys_destroy(pdevice->ws);
- if (PVR_IS_DEBUG_SET(INFO)) {
- pvr_physical_device_dump_info(
- pdevice,
- drm_display_device->deviceinfo.platform->compatible,
- drm_render_device->deviceinfo.platform->compatible);
- }
+ vk_free(&pdevice->vk.instance->alloc, pdevice->render_path);
+ vk_free(&pdevice->vk.instance->alloc, pdevice->display_path);
- list_add(&pdevice->vk.link, &vk_instance->physical_devices.list);
+ vk_physical_device_finish(&pdevice->vk);
- result = VK_SUCCESS;
- goto out_free_drm_devices;
+ vk_free(&pdevice->vk.instance->alloc, pdevice);
+}
-err_free_pdevice:
- vk_free(&vk_instance->alloc, pdevice);
+void pvr_DestroyInstance(VkInstance _instance,
+ const VkAllocationCallbacks *pAllocator)
+{
+ PVR_FROM_HANDLE(pvr_instance, instance, _instance);
-out_free_drm_devices:
- drmFreeDevices(drm_devices, num_drm_devices);
+ if (!instance)
+ return;
-out_free_drm_device_ptrs:
- vk_free(&vk_instance->alloc, drm_devices);
+ VG(VALGRIND_DESTROY_MEMPOOL(instance));
-out:
- return result;
+ vk_instance_finish(&instance->vk);
+ vk_free(&instance->vk.alloc, instance);
}
-VkResult pvr_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
- const VkAllocationCallbacks *pAllocator,
- VkInstance *pInstance)
+static uint64_t pvr_compute_heap_size(void)
{
- struct vk_instance_dispatch_table dispatch_table;
- struct pvr_instance *instance;
- VkResult result;
-
- assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
+ /* Query the total ram from the system */
+ uint64_t total_ram;
+ if (!os_get_total_physical_memory(&total_ram))
+ return 0;
- if (!pAllocator)
- pAllocator = vk_default_allocator();
+ /* 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 * 1024ULL * 1024ULL * 1024ULL)
+ available_ram = total_ram / 2U;
+ else
+ available_ram = total_ram * 3U / 4U;
- instance = vk_alloc(pAllocator,
- sizeof(*instance),
- 8,
- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
- if (!instance)
- return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
+ return available_ram;
+}
- vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
- &pvr_instance_entrypoints,
- true);
+static VkResult pvr_physical_device_init(struct pvr_physical_device *pdevice,
+ struct pvr_instance *instance,
+ drmDevicePtr drm_render_device,
+ drmDevicePtr drm_display_device)
+{
+ struct vk_physical_device_dispatch_table dispatch_table;
+ struct vk_device_extension_table supported_extensions;
+ struct vk_features supported_features;
+ struct pvr_winsys *ws;
+ char *display_path;
+ char *render_path;
+ VkResult result;
- vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
- &wsi_instance_entrypoints,
- false);
+ if (!getenv("PVR_I_WANT_A_BROKEN_VULKAN_DRIVER")) {
+ return vk_errorf(instance,
+ VK_ERROR_INCOMPATIBLE_DRIVER,
+ "WARNING: powervr is not a conformant Vulkan "
+ "implementation. Pass "
+ "PVR_I_WANT_A_BROKEN_VULKAN_DRIVER=1 if you know "
+ "what you're doing.");
+ }
- result = vk_instance_init(&instance->vk,
- &pvr_instance_extensions,
- &dispatch_table,
- pCreateInfo,
- pAllocator);
- if (result != VK_SUCCESS) {
- vk_free(pAllocator, instance);
- return result;
+ render_path = vk_strdup(&instance->vk.alloc,
+ drm_render_device->nodes[DRM_NODE_RENDER],
+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (!render_path) {
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto err_out;
}
- pvr_process_debug_variable();
+ if (instance->vk.enabled_extensions.KHR_display) {
+ display_path = vk_strdup(&instance->vk.alloc,
+ drm_display_device->nodes[DRM_NODE_PRIMARY],
+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (!display_path) {
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto err_vk_free_render_path;
+ }
+ } else {
+ display_path = NULL;
+ }
- instance->active_device_count = 0;
+ result =
+ pvr_winsys_create(render_path, display_path, &instance->vk.alloc, &ws);
+ if (result != VK_SUCCESS)
+ goto err_vk_free_display_path;
- instance->vk.physical_devices.enumerate = pvr_physical_device_enumerate;
- instance->vk.physical_devices.destroy = pvr_physical_device_destroy;
+ pdevice->instance = instance;
+ pdevice->render_path = render_path;
+ pdevice->display_path = display_path;
+ pdevice->ws = ws;
- VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
+ result = ws->ops->device_info_init(ws,
+ &pdevice->dev_info,
+ &pdevice->dev_runtime_info);
+ if (result != VK_SUCCESS)
+ goto err_pvr_winsys_destroy;
- *pInstance = pvr_instance_to_handle(instance);
+ pvr_physical_device_get_supported_extensions(&supported_extensions);
+ pvr_physical_device_get_supported_features(&pdevice->dev_info,
+ &supported_features);
- return VK_SUCCESS;
-}
+ vk_physical_device_dispatch_table_from_entrypoints(
+ &dispatch_table,
+ &pvr_physical_device_entrypoints,
+ true);
-static uint32_t pvr_get_simultaneous_num_allocs(
- const struct pvr_device_info *dev_info,
- ASSERTED const struct pvr_device_runtime_info *dev_runtime_info)
-{
- uint32_t min_cluster_per_phantom;
+ vk_physical_device_dispatch_table_from_entrypoints(
+ &dispatch_table,
+ &wsi_physical_device_entrypoints,
+ false);
- if (PVR_HAS_FEATURE(dev_info, s8xe))
- return PVR_GET_FEATURE_VALUE(dev_info, num_raster_pipes, 0U);
+ result = vk_physical_device_init(&pdevice->vk,
+ &instance->vk,
+ &supported_extensions,
+ &supported_features,
+ NULL,
+ &dispatch_table);
+ if (result != VK_SUCCESS)
+ goto err_pvr_winsys_destroy;
- assert(dev_runtime_info->num_phantoms == 1);
- min_cluster_per_phantom = PVR_GET_FEATURE_VALUE(dev_info, num_clusters, 1U);
+ pdevice->vk.supported_sync_types = ws->sync_types;
- if (min_cluster_per_phantom >= 4)
- return 1;
- else if (min_cluster_per_phantom == 2)
- return 2;
- else
- return 4;
-}
+ result = pvr_physical_device_init_uuids(pdevice);
+ if (result != VK_SUCCESS)
+ goto err_vk_physical_device_finish;
-uint32_t pvr_calc_fscommon_size_and_tiles_in_flight(
- const struct pvr_device_info *dev_info,
- const struct pvr_device_runtime_info *dev_runtime_info,
- uint32_t fs_common_size,
- uint32_t min_tiles_in_flight)
-{
- const uint32_t available_shareds =
- dev_runtime_info->reserved_shared_size - dev_runtime_info->max_coeffs;
- const uint32_t max_tiles_in_flight =
- PVR_GET_FEATURE_VALUE(dev_info, isp_max_tiles_in_flight, 1U);
- uint32_t num_tile_in_flight;
- uint32_t num_allocs;
+ if (asprintf(&pdevice->name,
+ "Imagination PowerVR %s %s",
+ pdevice->dev_info.ident.series_name,
+ pdevice->dev_info.ident.public_name) < 0) {
+ result = vk_errorf(instance,
+ VK_ERROR_OUT_OF_HOST_MEMORY,
+ "Unable to allocate memory to store device name");
+ goto err_vk_physical_device_finish;
+ }
- if (fs_common_size == 0)
- return max_tiles_in_flight;
+ /* Setup available memory heaps and types */
+ pdevice->memory.memoryHeapCount = 1;
+ pdevice->memory.memoryHeaps[0].size = pvr_compute_heap_size();
+ pdevice->memory.memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
- num_allocs = pvr_get_simultaneous_num_allocs(dev_info, dev_runtime_info);
+ pdevice->memory.memoryTypeCount = 1;
+ pdevice->memory.memoryTypes[0].propertyFlags =
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ pdevice->memory.memoryTypes[0].heapIndex = 0;
- if (fs_common_size == UINT32_MAX) {
- uint32_t max_common_size = available_shareds;
+ result = pvr_wsi_init(pdevice);
+ if (result != VK_SUCCESS) {
+ vk_error(instance, result);
+ goto err_free_name;
+ }
- num_allocs *= MIN2(min_tiles_in_flight, max_tiles_in_flight);
+ pdevice->compiler = rogue_compiler_create(&pdevice->dev_info);
+ if (!pdevice->compiler) {
+ result = vk_errorf(instance,
+ VK_ERROR_INITIALIZATION_FAILED,
+ "Failed to initialize Rogue compiler");
+ goto err_wsi_finish;
+ }
- if (!PVR_HAS_ERN(dev_info, 38748)) {
- /* Hardware needs space for one extra shared allocation. */
- num_allocs += 1;
- }
+ return VK_SUCCESS;
- /* Double resource requirements to deal with fragmentation. */
- max_common_size /= num_allocs * 2;
- max_common_size = MIN2(max_common_size, ROGUE_MAX_PIXEL_SHARED_REGISTERS);
- max_common_size =
- ROUND_DOWN_TO(max_common_size,
- PVRX(TA_STATE_PDS_SIZEINFO2_USC_SHAREDSIZE_UNIT_SIZE));
+err_wsi_finish:
+ pvr_wsi_finish(pdevice);
- return max_common_size;
- }
+err_free_name:
+ free(pdevice->name);
- num_tile_in_flight = available_shareds / (fs_common_size * 2);
+err_vk_physical_device_finish:
+ vk_physical_device_finish(&pdevice->vk);
- if (!PVR_HAS_ERN(dev_info, 38748))
- num_tile_in_flight -= 1;
+err_pvr_winsys_destroy:
+ pvr_winsys_destroy(ws);
- num_tile_in_flight /= num_allocs;
+err_vk_free_display_path:
+ vk_free(&instance->vk.alloc, display_path);
-#if defined(DEBUG)
- /* Validate the above result. */
+err_vk_free_render_path:
+ vk_free(&instance->vk.alloc, render_path);
- assert(num_tile_in_flight >= MIN2(num_tile_in_flight, max_tiles_in_flight));
- num_allocs *= num_tile_in_flight;
+err_out:
+ return result;
+}
- if (!PVR_HAS_ERN(dev_info, 38748)) {
- /* Hardware needs space for one extra shared allocation. */
- num_allocs += 1;
+static VkResult pvr_get_drm_devices(void *const obj,
+ drmDevicePtr *const devices,
+ const int max_devices,
+ int *const num_devices_out)
+{
+ int ret = drmGetDevices2(0, devices, max_devices);
+ if (ret < 0) {
+ return vk_errorf(obj,
+ VK_ERROR_INITIALIZATION_FAILED,
+ "Failed to enumerate drm devices (errno %d: %s)",
+ -ret,
+ strerror(-ret));
}
- assert(fs_common_size <= available_shareds / (num_allocs * 2));
-#endif
+ if (num_devices_out)
+ *num_devices_out = ret;
- return MIN2(num_tile_in_flight, max_tiles_in_flight);
+ return VK_SUCCESS;
}
-struct pvr_descriptor_limits {
- uint32_t max_per_stage_resources;
- uint32_t max_per_stage_samplers;
- uint32_t max_per_stage_uniform_buffers;
- uint32_t max_per_stage_storage_buffers;
- uint32_t max_per_stage_sampled_images;
- uint32_t max_per_stage_storage_images;
- uint32_t max_per_stage_input_attachments;
-};
-
-static const struct pvr_descriptor_limits *
-pvr_get_physical_device_descriptor_limits(
- const struct pvr_device_info *dev_info,
- const struct pvr_device_runtime_info *dev_runtime_info)
+static bool
+pvr_drm_device_compatible(const struct pvr_drm_device_info *const info,
+ drmDevice *const drm_dev)
{
- enum pvr_descriptor_cs_level {
- /* clang-format off */
- CS4096, /* 6XT and some XE cores with large CS. */
- CS2560, /* Mid range Rogue XE cores. */
- CS2048, /* Low end Rogue XE cores. */
- CS1536, /* Ultra-low-end 9XEP. */
- CS680, /* lower limits for older devices. */
- CS408, /* 7XE. */
- /* clang-format on */
- };
-
- static const struct pvr_descriptor_limits descriptor_limits[] = {
- [CS4096] = { 1160U, 256U, 192U, 144U, 256U, 256U, 8U, },
- [CS2560] = { 648U, 128U, 128U, 128U, 128U, 128U, 8U, },
- [CS2048] = { 584U, 128U, 96U, 64U, 128U, 128U, 8U, },
- [CS1536] = { 456U, 64U, 96U, 64U, 128U, 64U, 8U, },
- [CS680] = { 224U, 32U, 64U, 36U, 48U, 8U, 8U, },
- [CS408] = { 128U, 16U, 40U, 28U, 16U, 8U, 8U, },
- };
-
- const uint32_t common_size =
- pvr_calc_fscommon_size_and_tiles_in_flight(dev_info,
- dev_runtime_info,
- UINT32_MAX,
- 1);
- enum pvr_descriptor_cs_level cs_level;
+ char **const compatible = drm_dev->deviceinfo.platform->compatible;
- if (common_size >= 2048) {
- cs_level = CS2048;
- } else if (common_size >= 1526) {
- cs_level = CS1536;
- } else if (common_size >= 680) {
- cs_level = CS680;
- } else if (common_size >= 408) {
- cs_level = CS408;
- } else {
- mesa_loge("This core appears to have a very limited amount of shared "
- "register space and may not meet the Vulkan spec limits.");
- abort();
+ for (char **compat = compatible; *compat; compat++) {
+ if (strncmp(*compat, info->name, info->len) == 0)
+ return true;
}
- return &descriptor_limits[cs_level];
+ return false;
}
-static void
-pvr_get_physical_device_properties_1_1(struct pvr_physical_device *pdevice,
- VkPhysicalDeviceVulkan11Properties *p)
+static const struct pvr_drm_device_config *
+pvr_drm_device_get_config(drmDevice *const drm_dev)
{
- assert(p->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES);
+ for (size_t i = 0U; i < ARRAY_SIZE(pvr_drm_configs); i++) {
+ if (pvr_drm_device_compatible(&pvr_drm_configs[i].render, drm_dev))
+ return &pvr_drm_configs[i];
+ }
+
+ return NULL;
}
static void
-pvr_get_physical_device_properties_1_2(struct pvr_physical_device *pdevice,
- VkPhysicalDeviceVulkan12Properties *p)
+pvr_physical_device_dump_info(const struct pvr_physical_device *pdevice,
+ char *const *comp_display,
+ char *const *comp_render)
{
- assert(p->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES);
+ drmVersionPtr version_display, version_render;
+ struct pvr_device_dump_info info;
- /* VK_KHR_driver_properties */
- p->driverID = VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA;
- memset(p->driverName, 0, sizeof(p->driverName));
- snprintf(p->driverName,
- VK_MAX_DRIVER_NAME_SIZE,
- "Imagination open-source Mesa driver");
- memset(p->driverInfo, 0, sizeof(p->driverInfo));
- snprintf(p->driverInfo,
- VK_MAX_DRIVER_INFO_SIZE,
- ("Mesa " PACKAGE_VERSION MESA_GIT_SHA1));
- p->conformanceVersion = (VkConformanceVersion){
- .major = 1,
- .minor = 3,
- .subminor = 4,
- .patch = 1,
- };
+ version_display = drmGetVersion(pdevice->ws->display_fd);
+ if (!version_display)
+ return;
- /* VK_KHR_timeline_semaphore */
- p->maxTimelineSemaphoreValueDifference = UINT64_MAX;
-}
+ version_render = drmGetVersion(pdevice->ws->render_fd);
+ if (!version_render) {
+ drmFreeVersion(version_display);
+ return;
+ }
-static void
-pvr_get_physical_device_properties_1_3(struct pvr_physical_device *pdevice,
- VkPhysicalDeviceVulkan13Properties *p)
-{
- assert(p->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES);
+ info.device_info = &pdevice->dev_info;
+ info.device_runtime_info = &pdevice->dev_runtime_info;
+ info.drm_display.patchlevel = version_display->version_patchlevel;
+ info.drm_display.major = version_display->version_major;
+ info.drm_display.minor = version_display->version_minor;
+ info.drm_display.name = version_display->name;
+ info.drm_display.date = version_display->date;
+ info.drm_display.comp = comp_display;
+ info.drm_render.patchlevel = version_render->version_patchlevel;
+ info.drm_render.major = version_render->version_major;
+ info.drm_render.minor = version_render->version_minor;
+ info.drm_render.name = version_render->name;
+ info.drm_render.date = version_render->date;
+ info.drm_render.comp = comp_render;
+
+ pvr_dump_physical_device_info(&info);
+
+ drmFreeVersion(version_display);
+ drmFreeVersion(version_render);
}
-void pvr_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceProperties *pProperties)
+static VkResult
+pvr_physical_device_enumerate(struct vk_instance *const vk_instance)
{
- PVR_FROM_HANDLE(pvr_physical_device, pdevice, physicalDevice);
- const struct pvr_device_info *const dev_info = &pdevice->dev_info;
+ struct pvr_instance *const instance =
+ container_of(vk_instance, struct pvr_instance, vk);
- const struct pvr_descriptor_limits *descriptor_limits =
- pvr_get_physical_device_descriptor_limits(dev_info,
- &pdevice->dev_runtime_info);
+ const struct pvr_drm_device_config *config = NULL;
- /* Default value based on the minimum value found in all existing cores. */
- const uint32_t max_multisample =
- PVR_GET_FEATURE_VALUE(dev_info, max_multisample, 4);
+ drmDevicePtr drm_display_device = NULL;
+ drmDevicePtr drm_render_device = NULL;
+ struct pvr_physical_device *pdevice;
+ drmDevicePtr *drm_devices;
+ int num_drm_devices = 0;
+ VkResult result;
- /* Default value based on the minimum value found in all existing cores. */
- const uint32_t uvs_banks = PVR_GET_FEATURE_VALUE(dev_info, uvs_banks, 2);
+ result = pvr_get_drm_devices(instance, NULL, 0, &num_drm_devices);
+ if (result != VK_SUCCESS)
+ goto out;
- /* Default value based on the minimum value found in all existing cores. */
- const uint32_t uvs_pba_entries =
- PVR_GET_FEATURE_VALUE(dev_info, uvs_pba_entries, 160);
+ if (num_drm_devices == 0) {
+ result = VK_SUCCESS;
+ goto out;
+ }
- /* Default value based on the minimum value found in all existing cores. */
- const uint32_t num_user_clip_planes =
- PVR_GET_FEATURE_VALUE(dev_info, num_user_clip_planes, 8);
+ drm_devices = vk_alloc(&vk_instance->alloc,
+ sizeof(*drm_devices) * num_drm_devices,
+ 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (!drm_devices) {
+ result = vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
+ goto out;
+ }
- const uint32_t sub_pixel_precision =
- PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format) ? 4U : 8U;
+ result = pvr_get_drm_devices(instance, drm_devices, num_drm_devices, NULL);
+ if (result != VK_SUCCESS)
+ goto out_free_drm_device_ptrs;
- const uint32_t max_render_size = rogue_get_render_size_max(dev_info);
+ /* First search for our render node... */
+ for (int i = 0; i < num_drm_devices; i++) {
+ drmDevice *const drm_dev = drm_devices[i];
- const uint32_t max_sample_bits = ((max_multisample << 1) - 1);
+ if (drm_dev->bustype != DRM_BUS_PLATFORM)
+ continue;
- const uint32_t max_user_vertex_components =
- ((uvs_banks <= 8U) && (uvs_pba_entries == 160U)) ? 64U : 128U;
+ if (!(drm_dev->available_nodes & BITFIELD_BIT(DRM_NODE_RENDER)))
+ continue;
- /* The workgroup invocations are limited by the case where we have a compute
- * barrier - each slot has a fixed number of invocations, the whole workgroup
- * may need to span multiple slots. As each slot will WAIT at the barrier
- * until the last invocation completes, all have to be schedulable at the
- * same time.
- *
- * Typically all Rogue cores have 16 slots. Some of the smallest cores are
- * reduced to 14.
- *
- * The compute barrier slot exhaustion scenario can be tested with:
- * dEQP-VK.memory_model.message_passing*u32.coherent.fence_fence
- * .atomicwrite*guard*comp
- */
+ config = pvr_drm_device_get_config(drm_dev);
+ if (config) {
+ drm_render_device = drm_dev;
+ break;
+ }
+ }
- /* Default value based on the minimum value found in all existing cores. */
- const uint32_t usc_slots = PVR_GET_FEATURE_VALUE(dev_info, usc_slots, 14);
+ if (!config) {
+ result = VK_SUCCESS;
+ goto out_free_drm_devices;
+ }
- /* Default value based on the minimum value found in all existing cores. */
- const uint32_t max_instances_per_pds_task =
- PVR_GET_FEATURE_VALUE(dev_info, max_instances_per_pds_task, 32U);
+ mesa_logd("Found compatible render device '%s'.",
+ drm_render_device->nodes[DRM_NODE_RENDER]);
- const uint32_t max_compute_work_group_invocations =
- (usc_slots * max_instances_per_pds_task >= 512U) ? 512U : 384U;
+ /* ...then find the compatible display node. */
+ for (int i = 0; i < num_drm_devices; i++) {
+ drmDevice *const drm_dev = drm_devices[i];
- VkPhysicalDeviceLimits limits = {
- .maxImageDimension1D = max_render_size,
- .maxImageDimension2D = max_render_size,
- .maxImageDimension3D = PVR_MAX_TEXTURE_EXTENT_Z,
- .maxImageDimensionCube = max_render_size,
- .maxImageArrayLayers = PVR_MAX_ARRAY_LAYERS,
- .maxTexelBufferElements = 64U * 1024U,
- .maxUniformBufferRange = 128U * 1024U * 1024U,
- .maxStorageBufferRange = 128U * 1024U * 1024U,
- .maxPushConstantsSize = PVR_MAX_PUSH_CONSTANTS_SIZE,
- .maxMemoryAllocationCount = UINT32_MAX,
- .maxSamplerAllocationCount = UINT32_MAX,
- .bufferImageGranularity = 1U,
- .sparseAddressSpaceSize = 256ULL * 1024ULL * 1024ULL * 1024ULL,
+ if (!(drm_dev->available_nodes & BITFIELD_BIT(DRM_NODE_PRIMARY)))
+ continue;
- /* Maximum number of descriptor sets that can be bound at the same time.
- */
- .maxBoundDescriptorSets = PVR_MAX_DESCRIPTOR_SETS,
+ if (pvr_drm_device_compatible(&config->display, drm_dev)) {
+ drm_display_device = drm_dev;
+ break;
+ }
+ }
- .maxPerStageResources = descriptor_limits->max_per_stage_resources,
- .maxPerStageDescriptorSamplers =
- descriptor_limits->max_per_stage_samplers,
- .maxPerStageDescriptorUniformBuffers =
- descriptor_limits->max_per_stage_uniform_buffers,
- .maxPerStageDescriptorStorageBuffers =
- descriptor_limits->max_per_stage_storage_buffers,
- .maxPerStageDescriptorSampledImages =
- descriptor_limits->max_per_stage_sampled_images,
- .maxPerStageDescriptorStorageImages =
- descriptor_limits->max_per_stage_storage_images,
- .maxPerStageDescriptorInputAttachments =
- descriptor_limits->max_per_stage_input_attachments,
+ if (!drm_display_device) {
+ mesa_loge("Render device '%s' has no compatible display device.",
+ drm_render_device->nodes[DRM_NODE_RENDER]);
+ result = VK_SUCCESS;
+ goto out_free_drm_devices;
+ }
- .maxDescriptorSetSamplers = 256U,
- .maxDescriptorSetUniformBuffers = 256U,
- .maxDescriptorSetUniformBuffersDynamic =
- PVR_MAX_DESCRIPTOR_SET_UNIFORM_DYNAMIC_BUFFERS,
- .maxDescriptorSetStorageBuffers = 256U,
- .maxDescriptorSetStorageBuffersDynamic =
- PVR_MAX_DESCRIPTOR_SET_STORAGE_DYNAMIC_BUFFERS,
- .maxDescriptorSetSampledImages = 256U,
- .maxDescriptorSetStorageImages = 256U,
- .maxDescriptorSetInputAttachments = 256U,
+ mesa_logd("Found compatible display device '%s'.",
+ drm_display_device->nodes[DRM_NODE_PRIMARY]);
+
+ pdevice = vk_alloc(&vk_instance->alloc,
+ sizeof(*pdevice),
+ 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (!pdevice) {
+ result = vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
+ goto out_free_drm_devices;
+ }
+
+ result = pvr_physical_device_init(pdevice,
+ instance,
+ drm_render_device,
+ drm_display_device);
+ if (result != VK_SUCCESS) {
+ if (result == VK_ERROR_INCOMPATIBLE_DRIVER)
+ result = VK_SUCCESS;
+
+ goto err_free_pdevice;
+ }
+
+ if (PVR_IS_DEBUG_SET(INFO)) {
+ pvr_physical_device_dump_info(
+ pdevice,
+ drm_display_device->deviceinfo.platform->compatible,
+ drm_render_device->deviceinfo.platform->compatible);
+ }
+
+ list_add(&pdevice->vk.link, &vk_instance->physical_devices.list);
+
+ result = VK_SUCCESS;
+ goto out_free_drm_devices;
- /* Vertex Shader Limits */
- .maxVertexInputAttributes = PVR_MAX_VERTEX_INPUT_BINDINGS,
- .maxVertexInputBindings = PVR_MAX_VERTEX_INPUT_BINDINGS,
- .maxVertexInputAttributeOffset = 0xFFFF,
- .maxVertexInputBindingStride = 1024U * 1024U * 1024U * 2U,
- .maxVertexOutputComponents = max_user_vertex_components,
+err_free_pdevice:
+ vk_free(&vk_instance->alloc, pdevice);
- /* Tessellation Limits */
- .maxTessellationGenerationLevel = 0,
- .maxTessellationPatchSize = 0,
- .maxTessellationControlPerVertexInputComponents = 0,
- .maxTessellationControlPerVertexOutputComponents = 0,
- .maxTessellationControlPerPatchOutputComponents = 0,
- .maxTessellationControlTotalOutputComponents = 0,
- .maxTessellationEvaluationInputComponents = 0,
- .maxTessellationEvaluationOutputComponents = 0,
+out_free_drm_devices:
+ drmFreeDevices(drm_devices, num_drm_devices);
- /* Geometry Shader Limits */
- .maxGeometryShaderInvocations = 0,
- .maxGeometryInputComponents = 0,
- .maxGeometryOutputComponents = 0,
- .maxGeometryOutputVertices = 0,
- .maxGeometryTotalOutputComponents = 0,
+out_free_drm_device_ptrs:
+ vk_free(&vk_instance->alloc, drm_devices);
- /* Fragment Shader Limits */
- .maxFragmentInputComponents = max_user_vertex_components,
- .maxFragmentOutputAttachments = PVR_MAX_COLOR_ATTACHMENTS,
- .maxFragmentDualSrcAttachments = 0,
- .maxFragmentCombinedOutputResources =
- descriptor_limits->max_per_stage_storage_buffers +
- descriptor_limits->max_per_stage_storage_images +
- PVR_MAX_COLOR_ATTACHMENTS,
+out:
+ return result;
+}
- /* Compute Shader Limits */
- .maxComputeSharedMemorySize = 16U * 1024U,
- .maxComputeWorkGroupCount = { 64U * 1024U, 64U * 1024U, 64U * 1024U },
- .maxComputeWorkGroupInvocations = max_compute_work_group_invocations,
- .maxComputeWorkGroupSize = { max_compute_work_group_invocations,
- max_compute_work_group_invocations,
- 64U },
+VkResult pvr_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkInstance *pInstance)
+{
+ struct vk_instance_dispatch_table dispatch_table;
+ struct pvr_instance *instance;
+ VkResult result;
- /* Rasterization Limits */
- .subPixelPrecisionBits = sub_pixel_precision,
- .subTexelPrecisionBits = 8U,
- .mipmapPrecisionBits = 8U,
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
- .maxDrawIndexedIndexValue = UINT32_MAX,
- .maxDrawIndirectCount = 2U * 1024U * 1024U * 1024U,
- .maxSamplerLodBias = 16.0f,
- .maxSamplerAnisotropy = 1.0f,
- .maxViewports = PVR_MAX_VIEWPORTS,
+ if (!pAllocator)
+ pAllocator = vk_default_allocator();
- .maxViewportDimensions[0] = max_render_size,
- .maxViewportDimensions[1] = max_render_size,
- .viewportBoundsRange[0] = -(int32_t)(2U * max_render_size),
- .viewportBoundsRange[1] = 2U * max_render_size,
+ instance = vk_alloc(pAllocator,
+ sizeof(*instance),
+ 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (!instance)
+ return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
- .viewportSubPixelBits = 0,
- .minMemoryMapAlignment = 64U,
- .minTexelBufferOffsetAlignment = 16U,
- .minUniformBufferOffsetAlignment = 4U,
- .minStorageBufferOffsetAlignment = 4U,
+ vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
+ &pvr_instance_entrypoints,
+ true);
- .minTexelOffset = -8,
- .maxTexelOffset = 7U,
- .minTexelGatherOffset = -8,
- .maxTexelGatherOffset = 7,
- .minInterpolationOffset = -0.5,
- .maxInterpolationOffset = 0.5,
- .subPixelInterpolationOffsetBits = 4U,
+ vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
+ &wsi_instance_entrypoints,
+ false);
- .maxFramebufferWidth = max_render_size,
- .maxFramebufferHeight = max_render_size,
- .maxFramebufferLayers = PVR_MAX_FRAMEBUFFER_LAYERS,
+ result = vk_instance_init(&instance->vk,
+ &pvr_instance_extensions,
+ &dispatch_table,
+ pCreateInfo,
+ pAllocator);
+ if (result != VK_SUCCESS) {
+ vk_free(pAllocator, instance);
+ return result;
+ }
- .framebufferColorSampleCounts = max_sample_bits,
- .framebufferDepthSampleCounts = max_sample_bits,
- .framebufferStencilSampleCounts = max_sample_bits,
- .framebufferNoAttachmentsSampleCounts = max_sample_bits,
- .maxColorAttachments = PVR_MAX_COLOR_ATTACHMENTS,
- .sampledImageColorSampleCounts = max_sample_bits,
- .sampledImageIntegerSampleCounts = max_sample_bits,
- .sampledImageDepthSampleCounts = max_sample_bits,
- .sampledImageStencilSampleCounts = max_sample_bits,
- .storageImageSampleCounts = max_sample_bits,
- .maxSampleMaskWords = 1U,
- .timestampComputeAndGraphics = false,
- .timestampPeriod = 0.0f,
- .maxClipDistances = num_user_clip_planes,
- .maxCullDistances = num_user_clip_planes,
- .maxCombinedClipAndCullDistances = num_user_clip_planes,
- .discreteQueuePriorities = 2U,
- .pointSizeRange[0] = 1.0f,
- .pointSizeRange[1] = 511.0f,
- .pointSizeGranularity = 0.0625f,
- .lineWidthRange[0] = 1.0f / 16.0f,
- .lineWidthRange[1] = 16.0f,
- .lineWidthGranularity = 1.0f / 16.0f,
- .strictLines = false,
- .standardSampleLocations = true,
- .optimalBufferCopyOffsetAlignment = 4U,
- .optimalBufferCopyRowPitchAlignment = 4U,
- .nonCoherentAtomSize = 1U,
- };
+ pvr_process_debug_variable();
- *pProperties = (VkPhysicalDeviceProperties){
- .apiVersion = PVR_API_VERSION,
- .driverVersion = vk_get_driver_version(),
- .vendorID = VK_VENDOR_ID_IMAGINATION,
- .deviceID = dev_info->ident.device_id,
- .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
- .limits = limits,
- .sparseProperties = { 0 },
- };
+ instance->active_device_count = 0;
- snprintf(pProperties->deviceName,
- sizeof(pProperties->deviceName),
- "%s",
- pdevice->name);
+ instance->vk.physical_devices.enumerate = pvr_physical_device_enumerate;
+ instance->vk.physical_devices.destroy = pvr_physical_device_destroy;
- memcpy(pProperties->pipelineCacheUUID,
- pdevice->pipeline_cache_uuid,
- VK_UUID_SIZE);
+ VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
+
+ *pInstance = pvr_instance_to_handle(instance);
+
+ return VK_SUCCESS;
}
-void pvr_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceProperties2 *pProperties)
+static uint32_t pvr_get_simultaneous_num_allocs(
+ const struct pvr_device_info *dev_info,
+ ASSERTED const struct pvr_device_runtime_info *dev_runtime_info)
{
- PVR_FROM_HANDLE(pvr_physical_device, pdevice, physicalDevice);
+ uint32_t min_cluster_per_phantom;
- VkPhysicalDeviceVulkan11Properties core_1_1 = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES,
- };
+ if (PVR_HAS_FEATURE(dev_info, s8xe))
+ return PVR_GET_FEATURE_VALUE(dev_info, num_raster_pipes, 0U);
- VkPhysicalDeviceVulkan12Properties core_1_2 = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES,
- };
+ assert(dev_runtime_info->num_phantoms == 1);
+ min_cluster_per_phantom = PVR_GET_FEATURE_VALUE(dev_info, num_clusters, 1U);
- VkPhysicalDeviceVulkan13Properties core_1_3 = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES,
- };
+ if (min_cluster_per_phantom >= 4)
+ return 1;
+ else if (min_cluster_per_phantom == 2)
+ return 2;
+ else
+ return 4;
+}
- pvr_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
- pvr_get_physical_device_properties_1_1(pdevice, &core_1_1);
- pvr_get_physical_device_properties_1_2(pdevice, &core_1_2);
- pvr_get_physical_device_properties_1_3(pdevice, &core_1_3);
+uint32_t pvr_calc_fscommon_size_and_tiles_in_flight(
+ const struct pvr_device_info *dev_info,
+ const struct pvr_device_runtime_info *dev_runtime_info,
+ uint32_t fs_common_size,
+ uint32_t min_tiles_in_flight)
+{
+ const uint32_t available_shareds =
+ dev_runtime_info->reserved_shared_size - dev_runtime_info->max_coeffs;
+ const uint32_t max_tiles_in_flight =
+ PVR_GET_FEATURE_VALUE(dev_info, isp_max_tiles_in_flight, 1U);
+ uint32_t num_tile_in_flight;
+ uint32_t num_allocs;
- vk_foreach_struct (ext, pProperties->pNext) {
- if (vk_get_physical_device_core_1_1_property_ext(ext, &core_1_1))
- continue;
+ if (fs_common_size == 0)
+ return max_tiles_in_flight;
- if (vk_get_physical_device_core_1_2_property_ext(ext, &core_1_2))
- continue;
+ num_allocs = pvr_get_simultaneous_num_allocs(dev_info, dev_runtime_info);
- if (vk_get_physical_device_core_1_3_property_ext(ext, &core_1_3))
- continue;
+ if (fs_common_size == UINT32_MAX) {
+ uint32_t max_common_size = available_shareds;
- switch (ext->sType) {
- default: {
- pvr_debug_ignored_stype(ext->sType);
- break;
- }
+ num_allocs *= MIN2(min_tiles_in_flight, max_tiles_in_flight);
+
+ if (!PVR_HAS_ERN(dev_info, 38748)) {
+ /* Hardware needs space for one extra shared allocation. */
+ num_allocs += 1;
}
+
+ /* Double resource requirements to deal with fragmentation. */
+ max_common_size /= num_allocs * 2;
+ max_common_size = MIN2(max_common_size, ROGUE_MAX_PIXEL_SHARED_REGISTERS);
+ max_common_size =
+ ROUND_DOWN_TO(max_common_size,
+ PVRX(TA_STATE_PDS_SIZEINFO2_USC_SHAREDSIZE_UNIT_SIZE));
+
+ return max_common_size;
+ }
+
+ num_tile_in_flight = available_shareds / (fs_common_size * 2);
+
+ if (!PVR_HAS_ERN(dev_info, 38748))
+ num_tile_in_flight -= 1;
+
+ num_tile_in_flight /= num_allocs;
+
+#if defined(DEBUG)
+ /* Validate the above result. */
+
+ assert(num_tile_in_flight >= MIN2(num_tile_in_flight, max_tiles_in_flight));
+ num_allocs *= num_tile_in_flight;
+
+ if (!PVR_HAS_ERN(dev_info, 38748)) {
+ /* Hardware needs space for one extra shared allocation. */
+ num_allocs += 1;
}
+
+ assert(fs_common_size <= available_shareds / (num_allocs * 2));
+#endif
+
+ return MIN2(num_tile_in_flight, max_tiles_in_flight);
}
const static VkQueueFamilyProperties pvr_queue_family_properties = {