diff --git a/docs/features.txt b/docs/features.txt index d0c0faf5f40..50566e86f24 100644 --- a/docs/features.txt +++ b/docs/features.txt @@ -563,7 +563,7 @@ Khronos extensions that are not part of any Vulkan version: VK_KHR_maintenance10 DONE (anv, nvk, radv) VK_KHR_performance_query DONE (anv, radv/gfx10.3+, tu, v3dv) VK_KHR_pipeline_binary DONE (anv, hk, nvk, panvk, radv) - VK_KHR_pipeline_executable_properties DONE (anv, hk, nvk, panvk, hasvk, radv, tu, v3dv) + VK_KHR_pipeline_executable_properties DONE (anv, hasvk, hk, nvk, panvk, pvr, radv, tu, v3dv) VK_KHR_pipeline_library DONE (anv, hk, lvp, nvk, panvk, radv, tu, vn) VK_KHR_present_id DONE (anv, hk, nvk, panvk, radv, tu, vn) VK_KHR_present_id2 DONE (anv, hk, nvk, panvk, pvr, radv, tu, v3dv, vn) diff --git a/docs/relnotes/new_features.txt b/docs/relnotes/new_features.txt index 47d2e8b2efd..792b60e1d39 100644 --- a/docs/relnotes/new_features.txt +++ b/docs/relnotes/new_features.txt @@ -9,3 +9,4 @@ VK_KHR_get_display_properties2 on panvk VK_EXT_acquire_drm_display on panvk VK_KHR_present_id on panvk VK_KHR_present_wait on panvk +VK_KHR_pipeline_executable_properties on pvr diff --git a/src/imagination/vulkan/pvr_arch_pipeline.c b/src/imagination/vulkan/pvr_arch_pipeline.c index e3969335f80..a32e7257429 100644 --- a/src/imagination/vulkan/pvr_arch_pipeline.c +++ b/src/imagination/vulkan/pvr_arch_pipeline.c @@ -59,6 +59,7 @@ #include "util/log.h" #include "util/macros.h" #include "util/ralloc.h" +#include "util/shader_stats.h" #include "util/u_dynarray.h" #include "util/u_math.h" #include "vk_alloc.h" @@ -1044,6 +1045,21 @@ static VkResult pvr_compute_pipeline_compile( pvr_compute_state_save(compute_pipeline, cs); + if (pCreateInfo->flags & VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR) { + struct pvr_stats stats = pco_get_pvr_stats(cs); + compute_pipeline->cs_stats = + vk_zalloc2(&device->vk.alloc, + allocator, + sizeof(stats), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!compute_pipeline->cs_stats) + return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + memcpy(compute_pipeline->cs_stats, &stats, sizeof(stats)); + } + result = pvr_gpu_upload_usc(device, pco_shader_binary_data(cs), pco_shader_binary_size(cs), @@ -1191,6 +1207,8 @@ static void pvr_compute_pipeline_destroy( pvr_pipeline_finish(device, &compute_pipeline->base); + vk_free2(&device->vk.alloc, allocator, compute_pipeline->cs_stats); + vk_free2(&device->vk.alloc, allocator, compute_pipeline); } @@ -1275,6 +1293,9 @@ pvr_graphics_pipeline_destroy(struct pvr_device *const device, pvr_pipeline_destroy_shader_data(&gfx_pipeline->vs_data); pvr_pipeline_destroy_shader_data(&gfx_pipeline->fs_data); + vk_free2(&device->vk.alloc, allocator, gfx_pipeline->vs_stats); + vk_free2(&device->vk.alloc, allocator, gfx_pipeline->fs_stats); + vk_free2(&device->vk.alloc, allocator, gfx_pipeline); } @@ -2913,6 +2934,20 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, pvr_vertex_state_save(gfx_pipeline, *vs); + if (pCreateInfo->flags & VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR) { + struct pvr_stats stats = pco_get_pvr_stats(*vs); + gfx_pipeline->vs_stats = vk_zalloc2(&device->vk.alloc, + allocator, + sizeof(stats), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!gfx_pipeline->vs_stats) + return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + memcpy(gfx_pipeline->vs_stats, &stats, sizeof(stats)); + } + pvr_graphics_pipeline_setup_vertex_dma(gfx_pipeline, pCreateInfo->pVertexInputState, state->vi, @@ -2930,6 +2965,20 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, if (*fs) { pvr_fragment_state_save(gfx_pipeline, *fs); + if (pCreateInfo->flags & VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR) { + struct pvr_stats stats = pco_get_pvr_stats(*fs); + gfx_pipeline->fs_stats = vk_zalloc2(&device->vk.alloc, + allocator, + sizeof(stats), + 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (!gfx_pipeline->fs_stats) + return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + memcpy(gfx_pipeline->fs_stats, &stats, sizeof(stats)); + } + pvr_graphics_pipeline_setup_fragment_coeff_program( gfx_pipeline, nir_shaders[MESA_SHADER_FRAGMENT]); @@ -3303,3 +3352,157 @@ void PVR_PER_ARCH(DestroyPipeline)(VkDevice _device, UNREACHABLE("Unknown pipeline type."); } } + +static uint32_t pvr_get_executable_count(struct pvr_pipeline *pipeline) +{ + uint32_t exe_count = 0; + + switch (pipeline->type) { + case PVR_PIPELINE_TYPE_GRAPHICS: { + struct pvr_graphics_pipeline *const gfx_pipeline = + to_pvr_graphics_pipeline(pipeline); + + for (mesa_shader_stage stage = 0; stage < MESA_SHADER_STAGES; ++stage) { + size_t stage_index = gfx_pipeline->stage_indices[stage]; + + if (stage_index != ~0) + exe_count++; + } + break; + } + + case PVR_PIPELINE_TYPE_COMPUTE: { + /* Compute pipelines always only have one executable. */ + exe_count = 1; + break; + } + + default: + UNREACHABLE("Unknown pipeline type."); + } + + return exe_count; +} + +VkResult pvr_GetPipelineExecutableStatisticsKHR( + UNUSED VkDevice _device, + const VkPipelineExecutableInfoKHR *pExecutableInfo, + uint32_t *pStatisticCount, + VkPipelineExecutableStatisticKHR *pStatistics) +{ + VK_FROM_HANDLE(pvr_pipeline, pipeline, pExecutableInfo->pipeline); + VK_OUTARRAY_MAKE_TYPED(VkPipelineExecutableStatisticKHR, + out, + pStatistics, + pStatisticCount); + + switch (pipeline->type) { + case PVR_PIPELINE_TYPE_GRAPHICS: { + struct pvr_graphics_pipeline *const gfx_pipeline = + to_pvr_graphics_pipeline(pipeline); + + if (pExecutableInfo->executableIndex == 0) { + vk_add_pvr_stats(out, gfx_pipeline->vs_stats); + } else { + assert(pExecutableInfo->executableIndex == 1); + vk_add_pvr_stats(out, gfx_pipeline->fs_stats); + } + break; + } + + case PVR_PIPELINE_TYPE_COMPUTE: { + struct pvr_compute_pipeline *const compute_pipeline = + to_pvr_compute_pipeline(pipeline); + + assert(pExecutableInfo->executableIndex == 0); + vk_add_pvr_stats(out, compute_pipeline->cs_stats); + break; + } + + default: + UNREACHABLE("Unknown pipeline type."); + } + + return vk_outarray_status(&out); +} + +VkResult pvr_GetPipelineExecutablePropertiesKHR( + VkDevice _device, + const VkPipelineInfoKHR *pPipelineInfo, + uint32_t *pExecutableCount, + VkPipelineExecutablePropertiesKHR *pProperties) +{ + VK_FROM_HANDLE(pvr_device, device, _device); + VK_FROM_HANDLE(pvr_pipeline, pipeline, pPipelineInfo->pipeline); + ASSERTED uint32_t actualExeCount = pvr_get_executable_count(pipeline); + + /* Due to individual shaders currently being stored as individual members + * of pvr_graphics_pipeline, if support is added for a new shader stage, + * this code will need to be updated. + */ + assert(actualExeCount >= 1 && actualExeCount <= 2); + + VK_OUTARRAY_MAKE_TYPED(VkPipelineExecutablePropertiesKHR, + out, + pProperties, + pExecutableCount); + + switch (pipeline->type) { + case PVR_PIPELINE_TYPE_GRAPHICS: { + struct pvr_graphics_pipeline *const gfx_pipeline = + to_pvr_graphics_pipeline(pipeline); + + vk_outarray_append_typed (VkPipelineExecutablePropertiesKHR, + &out, + vertProps) { + vertProps->stages |= VK_SHADER_STAGE_VERTEX_BIT; + VK_COPY_STR(vertProps->name, "vertex"); + VK_COPY_STR(vertProps->description, "Vulkan Vertex Shader"); + vertProps->subgroupSize = device->pdevice->vk.properties.subgroupSize; + } + + if (gfx_pipeline->stage_indices[MESA_SHADER_FRAGMENT] != ~0) { + vk_outarray_append_typed (VkPipelineExecutablePropertiesKHR, + &out, + fragProps) { + fragProps->stages |= VK_SHADER_STAGE_FRAGMENT_BIT; + VK_COPY_STR(fragProps->name, "fragment"); + VK_COPY_STR(fragProps->description, "Vulkan Fragment Shader"); + fragProps->subgroupSize = + device->pdevice->vk.properties.subgroupSize; + } + } + + break; + } + + case PVR_PIPELINE_TYPE_COMPUTE: { + vk_outarray_append_typed (VkPipelineExecutablePropertiesKHR, + &out, + compProps) { + compProps->stages = VK_SHADER_STAGE_COMPUTE_BIT; + VK_COPY_STR(compProps->name, "compute"); + VK_COPY_STR(compProps->description, "Vulkan Compute Shader"); + compProps->subgroupSize = device->pdevice->vk.properties.subgroupSize; + } + break; + } + default: + UNREACHABLE("Unknown pipeline type."); + } + + return vk_outarray_status(&out); +} + +VkResult pvr_GetPipelineExecutableInternalRepresentationsKHR( + UNUSED VkDevice _device, + UNUSED const VkPipelineExecutableInfoKHR *pExecutableInfo, + uint32_t *pInternalRepresentationCount, + UNUSED VkPipelineExecutableInternalRepresentationKHR + *pInternalRepresentations) +{ + pvr_finishme("Add support for requesting intermediate representations."); + *pInternalRepresentationCount = 0; + + return VK_SUCCESS; +} diff --git a/src/imagination/vulkan/pvr_physical_device.c b/src/imagination/vulkan/pvr_physical_device.c index 04decd75b55..ee60d74cf6e 100644 --- a/src/imagination/vulkan/pvr_physical_device.c +++ b/src/imagination/vulkan/pvr_physical_device.c @@ -150,6 +150,7 @@ static void pvr_physical_device_get_supported_extensions( .KHR_maintenance3 = true, .KHR_map_memory2 = true, .KHR_multiview = true, + .KHR_pipeline_executable_properties = true, .KHR_present_id2 = PVR_USE_WSI_PLATFORM, .KHR_present_wait2 = PVR_USE_WSI_PLATFORM, .KHR_relaxed_block_layout = true, @@ -468,6 +469,9 @@ static void pvr_physical_device_get_supported_features( /* Vulkan 1.2 / VK_KHR_dynamic_rendering */ .dynamicRendering = true, + + /* VK_KHR_pipeline_executable_properties */ + .pipelineExecutableInfo = true, }; } diff --git a/src/imagination/vulkan/pvr_pipeline.h b/src/imagination/vulkan/pvr_pipeline.h index d926ab9c1ed..8e4e2aa28e4 100644 --- a/src/imagination/vulkan/pvr_pipeline.h +++ b/src/imagination/vulkan/pvr_pipeline.h @@ -20,6 +20,7 @@ #include "pvr_common.h" #include "pvr_csb.h" #include "pvr_pds.h" +#include "util/shader_stats.h" struct pvr_suballoc_bo; @@ -109,6 +110,9 @@ struct pvr_compute_pipeline { uint32_t num_workgroups_data_patching_offset; uint32_t num_workgroups_indirect_src_patching_offset; uint32_t num_workgroups_indirect_src_dma_patching_offset; + + /* Debug Info */ + struct pvr_stats *cs_stats; }; struct pvr_graphics_pipeline { @@ -126,6 +130,10 @@ struct pvr_graphics_pipeline { struct pvr_vertex_shader_state vertex; struct pvr_fragment_shader_state fragment; } shader_state; + + /* Debug Info */ + struct pvr_stats *vs_stats; + struct pvr_stats *fs_stats; }; struct pvr_private_compute_pipeline {