2019-05-26 10:43:12 +02:00
|
|
|
|
/*
|
|
|
|
|
|
* Copyright © Microsoft Corporation
|
|
|
|
|
|
*
|
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
*
|
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
|
* Software.
|
|
|
|
|
|
*
|
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "d3d12_query.h"
|
2022-01-29 09:37:49 -08:00
|
|
|
|
#include "d3d12_compiler.h"
|
2019-05-26 10:43:12 +02:00
|
|
|
|
#include "d3d12_context.h"
|
|
|
|
|
|
#include "d3d12_resource.h"
|
|
|
|
|
|
#include "d3d12_screen.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "util/u_dump.h"
|
|
|
|
|
|
#include "util/u_inlines.h"
|
|
|
|
|
|
#include "util/u_memory.h"
|
2021-11-03 10:20:44 -07:00
|
|
|
|
#include "util/u_threaded_context.h"
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
2020-12-08 10:02:35 -08:00
|
|
|
|
#include <dxguids/dxguids.h>
|
|
|
|
|
|
|
2022-01-29 09:37:49 -08:00
|
|
|
|
constexpr unsigned MAX_SUBQUERIES = 3;
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
struct d3d12_query_impl {
|
2019-05-26 10:43:12 +02:00
|
|
|
|
ID3D12QueryHeap *query_heap;
|
|
|
|
|
|
unsigned curr_query, num_queries;
|
|
|
|
|
|
size_t query_size;
|
|
|
|
|
|
|
|
|
|
|
|
D3D12_QUERY_TYPE d3d12qtype;
|
|
|
|
|
|
|
|
|
|
|
|
pipe_resource *buffer;
|
|
|
|
|
|
unsigned buffer_offset;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
|
|
|
|
|
|
bool active;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct d3d12_query {
|
|
|
|
|
|
struct threaded_query base;
|
|
|
|
|
|
enum pipe_query_type type;
|
|
|
|
|
|
|
2022-01-29 09:37:49 -08:00
|
|
|
|
struct d3d12_query_impl subqueries[MAX_SUBQUERIES];
|
2022-01-27 07:19:51 -08:00
|
|
|
|
|
2019-05-26 10:43:12 +02:00
|
|
|
|
struct list_head active_list;
|
|
|
|
|
|
struct d3d12_resource *predicate;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
static unsigned
|
|
|
|
|
|
num_sub_queries(unsigned query_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (query_type) {
|
|
|
|
|
|
case PIPE_QUERY_PRIMITIVES_GENERATED:
|
2022-01-29 09:37:49 -08:00
|
|
|
|
return 3;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
default:
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-26 10:43:12 +02:00
|
|
|
|
static D3D12_QUERY_HEAP_TYPE
|
2022-01-27 07:19:51 -08:00
|
|
|
|
d3d12_query_heap_type(unsigned query_type, unsigned sub_query)
|
2019-05-26 10:43:12 +02:00
|
|
|
|
{
|
|
|
|
|
|
switch (query_type) {
|
|
|
|
|
|
case PIPE_QUERY_OCCLUSION_COUNTER:
|
|
|
|
|
|
case PIPE_QUERY_OCCLUSION_PREDICATE:
|
|
|
|
|
|
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
|
|
|
|
|
|
return D3D12_QUERY_HEAP_TYPE_OCCLUSION;
|
|
|
|
|
|
case PIPE_QUERY_PIPELINE_STATISTICS:
|
|
|
|
|
|
return D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS;
|
|
|
|
|
|
case PIPE_QUERY_PRIMITIVES_GENERATED:
|
2022-01-27 07:19:51 -08:00
|
|
|
|
return sub_query == 0 ?
|
|
|
|
|
|
D3D12_QUERY_HEAP_TYPE_SO_STATISTICS :
|
|
|
|
|
|
D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS;
|
2019-05-26 10:43:12 +02:00
|
|
|
|
case PIPE_QUERY_PRIMITIVES_EMITTED:
|
|
|
|
|
|
case PIPE_QUERY_SO_STATISTICS:
|
|
|
|
|
|
return D3D12_QUERY_HEAP_TYPE_SO_STATISTICS;
|
|
|
|
|
|
case PIPE_QUERY_TIMESTAMP:
|
|
|
|
|
|
case PIPE_QUERY_TIME_ELAPSED:
|
|
|
|
|
|
return D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
debug_printf("unknown query: %s\n",
|
|
|
|
|
|
util_str_query_type(query_type, true));
|
|
|
|
|
|
unreachable("d3d12: unknown query type");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static D3D12_QUERY_TYPE
|
2022-01-29 09:41:03 -08:00
|
|
|
|
d3d12_query_type(unsigned query_type, unsigned sub_query, unsigned index)
|
2019-05-26 10:43:12 +02:00
|
|
|
|
{
|
|
|
|
|
|
switch (query_type) {
|
|
|
|
|
|
case PIPE_QUERY_OCCLUSION_COUNTER:
|
|
|
|
|
|
return D3D12_QUERY_TYPE_OCCLUSION;
|
|
|
|
|
|
case PIPE_QUERY_OCCLUSION_PREDICATE:
|
|
|
|
|
|
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
|
|
|
|
|
|
return D3D12_QUERY_TYPE_BINARY_OCCLUSION;
|
|
|
|
|
|
case PIPE_QUERY_PIPELINE_STATISTICS:
|
|
|
|
|
|
return D3D12_QUERY_TYPE_PIPELINE_STATISTICS;
|
|
|
|
|
|
case PIPE_QUERY_PRIMITIVES_GENERATED:
|
2022-01-27 07:19:51 -08:00
|
|
|
|
return sub_query == 0 ?
|
|
|
|
|
|
D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 :
|
|
|
|
|
|
D3D12_QUERY_TYPE_PIPELINE_STATISTICS;
|
2019-05-26 10:43:12 +02:00
|
|
|
|
case PIPE_QUERY_PRIMITIVES_EMITTED:
|
|
|
|
|
|
case PIPE_QUERY_SO_STATISTICS:
|
2022-01-29 09:41:03 -08:00
|
|
|
|
return (D3D12_QUERY_TYPE)(D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 + index);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
case PIPE_QUERY_TIMESTAMP:
|
|
|
|
|
|
case PIPE_QUERY_TIME_ELAPSED:
|
|
|
|
|
|
return D3D12_QUERY_TYPE_TIMESTAMP;
|
|
|
|
|
|
default:
|
|
|
|
|
|
debug_printf("unknown query: %s\n",
|
|
|
|
|
|
util_str_query_type(query_type, true));
|
|
|
|
|
|
unreachable("d3d12: unknown query type");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct pipe_query *
|
|
|
|
|
|
d3d12_create_query(struct pipe_context *pctx,
|
|
|
|
|
|
unsigned query_type, unsigned index)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(pctx->screen);
|
|
|
|
|
|
struct d3d12_query *query = CALLOC_STRUCT(d3d12_query);
|
|
|
|
|
|
D3D12_QUERY_HEAP_DESC desc = {};
|
|
|
|
|
|
|
|
|
|
|
|
if (!query)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
query->type = (pipe_query_type)query_type;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
for (unsigned i = 0; i < num_sub_queries(query_type); ++i) {
|
2022-01-29 09:37:49 -08:00
|
|
|
|
assert(i < MAX_SUBQUERIES);
|
2022-01-29 09:41:03 -08:00
|
|
|
|
query->subqueries[i].d3d12qtype = d3d12_query_type(query_type, i, index);
|
2022-01-27 07:19:51 -08:00
|
|
|
|
query->subqueries[i].num_queries = 16;
|
|
|
|
|
|
|
|
|
|
|
|
/* With timer queries we want a few more queries, especially since we need two slots
|
|
|
|
|
|
* per query for TIME_ELAPSED queries
|
|
|
|
|
|
* For TIMESTAMP, we don't need more than one slot, since there's nothing to accumulate */
|
|
|
|
|
|
if (unlikely(query_type == PIPE_QUERY_TIME_ELAPSED))
|
|
|
|
|
|
query->subqueries[i].num_queries = 64;
|
|
|
|
|
|
else if (query_type == PIPE_QUERY_TIMESTAMP)
|
|
|
|
|
|
query->subqueries[i].num_queries = 1;
|
|
|
|
|
|
|
|
|
|
|
|
query->subqueries[i].curr_query = 0;
|
2022-01-29 09:41:03 -08:00
|
|
|
|
desc.Count = query->subqueries[i].num_queries;
|
|
|
|
|
|
desc.Type = d3d12_query_heap_type(query_type, i);
|
2022-01-27 07:19:51 -08:00
|
|
|
|
|
2022-01-29 09:41:03 -08:00
|
|
|
|
switch (desc.Type) {
|
|
|
|
|
|
case D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS:
|
2022-01-27 07:19:51 -08:00
|
|
|
|
query->subqueries[i].query_size = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS);
|
|
|
|
|
|
break;
|
2022-01-29 09:41:03 -08:00
|
|
|
|
case D3D12_QUERY_HEAP_TYPE_SO_STATISTICS:
|
2022-01-27 07:19:51 -08:00
|
|
|
|
query->subqueries[i].query_size = sizeof(D3D12_QUERY_DATA_SO_STATISTICS);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
query->subqueries[i].query_size = sizeof(uint64_t);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (FAILED(screen->dev->CreateQueryHeap(&desc,
|
|
|
|
|
|
IID_PPV_ARGS(&query->subqueries[i].query_heap)))) {
|
|
|
|
|
|
FREE(query);
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
/* Query result goes into a readback buffer */
|
|
|
|
|
|
size_t buffer_size = query->subqueries[i].query_size * query->subqueries[i].num_queries;
|
|
|
|
|
|
u_suballocator_alloc(&ctx->query_allocator, buffer_size, 256,
|
|
|
|
|
|
&query->subqueries[i].buffer_offset, &query->subqueries[i].buffer);
|
|
|
|
|
|
|
|
|
|
|
|
query->subqueries[i].active = (query_type == PIPE_QUERY_TIMESTAMP);
|
|
|
|
|
|
}
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
|
|
|
|
|
return (struct pipe_query *)query;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
d3d12_destroy_query(struct pipe_context *pctx,
|
|
|
|
|
|
struct pipe_query *q)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_query *query = (struct d3d12_query *)q;
|
2021-11-03 10:23:14 -07:00
|
|
|
|
pipe_resource *predicate = &query->predicate->base.b;
|
2019-05-26 10:43:12 +02:00
|
|
|
|
pipe_resource_reference(&predicate, NULL);
|
2022-01-27 07:19:51 -08:00
|
|
|
|
for (unsigned i = 0; i < num_sub_queries(query->type); ++i) {
|
|
|
|
|
|
query->subqueries[i].query_heap->Release();
|
|
|
|
|
|
pipe_resource_reference(&query->subqueries[i].buffer, NULL);
|
|
|
|
|
|
}
|
2019-05-26 10:43:12 +02:00
|
|
|
|
FREE(query);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
2022-01-27 07:19:51 -08:00
|
|
|
|
accumulate_subresult(struct d3d12_context *ctx, struct d3d12_query *q_parent,
|
|
|
|
|
|
unsigned sub_query,
|
2022-02-10 11:11:13 -08:00
|
|
|
|
union pipe_query_result *result, bool write, bool wait)
|
2019-05-26 10:43:12 +02:00
|
|
|
|
{
|
|
|
|
|
|
struct pipe_transfer *transfer = NULL;
|
|
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
|
2022-01-27 07:19:51 -08:00
|
|
|
|
struct d3d12_query_impl *q = &q_parent->subqueries[sub_query];
|
2019-05-26 10:43:12 +02:00
|
|
|
|
unsigned access = PIPE_MAP_READ;
|
|
|
|
|
|
void *results;
|
|
|
|
|
|
|
|
|
|
|
|
if (write)
|
|
|
|
|
|
access |= PIPE_MAP_WRITE;
|
2022-02-10 11:11:13 -08:00
|
|
|
|
if (!wait)
|
|
|
|
|
|
access |= PIPE_MAP_DONTBLOCK;
|
2019-05-26 10:43:12 +02:00
|
|
|
|
results = pipe_buffer_map_range(&ctx->base, q->buffer, q->buffer_offset,
|
|
|
|
|
|
q->num_queries * q->query_size,
|
|
|
|
|
|
access, &transfer);
|
|
|
|
|
|
|
|
|
|
|
|
if (results == NULL)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t *results_u64 = (uint64_t *)results;
|
|
|
|
|
|
D3D12_QUERY_DATA_PIPELINE_STATISTICS *results_stats = (D3D12_QUERY_DATA_PIPELINE_STATISTICS *)results;
|
|
|
|
|
|
D3D12_QUERY_DATA_SO_STATISTICS *results_so = (D3D12_QUERY_DATA_SO_STATISTICS *)results;
|
|
|
|
|
|
|
2022-01-10 09:39:20 -08:00
|
|
|
|
memset(result, 0, sizeof(*result));
|
2020-11-25 17:02:25 -08:00
|
|
|
|
for (unsigned i = 0; i < q->curr_query; ++i) {
|
2022-01-27 07:19:51 -08:00
|
|
|
|
switch (q->d3d12qtype) {
|
|
|
|
|
|
case D3D12_QUERY_TYPE_BINARY_OCCLUSION:
|
2019-05-26 10:43:12 +02:00
|
|
|
|
result->b |= results_u64[i] != 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
case D3D12_QUERY_TYPE_OCCLUSION:
|
2019-05-26 10:43:12 +02:00
|
|
|
|
result->u64 += results_u64[i];
|
|
|
|
|
|
break;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
|
|
|
|
|
|
case D3D12_QUERY_TYPE_TIMESTAMP:
|
|
|
|
|
|
if (q_parent->type == PIPE_QUERY_TIME_ELAPSED)
|
|
|
|
|
|
result->u64 += results_u64[2 * i + 1] - results_u64[2 * i];
|
|
|
|
|
|
else
|
|
|
|
|
|
result->u64 = results_u64[i];
|
2019-05-26 10:43:12 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
case D3D12_QUERY_TYPE_PIPELINE_STATISTICS:
|
2019-05-26 10:43:12 +02:00
|
|
|
|
result->pipeline_statistics.ia_vertices += results_stats[i].IAVertices;
|
|
|
|
|
|
result->pipeline_statistics.ia_primitives += results_stats[i].IAPrimitives;
|
|
|
|
|
|
result->pipeline_statistics.vs_invocations += results_stats[i].VSInvocations;
|
|
|
|
|
|
result->pipeline_statistics.gs_invocations += results_stats[i].GSInvocations;
|
|
|
|
|
|
result->pipeline_statistics.gs_primitives += results_stats[i].GSPrimitives;
|
|
|
|
|
|
result->pipeline_statistics.c_invocations += results_stats[i].CInvocations;
|
|
|
|
|
|
result->pipeline_statistics.c_primitives += results_stats[i].CPrimitives;
|
|
|
|
|
|
result->pipeline_statistics.ps_invocations += results_stats[i].PSInvocations;
|
|
|
|
|
|
result->pipeline_statistics.hs_invocations += results_stats[i].HSInvocations;
|
|
|
|
|
|
result->pipeline_statistics.ds_invocations += results_stats[i].DSInvocations;
|
|
|
|
|
|
result->pipeline_statistics.cs_invocations += results_stats[i].CSInvocations;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0:
|
2022-01-29 09:41:03 -08:00
|
|
|
|
case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM1:
|
|
|
|
|
|
case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM2:
|
|
|
|
|
|
case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3:
|
2019-05-26 10:43:12 +02:00
|
|
|
|
result->so_statistics.num_primitives_written += results_so[i].NumPrimitivesWritten;
|
|
|
|
|
|
result->so_statistics.primitives_storage_needed += results_so[i].PrimitivesStorageNeeded;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
debug_printf("unsupported query type: %s\n",
|
2022-01-27 07:19:51 -08:00
|
|
|
|
util_str_query_type(q_parent->type, true));
|
2019-05-26 10:43:12 +02:00
|
|
|
|
unreachable("unexpected query type");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (write) {
|
2022-01-27 07:19:51 -08:00
|
|
|
|
if (q->d3d12qtype == D3D12_QUERY_TYPE_PIPELINE_STATISTICS) {
|
2019-05-26 10:43:12 +02:00
|
|
|
|
results_stats[0].IAVertices = result->pipeline_statistics.ia_vertices;
|
|
|
|
|
|
results_stats[0].IAPrimitives = result->pipeline_statistics.ia_primitives;
|
|
|
|
|
|
results_stats[0].VSInvocations = result->pipeline_statistics.vs_invocations;
|
|
|
|
|
|
results_stats[0].GSInvocations = result->pipeline_statistics.gs_invocations;
|
|
|
|
|
|
results_stats[0].GSPrimitives = result->pipeline_statistics.gs_primitives;
|
|
|
|
|
|
results_stats[0].CInvocations = result->pipeline_statistics.c_invocations;
|
|
|
|
|
|
results_stats[0].CPrimitives = result->pipeline_statistics.c_primitives;
|
|
|
|
|
|
results_stats[0].PSInvocations = result->pipeline_statistics.ps_invocations;
|
|
|
|
|
|
results_stats[0].HSInvocations = result->pipeline_statistics.hs_invocations;
|
|
|
|
|
|
results_stats[0].DSInvocations = result->pipeline_statistics.ds_invocations;
|
|
|
|
|
|
results_stats[0].CSInvocations = result->pipeline_statistics.cs_invocations;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
} else if (d3d12_query_heap_type(q_parent->type, sub_query) == D3D12_QUERY_HEAP_TYPE_SO_STATISTICS) {
|
2019-05-26 10:43:12 +02:00
|
|
|
|
results_so[0].NumPrimitivesWritten = result->so_statistics.num_primitives_written;
|
|
|
|
|
|
results_so[0].PrimitivesStorageNeeded = result->so_statistics.primitives_storage_needed;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (unlikely(q->d3d12qtype == D3D12_QUERY_TYPE_TIMESTAMP)) {
|
|
|
|
|
|
results_u64[0] = 0;
|
|
|
|
|
|
results_u64[1] = result->u64;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
results_u64[0] = result->u64;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pipe_buffer_unmap(&ctx->base, transfer);
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
if (q->d3d12qtype == D3D12_QUERY_TYPE_TIMESTAMP)
|
2019-05-26 10:43:12 +02:00
|
|
|
|
result->u64 = static_cast<uint64_t>(screen->timestamp_multiplier * result->u64);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
static bool
|
|
|
|
|
|
accumulate_result(struct d3d12_context *ctx, struct d3d12_query *q,
|
2022-02-10 11:11:13 -08:00
|
|
|
|
union pipe_query_result *result, bool write, bool wait)
|
2022-01-27 07:19:51 -08:00
|
|
|
|
{
|
|
|
|
|
|
union pipe_query_result local_result;
|
|
|
|
|
|
|
|
|
|
|
|
switch (q->type) {
|
|
|
|
|
|
case PIPE_QUERY_PRIMITIVES_GENERATED:
|
2022-02-10 11:11:13 -08:00
|
|
|
|
if (!accumulate_subresult(ctx, q, 0, &local_result, write, wait))
|
2022-01-27 07:19:51 -08:00
|
|
|
|
return false;
|
|
|
|
|
|
result->u64 = local_result.so_statistics.primitives_storage_needed;
|
|
|
|
|
|
|
2022-02-10 11:11:13 -08:00
|
|
|
|
if (!accumulate_subresult(ctx, q, 1, &local_result, write, wait))
|
2022-01-27 07:19:51 -08:00
|
|
|
|
return false;
|
2022-01-29 09:37:49 -08:00
|
|
|
|
result->u64 += local_result.pipeline_statistics.gs_primitives;
|
|
|
|
|
|
|
2022-02-10 11:11:13 -08:00
|
|
|
|
if (!accumulate_subresult(ctx, q, 2, &local_result, write, wait))
|
2022-01-29 09:37:49 -08:00
|
|
|
|
return false;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
result->u64 += local_result.pipeline_statistics.ia_primitives;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
case PIPE_QUERY_PRIMITIVES_EMITTED:
|
2022-02-10 11:11:13 -08:00
|
|
|
|
if (!accumulate_subresult(ctx, q, 0, &local_result, write, wait))
|
2022-01-27 07:19:51 -08:00
|
|
|
|
return false;
|
|
|
|
|
|
result->u64 = local_result.so_statistics.num_primitives_written;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
default:
|
|
|
|
|
|
assert(num_sub_queries(q->type) == 1);
|
2022-02-10 11:11:13 -08:00
|
|
|
|
return accumulate_subresult(ctx, q, 0, result, write, wait);
|
2022-01-27 07:19:51 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
|
subquery_should_be_active(struct d3d12_context *ctx, struct d3d12_query *q, unsigned sub_query)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (q->type) {
|
|
|
|
|
|
case PIPE_QUERY_PRIMITIVES_GENERATED: {
|
|
|
|
|
|
bool has_xfb = !!ctx->gfx_pipeline_state.num_so_targets;
|
2022-01-29 09:37:49 -08:00
|
|
|
|
struct d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
|
|
|
|
|
|
bool has_gs = gs && !gs->is_variant;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
switch (sub_query) {
|
|
|
|
|
|
case 0: return has_xfb;
|
2022-01-29 09:37:49 -08:00
|
|
|
|
case 1: return !has_xfb && has_gs;
|
|
|
|
|
|
case 2: return !has_xfb && !has_gs;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
default: unreachable("Invalid subquery for primitives generated");
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-26 10:43:12 +02:00
|
|
|
|
static void
|
2022-01-27 07:19:51 -08:00
|
|
|
|
begin_subquery(struct d3d12_context *ctx, struct d3d12_query *q_parent, unsigned sub_query)
|
2019-05-26 10:43:12 +02:00
|
|
|
|
{
|
2022-01-27 07:19:51 -08:00
|
|
|
|
struct d3d12_query_impl *q = &q_parent->subqueries[sub_query];
|
|
|
|
|
|
if (q->curr_query == q->num_queries) {
|
2019-05-26 10:43:12 +02:00
|
|
|
|
union pipe_query_result result;
|
|
|
|
|
|
|
|
|
|
|
|
/* Accumulate current results and store in first slot */
|
2022-02-10 11:11:13 -08:00
|
|
|
|
accumulate_subresult(ctx, q_parent, sub_query, &result, true, true);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
q->curr_query = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ctx->cmdlist->BeginQuery(q->query_heap, q->d3d12qtype, q->curr_query);
|
2022-01-27 07:19:51 -08:00
|
|
|
|
q->active = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
begin_query(struct d3d12_context *ctx, struct d3d12_query *q_parent, bool restart)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (unsigned i = 0; i < num_sub_queries(q_parent->type); ++i) {
|
|
|
|
|
|
if (restart)
|
|
|
|
|
|
q_parent->subqueries[i].curr_query = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (!subquery_should_be_active(ctx, q_parent, i))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
begin_subquery(ctx, q_parent, i);
|
|
|
|
|
|
}
|
2019-05-26 10:43:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2022-01-27 07:19:51 -08:00
|
|
|
|
begin_timer_query(struct d3d12_context *ctx, struct d3d12_query *q_parent, bool restart)
|
2019-05-26 10:43:12 +02:00
|
|
|
|
{
|
2022-01-27 07:19:51 -08:00
|
|
|
|
struct d3d12_query_impl *q = &q_parent->subqueries[0];
|
|
|
|
|
|
|
2019-05-26 10:43:12 +02:00
|
|
|
|
/* For PIPE_QUERY_TIME_ELAPSED we record one time with BeginQuery and one in
|
|
|
|
|
|
* EndQuery, so we need two query slots */
|
|
|
|
|
|
unsigned query_index = 2 * q->curr_query;
|
|
|
|
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
|
|
q->curr_query = 0;
|
|
|
|
|
|
query_index = 0;
|
|
|
|
|
|
} else if (query_index == q->num_queries) {
|
|
|
|
|
|
union pipe_query_result result;
|
|
|
|
|
|
|
|
|
|
|
|
/* Accumulate current results and store in first slot */
|
|
|
|
|
|
d3d12_flush_cmdlist_and_wait(ctx);
|
2022-02-10 11:11:13 -08:00
|
|
|
|
accumulate_subresult(ctx, q_parent, 0, &result, true, true);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
q->curr_query = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ctx->cmdlist->EndQuery(q->query_heap, q->d3d12qtype, query_index);
|
2022-01-27 07:19:51 -08:00
|
|
|
|
q->active = true;
|
2019-05-26 10:43:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
|
d3d12_begin_query(struct pipe_context *pctx,
|
|
|
|
|
|
struct pipe_query *q)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
|
struct d3d12_query *query = (struct d3d12_query *)q;
|
|
|
|
|
|
|
|
|
|
|
|
assert(query->type != PIPE_QUERY_TIMESTAMP);
|
|
|
|
|
|
|
|
|
|
|
|
if (unlikely(query->type == PIPE_QUERY_TIME_ELAPSED))
|
|
|
|
|
|
begin_timer_query(ctx, query, true);
|
|
|
|
|
|
else {
|
|
|
|
|
|
begin_query(ctx, query, true);
|
|
|
|
|
|
list_addtail(&query->active_list, &ctx->active_queries);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2022-01-27 07:19:51 -08:00
|
|
|
|
end_subquery(struct d3d12_context *ctx, struct d3d12_query *q_parent, unsigned sub_query)
|
2019-05-26 10:43:12 +02:00
|
|
|
|
{
|
2022-01-27 07:19:51 -08:00
|
|
|
|
struct d3d12_query_impl *q = &q_parent->subqueries[sub_query];
|
|
|
|
|
|
|
2019-05-26 10:43:12 +02:00
|
|
|
|
uint64_t offset = 0;
|
|
|
|
|
|
struct d3d12_batch *batch = d3d12_current_batch(ctx);
|
|
|
|
|
|
struct d3d12_resource *res = (struct d3d12_resource *)q->buffer;
|
|
|
|
|
|
ID3D12Resource *d3d12_res = d3d12_resource_underlying(res, &offset);
|
|
|
|
|
|
|
2021-09-17 18:53:02 -07:00
|
|
|
|
/* For TIMESTAMP, there's only one slot */
|
2022-01-27 07:19:51 -08:00
|
|
|
|
if (q_parent->type == PIPE_QUERY_TIMESTAMP)
|
2021-09-17 18:53:02 -07:00
|
|
|
|
q->curr_query = 0;
|
|
|
|
|
|
|
2019-05-26 10:43:12 +02:00
|
|
|
|
/* With QUERY_TIME_ELAPSED we have recorded one value at
|
2022-01-27 07:19:51 -08:00
|
|
|
|
* (2 * q->curr_query), and now we record a value at (2 * q->curr_query + 1)
|
|
|
|
|
|
* and when resolving the query we subtract the latter from the former */
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
unsigned resolve_count = q_parent->type == PIPE_QUERY_TIME_ELAPSED ? 2 : 1;
|
2019-05-26 10:43:12 +02:00
|
|
|
|
unsigned resolve_index = resolve_count * q->curr_query;
|
|
|
|
|
|
unsigned end_index = resolve_index + resolve_count - 1;
|
|
|
|
|
|
|
|
|
|
|
|
offset += q->buffer_offset + resolve_index * q->query_size;
|
|
|
|
|
|
ctx->cmdlist->EndQuery(q->query_heap, q->d3d12qtype, end_index);
|
2022-07-21 09:10:13 -07:00
|
|
|
|
d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
|
2022-01-26 08:31:33 -08:00
|
|
|
|
d3d12_apply_resource_states(ctx, false);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
ctx->cmdlist->ResolveQueryData(q->query_heap, q->d3d12qtype, resolve_index,
|
2022-01-27 07:19:51 -08:00
|
|
|
|
resolve_count, d3d12_res, offset);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
|
|
|
|
|
d3d12_batch_reference_object(batch, q->query_heap);
|
2021-11-03 17:05:05 -07:00
|
|
|
|
d3d12_batch_reference_resource(batch, res, true);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
|
|
|
|
|
assert(q->curr_query < q->num_queries);
|
|
|
|
|
|
q->curr_query++;
|
2022-01-27 07:19:51 -08:00
|
|
|
|
q->active = (q_parent->type == PIPE_QUERY_TIMESTAMP);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
end_query(struct d3d12_context *ctx, struct d3d12_query *q_parent)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (unsigned i = 0; i < num_sub_queries(q_parent->type); ++i) {
|
|
|
|
|
|
struct d3d12_query_impl *q = &q_parent->subqueries[i];
|
|
|
|
|
|
if (!q->active)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
end_subquery(ctx, q_parent, i);
|
|
|
|
|
|
}
|
2019-05-26 10:43:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
|
d3d12_end_query(struct pipe_context *pctx,
|
|
|
|
|
|
struct pipe_query *q)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
|
struct d3d12_query *query = (struct d3d12_query *)q;
|
|
|
|
|
|
|
|
|
|
|
|
end_query(ctx, query);
|
|
|
|
|
|
|
|
|
|
|
|
if (query->type != PIPE_QUERY_TIMESTAMP &&
|
|
|
|
|
|
query->type != PIPE_QUERY_TIME_ELAPSED)
|
|
|
|
|
|
list_delinit(&query->active_list);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
|
d3d12_get_query_result(struct pipe_context *pctx,
|
|
|
|
|
|
struct pipe_query *q,
|
|
|
|
|
|
bool wait,
|
|
|
|
|
|
union pipe_query_result *result)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
|
struct d3d12_query *query = (struct d3d12_query *)q;
|
|
|
|
|
|
|
2022-02-10 11:11:13 -08:00
|
|
|
|
return accumulate_result(ctx, query, result, false, wait);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
d3d12_suspend_queries(struct d3d12_context *ctx)
|
|
|
|
|
|
{
|
|
|
|
|
|
list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) {
|
|
|
|
|
|
end_query(ctx, query);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
d3d12_resume_queries(struct d3d12_context *ctx)
|
|
|
|
|
|
{
|
|
|
|
|
|
list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) {
|
|
|
|
|
|
begin_query(ctx, query, false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
d3d12_validate_queries(struct d3d12_context *ctx)
|
|
|
|
|
|
{
|
2022-01-27 07:19:51 -08:00
|
|
|
|
/* Nothing to do, all queries are suspended */
|
|
|
|
|
|
if (ctx->queries_disabled)
|
|
|
|
|
|
return;
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) {
|
2022-01-27 07:19:51 -08:00
|
|
|
|
for (unsigned i = 0; i < num_sub_queries(query->type); ++i) {
|
|
|
|
|
|
if (query->subqueries[i].active && !subquery_should_be_active(ctx, query, i))
|
|
|
|
|
|
end_subquery(ctx, query, i);
|
|
|
|
|
|
else if (!query->subqueries[i].active && subquery_should_be_active(ctx, query, i))
|
|
|
|
|
|
begin_subquery(ctx, query, i);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
d3d12_set_active_query_state(struct pipe_context *pctx, bool enable)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
|
ctx->queries_disabled = !enable;
|
|
|
|
|
|
|
|
|
|
|
|
if (enable)
|
|
|
|
|
|
d3d12_resume_queries(ctx);
|
|
|
|
|
|
else
|
|
|
|
|
|
d3d12_suspend_queries(ctx);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
d3d12_render_condition(struct pipe_context *pctx,
|
|
|
|
|
|
struct pipe_query *pquery,
|
|
|
|
|
|
bool condition,
|
|
|
|
|
|
enum pipe_render_cond_flag mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
|
struct d3d12_query *query = (struct d3d12_query *)pquery;
|
|
|
|
|
|
|
|
|
|
|
|
if (query == nullptr) {
|
|
|
|
|
|
ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
|
|
|
|
|
|
ctx->current_predication = nullptr;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
assert(num_sub_queries(query->type) == 1);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
if (!query->predicate)
|
|
|
|
|
|
query->predicate = d3d12_resource(pipe_buffer_create(pctx->screen, 0,
|
|
|
|
|
|
PIPE_USAGE_DEFAULT, sizeof(uint64_t)));
|
|
|
|
|
|
|
|
|
|
|
|
if (mode == PIPE_RENDER_COND_WAIT) {
|
|
|
|
|
|
d3d12_flush_cmdlist_and_wait(ctx);
|
|
|
|
|
|
union pipe_query_result result;
|
2022-02-10 11:11:13 -08:00
|
|
|
|
accumulate_result(ctx, (d3d12_query *)pquery, &result, true, true);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-27 07:19:51 -08:00
|
|
|
|
struct d3d12_resource *res = (struct d3d12_resource *)query->subqueries[0].buffer;
|
|
|
|
|
|
uint64_t source_offset = 0;
|
|
|
|
|
|
ID3D12Resource *source = d3d12_resource_underlying(res, &source_offset);
|
|
|
|
|
|
source_offset += query->subqueries[0].buffer_offset;
|
2022-07-21 09:10:13 -07:00
|
|
|
|
d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
|
|
|
|
|
|
d3d12_transition_resource_state(ctx, query->predicate, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_NONE);
|
2022-01-26 08:31:33 -08:00
|
|
|
|
d3d12_apply_resource_states(ctx, false);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
ctx->cmdlist->CopyBufferRegion(d3d12_resource_resource(query->predicate), 0,
|
2022-01-27 07:19:51 -08:00
|
|
|
|
source, source_offset,
|
2019-05-26 10:43:12 +02:00
|
|
|
|
sizeof(uint64_t));
|
|
|
|
|
|
|
2022-07-21 09:10:13 -07:00
|
|
|
|
d3d12_transition_resource_state(ctx, query->predicate, D3D12_RESOURCE_STATE_PREDICATION, D3D12_TRANSITION_FLAG_NONE);
|
2022-01-26 08:31:33 -08:00
|
|
|
|
d3d12_apply_resource_states(ctx, false);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
|
|
|
|
|
ctx->current_predication = query->predicate;
|
2022-01-10 08:56:58 -08:00
|
|
|
|
ctx->predication_condition = condition;
|
|
|
|
|
|
d3d12_enable_predication(ctx);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
d3d12_enable_predication(struct d3d12_context *ctx)
|
|
|
|
|
|
{
|
2019-05-26 10:43:12 +02:00
|
|
|
|
/* documentation of ID3D12GraphicsCommandList::SetPredication method:
|
2022-01-10 08:56:58 -08:00
|
|
|
|
* "resource manipulation commands are _not_ actually performed
|
|
|
|
|
|
* if the resulting predicate data of the predicate is equal to
|
|
|
|
|
|
* the operation specified."
|
|
|
|
|
|
*/
|
|
|
|
|
|
ctx->cmdlist->SetPredication(d3d12_resource_resource(ctx->current_predication), 0,
|
|
|
|
|
|
ctx->predication_condition ? D3D12_PREDICATION_OP_NOT_EQUAL_ZERO :
|
2019-05-26 10:43:12 +02:00
|
|
|
|
D3D12_PREDICATION_OP_EQUAL_ZERO);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
d3d12_context_query_init(struct pipe_context *pctx)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct d3d12_context *ctx = d3d12_context(pctx);
|
|
|
|
|
|
list_inithead(&ctx->active_queries);
|
|
|
|
|
|
|
2020-11-29 01:16:25 -05:00
|
|
|
|
u_suballocator_init(&ctx->query_allocator, &ctx->base, 4096, 0, PIPE_USAGE_STAGING,
|
|
|
|
|
|
0, true);
|
2019-05-26 10:43:12 +02:00
|
|
|
|
|
|
|
|
|
|
pctx->create_query = d3d12_create_query;
|
|
|
|
|
|
pctx->destroy_query = d3d12_destroy_query;
|
|
|
|
|
|
pctx->begin_query = d3d12_begin_query;
|
|
|
|
|
|
pctx->end_query = d3d12_end_query;
|
|
|
|
|
|
pctx->get_query_result = d3d12_get_query_result;
|
|
|
|
|
|
pctx->set_active_query_state = d3d12_set_active_query_state;
|
|
|
|
|
|
pctx->render_condition = d3d12_render_condition;
|
|
|
|
|
|
}
|