anv/query: Use a variable-length slot size

Not all queries are the same.  Even the two queries we support today
require a different amount of data per slot.  Once we introduce pipeline
statistics queries, the size will vary wildly.

Reviewed-By: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
This commit is contained in:
Jason Ekstrand 2017-03-14 17:58:44 -07:00
parent 1c797af2c6
commit bce4a935c6
2 changed files with 33 additions and 28 deletions

View file

@ -2013,14 +2013,11 @@ struct anv_render_pass {
struct anv_subpass subpasses[0]; struct anv_subpass subpasses[0];
}; };
struct anv_query_pool_slot {
uint64_t available;
uint64_t begin;
uint64_t end;
};
struct anv_query_pool { struct anv_query_pool {
VkQueryType type; VkQueryType type;
/** Stride between slots, in bytes */
uint32_t stride;
/** Number of slots in this query pool */
uint32_t slots; uint32_t slots;
struct anv_bo bo; struct anv_bo bo;
}; };

View file

@ -41,14 +41,24 @@ VkResult genX(CreateQueryPool)(
ANV_FROM_HANDLE(anv_device, device, _device); ANV_FROM_HANDLE(anv_device, device, _device);
struct anv_query_pool *pool; struct anv_query_pool *pool;
VkResult result; VkResult result;
uint32_t slot_size;
uint64_t size;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO); assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO);
/* Query pool slots are made up of some number of 64-bit values packed
* tightly together. The first 64-bit value is always the "available" bit
* which is 0 when the query is unavailable and 1 when it is available.
* The 64-bit values that follow are determined by the type of query.
*/
uint32_t uint64s_per_slot = 1;
switch (pCreateInfo->queryType) { switch (pCreateInfo->queryType) {
case VK_QUERY_TYPE_OCCLUSION: case VK_QUERY_TYPE_OCCLUSION:
/* Occlusion queries have two values: begin and end. */
uint64s_per_slot += 2;
break;
case VK_QUERY_TYPE_TIMESTAMP: case VK_QUERY_TYPE_TIMESTAMP:
/* Timestamps just have the one timestamp value */
uint64s_per_slot += 1;
break; break;
case VK_QUERY_TYPE_PIPELINE_STATISTICS: case VK_QUERY_TYPE_PIPELINE_STATISTICS:
return VK_ERROR_INCOMPATIBLE_DRIVER; return VK_ERROR_INCOMPATIBLE_DRIVER;
@ -56,16 +66,16 @@ VkResult genX(CreateQueryPool)(
assert(!"Invalid query type"); assert(!"Invalid query type");
} }
slot_size = sizeof(struct anv_query_pool_slot);
pool = vk_alloc2(&device->alloc, pAllocator, sizeof(*pool), 8, pool = vk_alloc2(&device->alloc, pAllocator, sizeof(*pool), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (pool == NULL) if (pool == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
pool->type = pCreateInfo->queryType; pool->type = pCreateInfo->queryType;
pool->stride = uint64s_per_slot * sizeof(uint64_t);
pool->slots = pCreateInfo->queryCount; pool->slots = pCreateInfo->queryCount;
size = pCreateInfo->queryCount * slot_size; uint64_t size = pool->slots * pool->stride;
result = anv_bo_init_new(&pool->bo, device, size); result = anv_bo_init_new(&pool->bo, device, size);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
goto fail; goto fail;
@ -130,18 +140,20 @@ VkResult genX(GetQueryPoolResults)(
} }
void *data_end = pData + dataSize; void *data_end = pData + dataSize;
struct anv_query_pool_slot *slot = pool->bo.map;
if (!device->info.has_llc) { if (!device->info.has_llc) {
uint64_t offset = firstQuery * sizeof(*slot); uint64_t offset = firstQuery * pool->stride;
uint64_t size = queryCount * sizeof(*slot); uint64_t size = queryCount * pool->stride;
anv_invalidate_range(pool->bo.map + offset, anv_invalidate_range(pool->bo.map + offset,
MIN2(size, pool->bo.size - offset)); MIN2(size, pool->bo.size - offset));
} }
VkResult status = VK_SUCCESS; VkResult status = VK_SUCCESS;
for (uint32_t i = 0; i < queryCount; i++) { for (uint32_t i = 0; i < queryCount; i++) {
bool available = slot[firstQuery + i].available; uint64_t *slot = pool->bo.map + (firstQuery + i) * pool->stride;
/* Availability is always at the start of the slot */
bool available = slot[0];
/* From the Vulkan 1.0.42 spec: /* From the Vulkan 1.0.42 spec:
* *
@ -157,13 +169,13 @@ VkResult genX(GetQueryPoolResults)(
if (write_results) { if (write_results) {
switch (pool->type) { switch (pool->type) {
case VK_QUERY_TYPE_OCCLUSION: { case VK_QUERY_TYPE_OCCLUSION: {
result = slot[firstQuery + i].end - slot[firstQuery + i].begin; result = slot[2] - slot[1];
break; break;
} }
case VK_QUERY_TYPE_PIPELINE_STATISTICS: case VK_QUERY_TYPE_PIPELINE_STATISTICS:
unreachable("pipeline stats not supported"); unreachable("pipeline stats not supported");
case VK_QUERY_TYPE_TIMESTAMP: { case VK_QUERY_TYPE_TIMESTAMP: {
result = slot[firstQuery + i].begin; result = slot[1];
break; break;
} }
default: default:
@ -178,13 +190,13 @@ VkResult genX(GetQueryPoolResults)(
if (write_results) if (write_results)
dst[0] = result; dst[0] = result;
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
dst[1] = slot[firstQuery + i].available; dst[1] = available;
} else { } else {
uint32_t *dst = pData; uint32_t *dst = pData;
if (write_results) if (write_results)
dst[0] = result; dst[0] = result;
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
dst[1] = slot[firstQuery + i].available; dst[1] = available;
} }
pData += stride; pData += stride;
@ -235,7 +247,7 @@ void genX(CmdResetQueryPool)(
anv_batch_emit(&cmd_buffer->batch, GENX(MI_STORE_DATA_IMM), sdm) { anv_batch_emit(&cmd_buffer->batch, GENX(MI_STORE_DATA_IMM), sdm) {
sdm.Address = (struct anv_address) { sdm.Address = (struct anv_address) {
.bo = &pool->bo, .bo = &pool->bo,
.offset = (firstQuery + i) * sizeof(struct anv_query_pool_slot), .offset = (firstQuery + i) * pool->stride,
}; };
sdm.DataDWord0 = 0; sdm.DataDWord0 = 0;
sdm.DataDWord1 = 0; sdm.DataDWord1 = 0;
@ -268,8 +280,7 @@ void genX(CmdBeginQuery)(
switch (pool->type) { switch (pool->type) {
case VK_QUERY_TYPE_OCCLUSION: case VK_QUERY_TYPE_OCCLUSION:
emit_ps_depth_count(cmd_buffer, &pool->bo, emit_ps_depth_count(cmd_buffer, &pool->bo, query * pool->stride + 8);
query * sizeof(struct anv_query_pool_slot) + 8);
break; break;
case VK_QUERY_TYPE_PIPELINE_STATISTICS: case VK_QUERY_TYPE_PIPELINE_STATISTICS:
@ -288,11 +299,8 @@ void genX(CmdEndQuery)(
switch (pool->type) { switch (pool->type) {
case VK_QUERY_TYPE_OCCLUSION: case VK_QUERY_TYPE_OCCLUSION:
emit_ps_depth_count(cmd_buffer, &pool->bo, emit_ps_depth_count(cmd_buffer, &pool->bo, query * pool->stride + 16);
query * sizeof(struct anv_query_pool_slot) + 16); emit_query_availability(cmd_buffer, &pool->bo, query * pool->stride);
emit_query_availability(cmd_buffer, &pool->bo,
query * sizeof(struct anv_query_pool_slot));
break; break;
case VK_QUERY_TYPE_PIPELINE_STATISTICS: case VK_QUERY_TYPE_PIPELINE_STATISTICS:
@ -311,7 +319,7 @@ void genX(CmdWriteTimestamp)(
{ {
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer); ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
ANV_FROM_HANDLE(anv_query_pool, pool, queryPool); ANV_FROM_HANDLE(anv_query_pool, pool, queryPool);
uint32_t offset = query * sizeof(struct anv_query_pool_slot); uint32_t offset = query * pool->stride;
assert(pool->type == VK_QUERY_TYPE_TIMESTAMP); assert(pool->type == VK_QUERY_TYPE_TIMESTAMP);
@ -433,7 +441,7 @@ void genX(CmdCopyQueryPoolResults)(
dst_offset = buffer->offset + destOffset; dst_offset = buffer->offset + destOffset;
for (uint32_t i = 0; i < queryCount; i++) { for (uint32_t i = 0; i < queryCount; i++) {
slot_offset = (firstQuery + i) * sizeof(struct anv_query_pool_slot); slot_offset = (firstQuery + i) * pool->stride;
switch (pool->type) { switch (pool->type) {
case VK_QUERY_TYPE_OCCLUSION: case VK_QUERY_TYPE_OCCLUSION:
emit_load_alu_reg_u64(&cmd_buffer->batch, emit_load_alu_reg_u64(&cmd_buffer->batch,