• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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