455 lines
14 KiB
C++
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);
|
|
}
|