2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2025-02-11 03:00:37 +01:00
# include "vkutils/query_pool.hpp"
2024-12-21 22:20:46 +01:00
# include "VKHelpers.h"
2020-10-04 19:50:45 +02:00
# include "VKQueryPool.h"
2021-01-09 19:46:50 +01:00
# include "VKRenderPass.h"
2020-10-04 19:50:45 +02:00
# include "VKResourceManager.h"
2021-12-17 14:40:39 +01:00
# include "util/asm.hpp"
2025-02-11 03:00:37 +01:00
# include "VKGSRender.h"
2020-10-04 19:50:45 +02:00
namespace vk
{
inline bool query_pool_manager : : poke_query ( query_slot_info & query , u32 index , VkQueryResultFlags flags )
{
// Query is ready if:
// 1. Any sample has been determined to have passed the Z test
// 2. The backend has fully processed the query and found no hits
2025-04-05 21:50:45 +02:00
u32 result [ 2 ] = { 0 , 0 } ;
2025-03-18 16:19:05 +01:00
switch ( const auto error = VK_GET_SYMBOL ( vkGetQueryPoolResults ) ( * owner , * query . pool , index , 1 , 8 , result , 8 , flags | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT ) )
2020-10-04 19:50:45 +02:00
{
case VK_SUCCESS :
{
if ( result [ 0 ] )
{
query . any_passed = true ;
query . ready = true ;
2021-09-04 20:50:53 +02:00
query . data = result [ 0 ] ;
2020-10-04 19:50:45 +02:00
return true ;
}
else if ( result [ 1 ] )
{
query . any_passed = false ;
query . ready = true ;
2021-09-04 20:50:53 +02:00
query . data = 0 ;
2020-10-04 19:50:45 +02:00
return true ;
}
return false ;
}
case VK_NOT_READY :
{
2022-05-09 23:09:13 +02:00
query . any_passed = ! ! result [ 0 ] ;
query . ready = query . any_passed & & ! ! ( flags & VK_QUERY_RESULT_PARTIAL_BIT ) ;
query . data = result [ 0 ] ;
return query . ready ;
2020-10-04 19:50:45 +02:00
}
default :
2020-12-09 16:04:52 +01:00
die_with_error ( error ) ;
2020-10-04 19:50:45 +02:00
return false ;
}
}
query_pool_manager : : query_pool_manager ( vk : : render_device & dev , VkQueryType type , u32 num_entries )
{
2020-12-09 08:47:45 +01:00
ensure ( num_entries > 0 ) ;
2020-10-04 19:50:45 +02:00
owner = & dev ;
query_type = type ;
query_slot_status . resize ( num_entries , { } ) ;
for ( unsigned i = 0 ; i < num_entries ; + + i )
{
m_available_slots . push_back ( i ) ;
}
}
query_pool_manager : : ~ query_pool_manager ( )
{
if ( m_current_query_pool )
{
m_current_query_pool . reset ( ) ;
owner = nullptr ;
}
}
void query_pool_manager : : allocate_new_pool ( vk : : command_buffer & cmd )
{
2020-12-09 08:47:45 +01:00
ensure ( ! m_current_query_pool ) ;
2020-10-04 19:50:45 +02:00
2024-12-21 22:20:46 +01:00
if ( m_query_pool_cache . size ( ) > 0 )
{
m_current_query_pool = std : : move ( m_query_pool_cache . front ( ) ) ;
m_query_pool_cache . pop_front ( ) ;
}
else
{
const u32 count = : : size32 ( query_slot_status ) ;
m_current_query_pool = std : : make_unique < query_pool > ( * owner , query_type , count ) ;
}
2020-10-04 19:50:45 +02:00
// From spec: "After query pool creation, each query must be reset before it is used."
2025-03-18 16:19:05 +01:00
VK_GET_SYMBOL ( vkCmdResetQueryPool ) ( cmd , * m_current_query_pool . get ( ) , 0 , m_current_query_pool - > size ( ) ) ;
2024-12-21 22:20:46 +01:00
m_pool_lifetime_counter = m_current_query_pool - > size ( ) ;
2020-10-04 19:50:45 +02:00
}
void query_pool_manager : : reallocate_pool ( vk : : command_buffer & cmd )
{
if ( m_current_query_pool )
{
if ( ! m_current_query_pool - > has_refs ( ) )
{
2024-12-21 22:20:46 +01:00
auto ref = std : : make_unique < query_pool_ref > ( this , m_current_query_pool ) ;
vk : : get_resource_manager ( ) - > dispose ( ref ) ;
2020-10-04 19:50:45 +02:00
}
else
{
m_consumed_pools . emplace_back ( std : : move ( m_current_query_pool ) ) ;
// Sanity check
if ( m_consumed_pools . size ( ) > 3 )
{
rsx_log . error ( " [Robustness warning] Query pool discard pile size is now %llu. Are we leaking?? " , m_consumed_pools . size ( ) ) ;
}
}
}
allocate_new_pool ( cmd ) ;
}
void query_pool_manager : : run_pool_cleanup ( )
{
for ( auto It = m_consumed_pools . begin ( ) ; It ! = m_consumed_pools . end ( ) ; )
{
if ( ! ( * It ) - > has_refs ( ) )
{
2024-12-21 22:20:46 +01:00
auto ref = std : : make_unique < query_pool_ref > ( this , * It ) ;
vk : : get_resource_manager ( ) - > dispose ( ref ) ;
2020-10-04 19:50:45 +02:00
It = m_consumed_pools . erase ( It ) ;
}
else
{
It + + ;
}
}
}
2021-09-04 20:50:53 +02:00
void query_pool_manager : : set_control_flags ( VkQueryControlFlags control_ , VkQueryResultFlags result_ )
{
control_flags = control_ ;
result_flags = result_ ;
}
2020-10-04 19:50:45 +02:00
void query_pool_manager : : begin_query ( vk : : command_buffer & cmd , u32 index )
{
2020-12-09 08:47:45 +01:00
ensure ( query_slot_status [ index ] . active = = false ) ;
2020-10-04 19:50:45 +02:00
auto & query_info = query_slot_status [ index ] ;
query_info . pool = m_current_query_pool . get ( ) ;
query_info . active = true ;
2025-03-18 16:19:05 +01:00
VK_GET_SYMBOL ( vkCmdBeginQuery ) ( cmd , * query_info . pool , index , control_flags ) ;
2020-10-04 19:50:45 +02:00
}
void query_pool_manager : : end_query ( vk : : command_buffer & cmd , u32 index )
{
2025-03-18 16:19:05 +01:00
VK_GET_SYMBOL ( vkCmdEndQuery ) ( cmd , * query_slot_status [ index ] . pool , index ) ;
2020-10-04 19:50:45 +02:00
}
bool query_pool_manager : : check_query_status ( u32 index )
{
2021-09-04 20:50:53 +02:00
return poke_query ( query_slot_status [ index ] , index , result_flags ) ;
2020-10-04 19:50:45 +02:00
}
u32 query_pool_manager : : get_query_result ( u32 index )
{
// Check for cached result
auto & query_info = query_slot_status [ index ] ;
2021-12-17 14:40:39 +01:00
if ( ! query_info . ready )
2020-10-04 19:50:45 +02:00
{
2021-09-04 20:50:53 +02:00
poke_query ( query_info , index , result_flags ) ;
2021-12-17 14:40:39 +01:00
while ( ! query_info . ready )
{
utils : : pause ( ) ;
poke_query ( query_info , index , result_flags ) ;
}
2020-10-04 19:50:45 +02:00
}
2021-09-04 20:50:53 +02:00
return query_info . data ;
2020-10-04 19:50:45 +02:00
}
2023-06-16 03:21:28 +02:00
void query_pool_manager : : get_query_result_indirect ( vk : : command_buffer & cmd , u32 index , u32 count , VkBuffer dst , VkDeviceSize dst_offset )
2020-10-04 19:50:45 +02:00
{
2023-06-06 16:20:53 +02:00
// We're technically supposed to stop any active renderpasses before streaming the results out, but that doesn't matter on IMR hw
// On TBDR setups like the apple M series, the stop is required (results are all 0 if you don't flush the RP), but this introduces a very heavy performance loss.
2025-03-18 16:19:05 +01:00
VK_GET_SYMBOL ( vkCmdCopyQueryPoolResults ) ( cmd , * query_slot_status [ index ] . pool , index , count , dst , dst_offset , 4 , VK_QUERY_RESULT_WAIT_BIT ) ;
2020-10-04 19:50:45 +02:00
}
2025-04-05 21:50:45 +02:00
void query_pool_manager : : free_query ( vk : : command_buffer & /*cmd*/ , u32 index )
2020-10-04 19:50:45 +02:00
{
// Release reference and discard
auto & query = query_slot_status [ index ] ;
2020-12-09 08:47:45 +01:00
ensure ( query . active ) ;
2020-10-04 19:50:45 +02:00
query . pool - > release ( ) ;
if ( ! query . pool - > has_refs ( ) )
{
// No more refs held, remove if in discard pile
run_pool_cleanup ( ) ;
}
query = { } ;
m_available_slots . push_back ( index ) ;
}
u32 query_pool_manager : : allocate_query ( vk : : command_buffer & cmd )
{
if ( ! m_pool_lifetime_counter )
{
// Pool is exhaused, create a new one
// This is basically a driver-level pool reset without synchronization
// TODO: Alternatively, use VK_EXT_host_pool_reset to reset an old pool with no references and swap that in
if ( vk : : is_renderpass_open ( cmd ) )
{
vk : : end_renderpass ( cmd ) ;
}
reallocate_pool ( cmd ) ;
}
if ( ! m_available_slots . empty ( ) )
{
m_pool_lifetime_counter - - ;
const auto result = m_available_slots . front ( ) ;
m_available_slots . pop_front ( ) ;
return result ;
}
return ~ 0u ;
}
2024-12-21 22:20:46 +01:00
void query_pool_manager : : on_query_pool_released ( std : : unique_ptr < vk : : query_pool > & pool )
{
if ( ! vk : : force_reuse_query_pools ( ) )
{
// Delete and let the driver recreate a new pool each time.
pool . reset ( ) ;
return ;
}
m_query_pool_cache . emplace_back ( std : : move ( pool ) ) ;
}
query_pool_manager : : query_pool_ref : : ~ query_pool_ref ( )
{
m_pool_man - > on_query_pool_released ( m_object ) ;
}
2025-04-05 21:50:45 +02:00
} // namespace vk