From 5824a59ee2c325e04b18592b12c23a622ef32d72 Mon Sep 17 00:00:00 2001 From: Brian Ho Date: Thu, 2 Jan 2020 15:15:27 -0500 Subject: [PATCH] turnip: Implement vkCmdBeginQuery for occlusion queries Mostly a translation of freedreno's implementation of glBeginQuery for GL_SAMPLES_PASSED query objects with special logic for handling tiled render passes. Part-of: --- src/freedreno/vulkan/tu_query.c | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/freedreno/vulkan/tu_query.c b/src/freedreno/vulkan/tu_query.c index aaa61f63a9d..aad004878d2 100644 --- a/src/freedreno/vulkan/tu_query.c +++ b/src/freedreno/vulkan/tu_query.c @@ -31,8 +31,14 @@ #include #include +#include "registers/adreno_pm4.xml.h" +#include "registers/adreno_common.xml.h" +#include "registers/a6xx.xml.h" + #include "nir/nir_builder.h" +#include "tu_cs.h" + /* It seems like sample counts need to be copied over to 16-byte aligned * memory. */ struct PACKED slot_value { @@ -47,6 +53,15 @@ struct PACKED occlusion_query_slot { struct slot_value result; }; +/* Returns the IOVA of a given uint64_t field in a given slot of a query + * pool. */ +#define query_iova(type, pool, query, field) \ + pool->bo.iova + pool->stride * query + offsetof(type, field) + \ + offsetof(struct slot_value, value) + +#define occlusion_query_iova(pool, query, field) \ + query_iova(struct occlusion_query_slot, pool, query, field) + VkResult tu_CreateQueryPool(VkDevice _device, const VkQueryPoolCreateInfo *pCreateInfo, @@ -150,12 +165,65 @@ tu_CmdResetQueryPool(VkCommandBuffer commandBuffer, { } +static void +emit_begin_occlusion_query(struct tu_cmd_buffer *cmdbuf, + struct tu_query_pool *pool, + uint32_t query) +{ + /* From the Vulkan 1.1.130 spec: + * + * A query must begin and end inside the same subpass of a render pass + * instance, or must both begin and end outside of a render pass + * instance. + * + * Unlike on an immediate-mode renderer, Turnip renders all tiles on + * vkCmdEndRenderPass, not individually on each vkCmdDraw*. As such, if a + * query begins/ends inside the same subpass of a render pass, we need to + * record the packets on the secondary draw command stream. cmdbuf->draw_cs + * is then run on every tile during render, so we just need to accumulate + * sample counts in slot->result to compute the query result. + */ + struct tu_cs *cs = cmdbuf->state.pass ? &cmdbuf->draw_cs : &cmdbuf->cs; + + uint64_t begin_iova = occlusion_query_iova(pool, query, begin); + + tu_cs_reserve_space(cmdbuf->device, cs, 7); + tu_cs_emit_regs(cs, + A6XX_RB_SAMPLE_COUNT_CONTROL(.copy = true)); + + tu_cs_emit_regs(cs, + A6XX_RB_SAMPLE_COUNT_ADDR_LO(begin_iova)); + + tu_cs_emit_pkt7(cs, CP_EVENT_WRITE, 1); + tu_cs_emit(cs, ZPASS_DONE); +} + void tu_CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags) { + TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, commandBuffer); + TU_FROM_HANDLE(tu_query_pool, pool, queryPool); + assert(query < pool->size); + + switch (pool->type) { + case VK_QUERY_TYPE_OCCLUSION: + /* In freedreno, there is no implementation difference between + * GL_SAMPLES_PASSED and GL_ANY_SAMPLES_PASSED, so we can similarly + * ignore the VK_QUERY_CONTROL_PRECISE_BIT flag here. + */ + emit_begin_occlusion_query(cmdbuf, pool, query); + break; + case VK_QUERY_TYPE_PIPELINE_STATISTICS: + case VK_QUERY_TYPE_TIMESTAMP: + unreachable("Unimplemented query type"); + default: + assert(!"Invalid query type"); + } + + tu_bo_list_add(&cmdbuf->bo_list, &pool->bo, MSM_SUBMIT_BO_WRITE); } void -- 2.30.2