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
53 SIZE_T APIENTRY
CalcPrivateQuerySize(D3D10DDI_HDEVICE hDevice,__in const D3D10DDIARG_CREATEQUERY * pCreateQuery)54 CalcPrivateQuerySize(D3D10DDI_HDEVICE hDevice, // IN
55 __in const D3D10DDIARG_CREATEQUERY *pCreateQuery) // IN
56 {
57 return sizeof(Query);
58 }
59
60
61 static uint
TranslateQueryType(D3D10DDI_QUERY query)62 TranslateQueryType(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
100 void APIENTRY
CreateQuery(D3D10DDI_HDEVICE hDevice,__in const D3D10DDIARG_CREATEQUERY * pCreateQuery,D3D10DDI_HQUERY hQuery,D3D10DDI_HRTQUERY hRTQuery)101 CreateQuery(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
134 void APIENTRY
DestroyQuery(D3D10DDI_HDEVICE hDevice,D3D10DDI_HQUERY hQuery)135 DestroyQuery(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
161 void APIENTRY
QueryBegin(D3D10DDI_HDEVICE hDevice,D3D10DDI_HQUERY hQuery)162 QueryBegin(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
192 void APIENTRY
QueryEnd(D3D10DDI_HDEVICE hDevice,D3D10DDI_HQUERY hQuery)193 QueryEnd(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
222 void APIENTRY
QueryGetData(D3D10DDI_HDEVICE hDevice,D3D10DDI_HQUERY hQuery,__out_bcount_full_opt (DataSize)void * pData,UINT DataSize,UINT Flags)223 QueryGetData(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
338 void APIENTRY
SetPredication(D3D10DDI_HDEVICE hDevice,D3D10DDI_HQUERY hQuery,BOOL PredicateValue)339 SetPredication(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
371 BOOL
CheckPredicate(Device * pDevice)372 CheckPredicate(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
415 void APIENTRY
CheckCounterInfo(D3D10DDI_HDEVICE hDevice,__out D3D10DDI_COUNTER_INFO * pCounterInfo)416 CheckCounterInfo(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
438 void APIENTRY
CheckCounter(D3D10DDI_HDEVICE hDevice,D3D10DDI_QUERY Query,__out D3D10DDI_COUNTER_TYPE * pCounterType,__out UINT * pActiveCounters,__out_ecount_part_z_opt (* pNameLength,* pNameLength)LPSTR pName,__inout_opt UINT * pNameLength,__out_ecount_part_z_opt (* pUnitsLength,* pUnitsLength)LPSTR pUnits,__inout_opt UINT * pUnitsLength,__out_ecount_part_z_opt (* pDescriptionLength,* pDescriptionLength)LPSTR pDescription,__inout_opt UINT * pDescriptionLength)439 CheckCounter(
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