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