1/************************************************************************** 2 * 3 * Copyright 2012-2021 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 * USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * The above copyright notice and this permission notice (including the 23 * next paragraph) shall be included in all copies or substantial portions 24 * of the Software. 25 * 26 **************************************************************************/ 27 28/* 29 * Query.cpp -- 30 * Functions that manipulate query resources. 31 */ 32 33 34#include "Query.h" 35#include "State.h" 36 37#include "Debug.h" 38 39 40/* 41 * ---------------------------------------------------------------------- 42 * 43 * CalcPrivateQuerySize -- 44 * 45 * The CalcPrivateQuerySize function determines the size of the 46 * user-mode display driver's private region of memory (that is, 47 * the size of internal driver structures, not the size of the 48 * resource video memory) for a query. 49 * 50 * ---------------------------------------------------------------------- 51 */ 52 53SIZE_T APIENTRY 54CalcPrivateQuerySize(D3D10DDI_HDEVICE hDevice, // IN 55 __in const D3D10DDIARG_CREATEQUERY *pCreateQuery) // IN 56{ 57 return sizeof(Query); 58} 59 60 61static uint 62TranslateQueryType(D3D10DDI_QUERY query) 63{ 64 switch (query) { 65 case D3D10DDI_QUERY_EVENT: 66 return PIPE_QUERY_GPU_FINISHED; 67 case D3D10DDI_QUERY_OCCLUSION: 68 return PIPE_QUERY_OCCLUSION_COUNTER; 69 case D3D10DDI_QUERY_TIMESTAMP: 70 return PIPE_QUERY_TIMESTAMP; 71 case D3D10DDI_QUERY_TIMESTAMPDISJOINT: 72 return PIPE_QUERY_TIMESTAMP_DISJOINT; 73 case D3D10DDI_QUERY_PIPELINESTATS: 74 return PIPE_QUERY_PIPELINE_STATISTICS; 75 case D3D10DDI_QUERY_OCCLUSIONPREDICATE: 76 return PIPE_QUERY_OCCLUSION_PREDICATE; 77 case D3D10DDI_QUERY_STREAMOUTPUTSTATS: 78 return PIPE_QUERY_SO_STATISTICS; 79 case D3D10DDI_QUERY_STREAMOVERFLOWPREDICATE: 80 return PIPE_QUERY_SO_OVERFLOW_PREDICATE; 81 default: 82 LOG_UNSUPPORTED(TRUE); 83 return PIPE_QUERY_TYPES; 84 } 85} 86 87 88/* 89 * ---------------------------------------------------------------------- 90 * 91 * CreateQuery -- 92 * 93 * The CreateQuery function creates driver-side resources for a 94 * query that the Microsoft Direct3D runtime subsequently issues 95 * for processing. 96 * 97 * ---------------------------------------------------------------------- 98 */ 99 100void APIENTRY 101CreateQuery(D3D10DDI_HDEVICE hDevice, // IN 102 __in const D3D10DDIARG_CREATEQUERY *pCreateQuery, // IN 103 D3D10DDI_HQUERY hQuery, // IN 104 D3D10DDI_HRTQUERY hRTQuery) // IN 105{ 106 LOG_ENTRYPOINT(); 107 108 Device *pDevice = CastDevice(hDevice); 109 struct pipe_context *pipe = pDevice->pipe; 110 111 Query *pQuery = CastQuery(hQuery); 112 memset(pQuery, 0, sizeof *pQuery); 113 114 pQuery->Type = pCreateQuery->Query; 115 pQuery->Flags = pCreateQuery->MiscFlags; 116 117 pQuery->pipe_type = TranslateQueryType(pCreateQuery->Query); 118 if (pQuery->pipe_type < PIPE_QUERY_TYPES) { 119 pQuery->handle = pipe->create_query(pipe, pQuery->pipe_type, 0); 120 } 121} 122 123 124/* 125 * ---------------------------------------------------------------------- 126 * 127 * DestroyQuery -- 128 * 129 * The DestroyQuery function releases resources for a query. 130 * 131 * ---------------------------------------------------------------------- 132 */ 133 134void APIENTRY 135DestroyQuery(D3D10DDI_HDEVICE hDevice, // IN 136 D3D10DDI_HQUERY hQuery) // IN 137{ 138 LOG_ENTRYPOINT(); 139 140 struct pipe_context *pipe = CastPipeContext(hDevice); 141 Query *pQuery = CastQuery(hQuery); 142 143 if (pQuery->handle) { 144 pipe->destroy_query(pipe, pQuery->handle); 145 } 146} 147 148 149/* 150 * ---------------------------------------------------------------------- 151 * 152 * QueryBegin -- 153 * 154 * The QueryBegin function marks the beginning of a sequence of 155 * graphics commands for a query and transitions the query to the 156 * "building" state. 157 * 158 * ---------------------------------------------------------------------- 159 */ 160 161void APIENTRY 162QueryBegin(D3D10DDI_HDEVICE hDevice, // IN 163 D3D10DDI_HQUERY hQuery) // IN 164{ 165 LOG_ENTRYPOINT(); 166 167 Device *pDevice = CastDevice(hDevice); 168 struct pipe_context *pipe = pDevice->pipe; 169 170 Query *pQuery = CastQuery(hQuery); 171 struct pipe_query *state = CastPipeQuery(hQuery); 172 173 if (state) { 174 assert(pQuery->pipe_type < PIPE_QUERY_TYPES); 175 pipe->begin_query(pipe, state); 176 } 177} 178 179 180/* 181 * ---------------------------------------------------------------------- 182 * 183 * QueryEnd -- 184 * 185 * The QueryEnd function marks the end of a sequence of graphics 186 * commands for a query and transitions the query to the 187 * "issued" state. 188 * 189 * ---------------------------------------------------------------------- 190 */ 191 192void APIENTRY 193QueryEnd(D3D10DDI_HDEVICE hDevice, // IN 194 D3D10DDI_HQUERY hQuery) // IN 195{ 196 LOG_ENTRYPOINT(); 197 198 Device *pDevice = CastDevice(hDevice); 199 struct pipe_context *pipe = pDevice->pipe; 200 Query *pQuery = CastQuery(hQuery); 201 struct pipe_query *state = pQuery->handle; 202 203 pQuery->SeqNo = ++pDevice->LastEmittedQuerySeqNo; 204 pQuery->GetDataCount = 0; 205 206 if (state) { 207 pipe->end_query(pipe, state); 208 } 209} 210 211 212/* 213 * ---------------------------------------------------------------------- 214 * 215 * QueryGetData -- 216 * 217 * The QueryGetData function polls for the state of a query operation. 218 * 219 * ---------------------------------------------------------------------- 220 */ 221 222void APIENTRY 223QueryGetData(D3D10DDI_HDEVICE hDevice, // IN 224 D3D10DDI_HQUERY hQuery, // IN 225 __out_bcount_full_opt (DataSize) void *pData, // OUT 226 UINT DataSize, // IN 227 UINT Flags) // IN 228{ 229 LOG_ENTRYPOINT(); 230 231 Device *pDevice = CastDevice(hDevice); 232 struct pipe_context *pipe = pDevice->pipe; 233 Query *pQuery = CastQuery(hQuery); 234 struct pipe_query *state = pQuery->handle; 235 236 /* 237 * Never return data for recently emitted queries immediately, to make 238 * wgfasync happy. 239 */ 240 if (DataSize == 0 && 241 (pQuery->SeqNo - pDevice->LastFinishedQuerySeqNo) > 0 && 242 (pQuery->GetDataCount++) == 0) { 243 SetError(hDevice, DXGI_DDI_ERR_WASSTILLDRAWING); 244 return; 245 } 246 247 boolean wait = !!(Flags & D3D10_DDI_GET_DATA_DO_NOT_FLUSH); 248 union pipe_query_result result; 249 250 memset(&result, 0, sizeof result); 251 252 boolean ret; 253 254 if (state) { 255 ret = pipe->get_query_result(pipe, state, wait, &result); 256 } else { 257 LOG_UNSUPPORTED(TRUE); 258 ret = TRUE; 259 } 260 261 if (!ret) { 262 SetError(hDevice, DXGI_DDI_ERR_WASSTILLDRAWING); 263 return; 264 } 265 266 if (pData) { 267 switch (pQuery->Type) { 268 case D3D10DDI_QUERY_EVENT: 269 case D3D10DDI_QUERY_OCCLUSIONPREDICATE: 270 case D3D10DDI_QUERY_STREAMOVERFLOWPREDICATE: 271 *(BOOL *)pData = result.b; 272 break; 273 case D3D10DDI_QUERY_OCCLUSION: 274 case D3D10DDI_QUERY_TIMESTAMP: 275 *(UINT64 *)pData = result.u64; 276 break; 277 case D3D10DDI_QUERY_TIMESTAMPDISJOINT: 278 { 279 D3D10_DDI_QUERY_DATA_TIMESTAMP_DISJOINT *pResult = 280 (D3D10_DDI_QUERY_DATA_TIMESTAMP_DISJOINT *)pData; 281 pResult->Frequency = result.timestamp_disjoint.frequency; 282 pResult->Disjoint = result.timestamp_disjoint.disjoint; 283 } 284 break; 285 case D3D10DDI_QUERY_PIPELINESTATS: 286 { 287 D3D10_DDI_QUERY_DATA_PIPELINE_STATISTICS *pResult = 288 (D3D10_DDI_QUERY_DATA_PIPELINE_STATISTICS *)pData; 289 pResult->IAVertices = result.pipeline_statistics.ia_vertices; 290 pResult->IAPrimitives = result.pipeline_statistics.ia_primitives; 291 pResult->VSInvocations = result.pipeline_statistics.vs_invocations; 292 pResult->GSInvocations = result.pipeline_statistics.gs_invocations; 293 pResult->GSPrimitives = result.pipeline_statistics.gs_primitives; 294 pResult->CInvocations = result.pipeline_statistics.c_invocations; 295 pResult->CPrimitives = result.pipeline_statistics.c_primitives; 296 pResult->PSInvocations = result.pipeline_statistics.ps_invocations; 297 //pResult->HSInvocations = result.pipeline_statistics.hs_invocations; 298 //pResult->DSInvocations = result.pipeline_statistics.ds_invocations; 299 //pResult->CSInvocations = result.pipeline_statistics.cs_invocations; 300 } 301 break; 302 case D3D10DDI_QUERY_STREAMOUTPUTSTATS: 303 { 304 D3D10_DDI_QUERY_DATA_SO_STATISTICS *pResult = 305 (D3D10_DDI_QUERY_DATA_SO_STATISTICS *)pData; 306 pResult->NumPrimitivesWritten = result.so_statistics.num_primitives_written; 307 pResult->PrimitivesStorageNeeded = result.so_statistics.primitives_storage_needed; 308 } 309 break; 310 default: 311 assert(0); 312 break; 313 } 314 } 315 316 /* 317 * Keep track of the last finished query, as wgfasync checks that queries 318 * are completed in order. 319 */ 320 if ((pQuery->SeqNo - pDevice->LastFinishedQuerySeqNo) > 0) { 321 pDevice->LastFinishedQuerySeqNo = pQuery->SeqNo; 322 } 323 pQuery->GetDataCount = 0x80000000; 324} 325 326 327/* 328 * ---------------------------------------------------------------------- 329 * 330 * SetPredication -- 331 * 332 * The SetPredication function specifies whether rendering and 333 * resource-manipulation commands that follow are actually performed. 334 * 335 * ---------------------------------------------------------------------- 336 */ 337 338void APIENTRY 339SetPredication(D3D10DDI_HDEVICE hDevice, // IN 340 D3D10DDI_HQUERY hQuery, // IN 341 BOOL PredicateValue) // IN 342{ 343 LOG_ENTRYPOINT(); 344 345 Device *pDevice = CastDevice(hDevice); 346 struct pipe_context *pipe = pDevice->pipe; 347 Query *pQuery = CastQuery(hQuery); 348 struct pipe_query *state = CastPipeQuery(hQuery); 349 enum pipe_render_cond_flag wait; 350 351 wait = (pQuery && pQuery->Flags & D3D10DDI_QUERY_MISCFLAG_PREDICATEHINT) ? 352 PIPE_RENDER_COND_NO_WAIT : PIPE_RENDER_COND_WAIT; 353 354 pipe->render_condition(pipe, state, PredicateValue, wait); 355 356 pDevice->pPredicate = pQuery; 357 pDevice->PredicateValue = PredicateValue; 358} 359 360 361/* 362 * ---------------------------------------------------------------------- 363 * 364 * CheckPredicate -- 365 * 366 * Check predicate value and whether to draw or not. 367 * 368 * ---------------------------------------------------------------------- 369 */ 370 371BOOL 372CheckPredicate(Device *pDevice) 373{ 374 Query *pQuery = pDevice->pPredicate; 375 if (!pQuery) { 376 return TRUE; 377 } 378 379 assert(pQuery->Type == D3D10DDI_QUERY_OCCLUSIONPREDICATE || 380 pQuery->Type == D3D10DDI_QUERY_STREAMOVERFLOWPREDICATE); 381 382 struct pipe_context *pipe = pDevice->pipe; 383 struct pipe_query *query = pQuery->handle; 384 assert(query); 385 386 union pipe_query_result result; 387 memset(&result, 0, sizeof result); 388 389 boolean ret; 390 ret = pipe->get_query_result(pipe, query, TRUE, &result); 391 assert(ret == TRUE); 392 if (!ret) { 393 return TRUE; 394 } 395 396 if (!!result.b == !!pDevice->PredicateValue) { 397 return FALSE; 398 } 399 400 return TRUE; 401} 402 403 404/* 405 * ---------------------------------------------------------------------- 406 * 407 * CheckCounterInfo -- 408 * 409 * The CheckCounterInfo function determines global information that 410 * is related to manipulating counters. 411 * 412 * ---------------------------------------------------------------------- 413 */ 414 415void APIENTRY 416CheckCounterInfo(D3D10DDI_HDEVICE hDevice, // IN 417 __out D3D10DDI_COUNTER_INFO *pCounterInfo) // OUT 418{ 419 //LOG_ENTRYPOINT(); 420 421 pCounterInfo->LastDeviceDependentCounter = (D3D10DDI_QUERY)0; 422 pCounterInfo->NumSimultaneousCounters = 0; 423 pCounterInfo->NumDetectableParallelUnits = 0; 424} 425 426 427/* 428 * ---------------------------------------------------------------------- 429 * 430 * CheckCounter -- 431 * 432 * The CheckCounter function retrieves information that 433 * describes a counter. 434 * 435 * ---------------------------------------------------------------------- 436 */ 437 438void APIENTRY 439CheckCounter( 440 D3D10DDI_HDEVICE hDevice, // IN 441 D3D10DDI_QUERY Query, // IN 442 __out D3D10DDI_COUNTER_TYPE *pCounterType, // OUT 443 __out UINT *pActiveCounters, // OUT 444 __out_ecount_part_z_opt (*pNameLength, *pNameLength) LPSTR pName, // OUT 445 __inout_opt UINT *pNameLength, // OUT 446 __out_ecount_part_z_opt (*pUnitsLength, *pUnitsLength) LPSTR pUnits, // OUT 447 __inout_opt UINT *pUnitsLength, // OUT 448 __out_ecount_part_z_opt (*pDescriptionLength, *pDescriptionLength) LPSTR pDescription, // OUT 449 __inout_opt UINT* pDescriptionLength) // OUT 450{ 451 LOG_ENTRYPOINT(); 452 453 SetError(hDevice, DXGI_DDI_ERR_UNSUPPORTED); 454} 455