mesa/src/gallium/frontends/d3d10umd/Query.cpp

455 lines
14 KiB
C++

/**************************************************************************
*
* Copyright 2012-2021 VMware, Inc.
* All Rights Reserved.
*
* 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
**************************************************************************/
/*
* Query.cpp --
* Functions that manipulate query resources.
*/
#include "Query.h"
#include "State.h"
#include "Debug.h"
/*
* ----------------------------------------------------------------------
*
* CalcPrivateQuerySize --
*
* The CalcPrivateQuerySize function determines the size of the
* user-mode display driver's private region of memory (that is,
* the size of internal driver structures, not the size of the
* resource video memory) for a query.
*
* ----------------------------------------------------------------------
*/
SIZE_T APIENTRY
CalcPrivateQuerySize(D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATEQUERY *pCreateQuery) // IN
{
return sizeof(Query);
}
static uint
TranslateQueryType(D3D10DDI_QUERY query)
{
switch (query) {
case D3D10DDI_QUERY_EVENT:
return PIPE_QUERY_GPU_FINISHED;
case D3D10DDI_QUERY_OCCLUSION:
return PIPE_QUERY_OCCLUSION_COUNTER;
case D3D10DDI_QUERY_TIMESTAMP:
return PIPE_QUERY_TIMESTAMP;
case D3D10DDI_QUERY_TIMESTAMPDISJOINT:
return PIPE_QUERY_TIMESTAMP_DISJOINT;
case D3D10DDI_QUERY_PIPELINESTATS:
return PIPE_QUERY_PIPELINE_STATISTICS;
case D3D10DDI_QUERY_OCCLUSIONPREDICATE:
return PIPE_QUERY_OCCLUSION_PREDICATE;
case D3D10DDI_QUERY_STREAMOUTPUTSTATS:
return PIPE_QUERY_SO_STATISTICS;
case D3D10DDI_QUERY_STREAMOVERFLOWPREDICATE:
return PIPE_QUERY_SO_OVERFLOW_PREDICATE;
default:
LOG_UNSUPPORTED(TRUE);
return PIPE_QUERY_TYPES;
}
}
/*
* ----------------------------------------------------------------------
*
* CreateQuery --
*
* The CreateQuery function creates driver-side resources for a
* query that the Microsoft Direct3D runtime subsequently issues
* for processing.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateQuery(D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATEQUERY *pCreateQuery, // IN
D3D10DDI_HQUERY hQuery, // IN
D3D10DDI_HRTQUERY hRTQuery) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
Query *pQuery = CastQuery(hQuery);
memset(pQuery, 0, sizeof *pQuery);
pQuery->Type = pCreateQuery->Query;
pQuery->Flags = pCreateQuery->MiscFlags;
pQuery->pipe_type = TranslateQueryType(pCreateQuery->Query);
if (pQuery->pipe_type < PIPE_QUERY_TYPES) {
pQuery->handle = pipe->create_query(pipe, pQuery->pipe_type, 0);
}
}
/*
* ----------------------------------------------------------------------
*
* DestroyQuery --
*
* The DestroyQuery function releases resources for a query.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
DestroyQuery(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HQUERY hQuery) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
Query *pQuery = CastQuery(hQuery);
if (pQuery->handle) {
pipe->destroy_query(pipe, pQuery->handle);
}
}
/*
* ----------------------------------------------------------------------
*
* QueryBegin --
*
* The QueryBegin function marks the beginning of a sequence of
* graphics commands for a query and transitions the query to the
* "building" state.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
QueryBegin(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HQUERY hQuery) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
Query *pQuery = CastQuery(hQuery);
struct pipe_query *state = CastPipeQuery(hQuery);
if (state) {
assert(pQuery->pipe_type < PIPE_QUERY_TYPES);
pipe->begin_query(pipe, state);
}
}
/*
* ----------------------------------------------------------------------
*
* QueryEnd --
*
* The QueryEnd function marks the end of a sequence of graphics
* commands for a query and transitions the query to the
* "issued" state.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
QueryEnd(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HQUERY hQuery) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
Query *pQuery = CastQuery(hQuery);
struct pipe_query *state = pQuery->handle;
pQuery->SeqNo = ++pDevice->LastEmittedQuerySeqNo;
pQuery->GetDataCount = 0;
if (state) {
pipe->end_query(pipe, state);
}
}
/*
* ----------------------------------------------------------------------
*
* QueryGetData --
*
* The QueryGetData function polls for the state of a query operation.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
QueryGetData(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HQUERY hQuery, // IN
__out_bcount_full_opt (DataSize) void *pData, // OUT
UINT DataSize, // IN
UINT Flags) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
Query *pQuery = CastQuery(hQuery);
struct pipe_query *state = pQuery->handle;
/*
* Never return data for recently emitted queries immediately, to make
* wgfasync happy.
*/
if (DataSize == 0 &&
(pQuery->SeqNo - pDevice->LastFinishedQuerySeqNo) > 0 &&
(pQuery->GetDataCount++) == 0) {
SetError(hDevice, DXGI_DDI_ERR_WASSTILLDRAWING);
return;
}
boolean wait = !!(Flags & D3D10_DDI_GET_DATA_DO_NOT_FLUSH);
union pipe_query_result result;
memset(&result, 0, sizeof result);
boolean ret;
if (state) {
ret = pipe->get_query_result(pipe, state, wait, &result);
} else {
LOG_UNSUPPORTED(TRUE);
ret = TRUE;
}
if (!ret) {
SetError(hDevice, DXGI_DDI_ERR_WASSTILLDRAWING);
return;
}
if (pData) {
switch (pQuery->Type) {
case D3D10DDI_QUERY_EVENT:
case D3D10DDI_QUERY_OCCLUSIONPREDICATE:
case D3D10DDI_QUERY_STREAMOVERFLOWPREDICATE:
*(BOOL *)pData = result.b;
break;
case D3D10DDI_QUERY_OCCLUSION:
case D3D10DDI_QUERY_TIMESTAMP:
*(UINT64 *)pData = result.u64;
break;
case D3D10DDI_QUERY_TIMESTAMPDISJOINT:
{
D3D10_DDI_QUERY_DATA_TIMESTAMP_DISJOINT *pResult =
(D3D10_DDI_QUERY_DATA_TIMESTAMP_DISJOINT *)pData;
pResult->Frequency = result.timestamp_disjoint.frequency;
pResult->Disjoint = result.timestamp_disjoint.disjoint;
}
break;
case D3D10DDI_QUERY_PIPELINESTATS:
{
D3D10_DDI_QUERY_DATA_PIPELINE_STATISTICS *pResult =
(D3D10_DDI_QUERY_DATA_PIPELINE_STATISTICS *)pData;
pResult->IAVertices = result.pipeline_statistics.ia_vertices;
pResult->IAPrimitives = result.pipeline_statistics.ia_primitives;
pResult->VSInvocations = result.pipeline_statistics.vs_invocations;
pResult->GSInvocations = result.pipeline_statistics.gs_invocations;
pResult->GSPrimitives = result.pipeline_statistics.gs_primitives;
pResult->CInvocations = result.pipeline_statistics.c_invocations;
pResult->CPrimitives = result.pipeline_statistics.c_primitives;
pResult->PSInvocations = result.pipeline_statistics.ps_invocations;
//pResult->HSInvocations = result.pipeline_statistics.hs_invocations;
//pResult->DSInvocations = result.pipeline_statistics.ds_invocations;
//pResult->CSInvocations = result.pipeline_statistics.cs_invocations;
}
break;
case D3D10DDI_QUERY_STREAMOUTPUTSTATS:
{
D3D10_DDI_QUERY_DATA_SO_STATISTICS *pResult =
(D3D10_DDI_QUERY_DATA_SO_STATISTICS *)pData;
pResult->NumPrimitivesWritten = result.so_statistics.num_primitives_written;
pResult->PrimitivesStorageNeeded = result.so_statistics.primitives_storage_needed;
}
break;
default:
assert(0);
break;
}
}
/*
* Keep track of the last finished query, as wgfasync checks that queries
* are completed in order.
*/
if ((pQuery->SeqNo - pDevice->LastFinishedQuerySeqNo) > 0) {
pDevice->LastFinishedQuerySeqNo = pQuery->SeqNo;
}
pQuery->GetDataCount = 0x80000000;
}
/*
* ----------------------------------------------------------------------
*
* SetPredication --
*
* The SetPredication function specifies whether rendering and
* resource-manipulation commands that follow are actually performed.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
SetPredication(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HQUERY hQuery, // IN
BOOL PredicateValue) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
Query *pQuery = CastQuery(hQuery);
struct pipe_query *state = CastPipeQuery(hQuery);
enum pipe_render_cond_flag wait;
wait = (pQuery && pQuery->Flags & D3D10DDI_QUERY_MISCFLAG_PREDICATEHINT) ?
PIPE_RENDER_COND_NO_WAIT : PIPE_RENDER_COND_WAIT;
pipe->render_condition(pipe, state, PredicateValue, wait);
pDevice->pPredicate = pQuery;
pDevice->PredicateValue = PredicateValue;
}
/*
* ----------------------------------------------------------------------
*
* CheckPredicate --
*
* Check predicate value and whether to draw or not.
*
* ----------------------------------------------------------------------
*/
BOOL
CheckPredicate(Device *pDevice)
{
Query *pQuery = pDevice->pPredicate;
if (!pQuery) {
return TRUE;
}
assert(pQuery->Type == D3D10DDI_QUERY_OCCLUSIONPREDICATE ||
pQuery->Type == D3D10DDI_QUERY_STREAMOVERFLOWPREDICATE);
struct pipe_context *pipe = pDevice->pipe;
struct pipe_query *query = pQuery->handle;
assert(query);
union pipe_query_result result;
memset(&result, 0, sizeof result);
boolean ret;
ret = pipe->get_query_result(pipe, query, TRUE, &result);
assert(ret == TRUE);
if (!ret) {
return TRUE;
}
if (!!result.b == !!pDevice->PredicateValue) {
return FALSE;
}
return TRUE;
}
/*
* ----------------------------------------------------------------------
*
* CheckCounterInfo --
*
* The CheckCounterInfo function determines global information that
* is related to manipulating counters.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CheckCounterInfo(D3D10DDI_HDEVICE hDevice, // IN
__out D3D10DDI_COUNTER_INFO *pCounterInfo) // OUT
{
//LOG_ENTRYPOINT();
pCounterInfo->LastDeviceDependentCounter = (D3D10DDI_QUERY)0;
pCounterInfo->NumSimultaneousCounters = 0;
pCounterInfo->NumDetectableParallelUnits = 0;
}
/*
* ----------------------------------------------------------------------
*
* CheckCounter --
*
* The CheckCounter function retrieves information that
* describes a counter.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CheckCounter(
D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_QUERY Query, // IN
__out D3D10DDI_COUNTER_TYPE *pCounterType, // OUT
__out UINT *pActiveCounters, // OUT
__out_ecount_part_z_opt (*pNameLength, *pNameLength) LPSTR pName, // OUT
__inout_opt UINT *pNameLength, // OUT
__out_ecount_part_z_opt (*pUnitsLength, *pUnitsLength) LPSTR pUnits, // OUT
__inout_opt UINT *pUnitsLength, // OUT
__out_ecount_part_z_opt (*pDescriptionLength, *pDescriptionLength) LPSTR pDescription, // OUT
__inout_opt UINT* pDescriptionLength) // OUT
{
LOG_ENTRYPOINT();
SetError(hDevice, DXGI_DDI_ERR_UNSUPPORTED);
}