/************************************************************************** * * 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); }