mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-07 15:31:26 +12:00
vk: Refactoring and optimizations to query handling
- Caches query results when looking up report availability to avoid entering driver code twice. - Minor code restructuring
This commit is contained in:
parent
55ad9244c0
commit
9f94a6dc11
2 changed files with 92 additions and 68 deletions
|
@ -2224,52 +2224,43 @@ void VKGSRender::sync_hint(rsx::FIFO_hint hint, void* args)
|
||||||
verify(HERE), args;
|
verify(HERE), args;
|
||||||
rsx::thread::sync_hint(hint, args);
|
rsx::thread::sync_hint(hint, args);
|
||||||
|
|
||||||
|
// Occlusion queries not enabled, do nothing
|
||||||
|
if (!(m_current_command_buffer->flags & vk::command_buffer::cb_has_occlusion_task))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if the required report is synced to this CB
|
||||||
|
auto occlusion_info = static_cast<rsx::reports::occlusion_query_info*>(args);
|
||||||
|
auto& data = m_occlusion_map[occlusion_info->driver_handle];
|
||||||
|
|
||||||
|
if (data.command_buffer_to_wait != m_current_command_buffer || data.indices.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
// Occlusion test result evaluation is coming up, avoid a hard sync
|
// Occlusion test result evaluation is coming up, avoid a hard sync
|
||||||
switch (hint)
|
switch (hint)
|
||||||
{
|
{
|
||||||
case rsx::FIFO_hint::hint_conditional_render_eval:
|
case rsx::FIFO_hint::hint_conditional_render_eval:
|
||||||
{
|
{
|
||||||
// Occlusion queries not enabled, do nothing
|
|
||||||
if (!(m_current_command_buffer->flags & vk::command_buffer::cb_has_occlusion_task))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If a flush request is already enqueued, do nothing
|
// If a flush request is already enqueued, do nothing
|
||||||
if (m_flush_requests.pending())
|
if (m_flush_requests.pending())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check if the required report is synced to this CB
|
// Schedule a sync on the next loop iteration
|
||||||
auto occlusion_info = static_cast<rsx::reports::occlusion_query_info*>(args);
|
m_flush_requests.post(false);
|
||||||
auto& data = m_occlusion_map[occlusion_info->driver_handle];
|
m_flush_requests.remove_one();
|
||||||
|
|
||||||
if (data.command_buffer_to_wait == m_current_command_buffer && !data.indices.empty())
|
|
||||||
{
|
|
||||||
// Confirmed hard sync coming up, post a sync request
|
|
||||||
m_flush_requests.post(false);
|
|
||||||
m_flush_requests.remove_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case rsx::FIFO_hint::hint_zcull_sync:
|
case rsx::FIFO_hint::hint_zcull_sync:
|
||||||
{
|
{
|
||||||
if (!(m_current_command_buffer->flags & vk::command_buffer::cb_has_occlusion_task))
|
// Unavoidable hard sync coming up, flush immediately
|
||||||
return;
|
// This heavyweight hint should be used with caution
|
||||||
|
std::lock_guard lock(m_flush_queue_mutex);
|
||||||
|
flush_command_queue();
|
||||||
|
|
||||||
auto occlusion_info = static_cast<rsx::reports::occlusion_query_info*>(args);
|
if (m_flush_requests.pending())
|
||||||
auto& data = m_occlusion_map[occlusion_info->driver_handle];
|
|
||||||
|
|
||||||
if (data.command_buffer_to_wait == m_current_command_buffer && !data.indices.empty())
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_flush_queue_mutex);
|
// Clear without wait
|
||||||
flush_command_queue();
|
m_flush_requests.clear_pending_flag();
|
||||||
|
|
||||||
if (m_flush_requests.pending())
|
|
||||||
{
|
|
||||||
// Clear without wait
|
|
||||||
m_flush_requests.clear_pending_flag();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2991,11 +2991,62 @@ public:
|
||||||
|
|
||||||
class occlusion_query_pool
|
class occlusion_query_pool
|
||||||
{
|
{
|
||||||
|
struct query_slot_info
|
||||||
|
{
|
||||||
|
bool any_passed;
|
||||||
|
bool active;
|
||||||
|
bool ready;
|
||||||
|
};
|
||||||
|
|
||||||
VkQueryPool query_pool = VK_NULL_HANDLE;
|
VkQueryPool query_pool = VK_NULL_HANDLE;
|
||||||
vk::render_device* owner = nullptr;
|
vk::render_device* owner = nullptr;
|
||||||
|
|
||||||
std::deque<u32> available_slots;
|
std::deque<u32> available_slots;
|
||||||
std::vector<bool> query_active_status;
|
std::vector<query_slot_info> query_slot_status;
|
||||||
|
|
||||||
|
inline bool poke_query(query_slot_info& query, u32 index)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
|
||||||
|
u32 result[2] = { 0, 0 };
|
||||||
|
switch (const auto error = vkGetQueryPoolResults(*owner, query_pool, index, 1, 8, result, 8, VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT))
|
||||||
|
{
|
||||||
|
case VK_SUCCESS:
|
||||||
|
{
|
||||||
|
if (result[0])
|
||||||
|
{
|
||||||
|
query.any_passed = true;
|
||||||
|
query.ready = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (result[1])
|
||||||
|
{
|
||||||
|
query.any_passed = false;
|
||||||
|
query.ready = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case VK_NOT_READY:
|
||||||
|
{
|
||||||
|
if (result[0])
|
||||||
|
{
|
||||||
|
query.any_passed = true;
|
||||||
|
query.ready = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
die_with_error(HERE, error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void create(vk::render_device &dev, u32 num_entries)
|
void create(vk::render_device &dev, u32 num_entries)
|
||||||
|
@ -3009,7 +3060,7 @@ public:
|
||||||
owner = &dev;
|
owner = &dev;
|
||||||
|
|
||||||
// From spec: "After query pool creation, each query must be reset before it is used."
|
// From spec: "After query pool creation, each query must be reset before it is used."
|
||||||
query_active_status.resize(num_entries, true);
|
query_slot_status.resize(num_entries, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy()
|
void destroy()
|
||||||
|
@ -3025,10 +3076,11 @@ public:
|
||||||
|
|
||||||
void initialize(vk::command_buffer &cmd)
|
void initialize(vk::command_buffer &cmd)
|
||||||
{
|
{
|
||||||
const u32 count = ::size32(query_active_status);
|
const u32 count = ::size32(query_slot_status);
|
||||||
vkCmdResetQueryPool(cmd, query_pool, 0, count);
|
vkCmdResetQueryPool(cmd, query_pool, 0, count);
|
||||||
|
|
||||||
std::fill(query_active_status.begin(), query_active_status.end(), false);
|
query_slot_info value{};
|
||||||
|
std::fill(query_slot_status.begin(), query_slot_status.end(), value);
|
||||||
|
|
||||||
for (u32 n = 0; n < count; ++n)
|
for (u32 n = 0; n < count; ++n)
|
||||||
{
|
{
|
||||||
|
@ -3038,14 +3090,15 @@ public:
|
||||||
|
|
||||||
void begin_query(vk::command_buffer &cmd, u32 index)
|
void begin_query(vk::command_buffer &cmd, u32 index)
|
||||||
{
|
{
|
||||||
if (query_active_status[index])
|
if (query_slot_status[index].active)
|
||||||
{
|
{
|
||||||
//Synchronization must be done externally
|
//Synchronization must be done externally
|
||||||
vkCmdResetQueryPool(cmd, query_pool, index, 1);
|
vkCmdResetQueryPool(cmd, query_pool, index, 1);
|
||||||
|
query_slot_status[index] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdBeginQuery(cmd, query_pool, index, 0);//VK_QUERY_CONTROL_PRECISE_BIT);
|
vkCmdBeginQuery(cmd, query_pool, index, 0);//VK_QUERY_CONTROL_PRECISE_BIT);
|
||||||
query_active_status[index] = true;
|
query_slot_status[index].active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void end_query(vk::command_buffer &cmd, u32 index)
|
void end_query(vk::command_buffer &cmd, u32 index)
|
||||||
|
@ -3055,40 +3108,20 @@ public:
|
||||||
|
|
||||||
bool check_query_status(u32 index)
|
bool check_query_status(u32 index)
|
||||||
{
|
{
|
||||||
u32 result[2] = {0, 0};
|
return poke_query(query_slot_status[index], index);
|
||||||
switch (const auto error = vkGetQueryPoolResults(*owner, query_pool, index, 1, 8, result, 8, VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT))
|
|
||||||
{
|
|
||||||
case VK_SUCCESS:
|
|
||||||
return (result[0] || result[1]);
|
|
||||||
case VK_NOT_READY:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
die_with_error(HERE, error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 get_query_result(u32 index)
|
u32 get_query_result(u32 index)
|
||||||
{
|
{
|
||||||
u32 result[2] = { 0, 0 };
|
// Check for cached result
|
||||||
|
auto& query_info = query_slot_status[index];
|
||||||
|
|
||||||
do
|
while (!query_info.ready)
|
||||||
{
|
{
|
||||||
switch (const auto error = vkGetQueryPoolResults(*owner, query_pool, index, 1, 8, result, 8, VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT))
|
poke_query(query_info, index);
|
||||||
{
|
|
||||||
case VK_SUCCESS:
|
|
||||||
if (result[0]) return 1u;
|
|
||||||
if (result[1]) return 0u; // Partial result can return SUCCESS when unavailable
|
|
||||||
continue;
|
|
||||||
case VK_NOT_READY:
|
|
||||||
if (result[0]) return 1u; // Partial result can return NOT_READY when unavailable
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
die_with_error(HERE, error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
while (true);
|
|
||||||
|
return query_info.any_passed ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_query_result_indirect(vk::command_buffer &cmd, u32 index, VkBuffer dst, VkDeviceSize dst_offset)
|
void get_query_result_indirect(vk::command_buffer &cmd, u32 index, VkBuffer dst, VkDeviceSize dst_offset)
|
||||||
|
@ -3098,11 +3131,11 @@ public:
|
||||||
|
|
||||||
void reset_query(vk::command_buffer &cmd, u32 index)
|
void reset_query(vk::command_buffer &cmd, u32 index)
|
||||||
{
|
{
|
||||||
if (query_active_status[index])
|
if (query_slot_status[index].active)
|
||||||
{
|
{
|
||||||
vkCmdResetQueryPool(cmd, query_pool, index, 1);
|
vkCmdResetQueryPool(cmd, query_pool, index, 1);
|
||||||
|
|
||||||
query_active_status[index] = false;
|
query_slot_status[index] = {};
|
||||||
available_slots.push_back(index);
|
available_slots.push_back(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3116,9 +3149,9 @@ public:
|
||||||
|
|
||||||
void reset_all(vk::command_buffer &cmd)
|
void reset_all(vk::command_buffer &cmd)
|
||||||
{
|
{
|
||||||
for (u32 n = 0; n < query_active_status.size(); n++)
|
for (u32 n = 0; n < query_slot_status.size(); n++)
|
||||||
{
|
{
|
||||||
if (query_active_status[n])
|
if (query_slot_status[n].active)
|
||||||
reset_query(cmd, n);
|
reset_query(cmd, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3133,7 +3166,7 @@ public:
|
||||||
u32 result = available_slots.front();
|
u32 result = available_slots.front();
|
||||||
available_slots.pop_front();
|
available_slots.pop_front();
|
||||||
|
|
||||||
verify(HERE), !query_active_status[result];
|
verify(HERE), !query_slot_status[result].active;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue