2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
25 #include "nine_helpers.h"
26 #include "pipe/p_screen.h"
27 #include "pipe/p_context.h"
28 #include "util/u_math.h"
29 #include "nine_dump.h"
31 #define DBG_CHANNEL DBG_QUERY
33 static inline unsigned
34 d3dquerytype_to_pipe_query(struct pipe_screen
*screen
, D3DQUERYTYPE type
)
37 case D3DQUERYTYPE_EVENT
:
38 return PIPE_QUERY_GPU_FINISHED
;
39 case D3DQUERYTYPE_OCCLUSION
:
40 return screen
->get_param(screen
, PIPE_CAP_OCCLUSION_QUERY
) ?
41 PIPE_QUERY_OCCLUSION_COUNTER
: PIPE_QUERY_TYPES
;
42 case D3DQUERYTYPE_TIMESTAMP
:
43 return screen
->get_param(screen
, PIPE_CAP_QUERY_TIMESTAMP
) ?
44 PIPE_QUERY_TIMESTAMP
: PIPE_QUERY_TYPES
;
45 case D3DQUERYTYPE_TIMESTAMPDISJOINT
:
46 case D3DQUERYTYPE_TIMESTAMPFREQ
:
47 return screen
->get_param(screen
, PIPE_CAP_QUERY_TIMESTAMP
) ?
48 PIPE_QUERY_TIMESTAMP_DISJOINT
: PIPE_QUERY_TYPES
;
49 case D3DQUERYTYPE_VERTEXSTATS
:
50 return screen
->get_param(screen
,
51 PIPE_CAP_QUERY_PIPELINE_STATISTICS
) ?
52 PIPE_QUERY_PIPELINE_STATISTICS
: PIPE_QUERY_TYPES
;
54 return PIPE_QUERY_TYPES
; /* Query not supported */
58 #define GET_DATA_SIZE_CASE2(a, b) case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_##b)
59 #define GET_DATA_SIZE_CASET(a, b) case D3DQUERYTYPE_##a: return sizeof(b)
61 nine_query_result_size(D3DQUERYTYPE type
)
64 GET_DATA_SIZE_CASE2(VERTEXSTATS
, D3DVERTEXSTATS
);
65 GET_DATA_SIZE_CASET(EVENT
, BOOL
);
66 GET_DATA_SIZE_CASET(OCCLUSION
, DWORD
);
67 GET_DATA_SIZE_CASET(TIMESTAMP
, UINT64
);
68 GET_DATA_SIZE_CASET(TIMESTAMPDISJOINT
, BOOL
);
69 GET_DATA_SIZE_CASET(TIMESTAMPFREQ
, UINT64
);
77 nine_is_query_supported(struct pipe_screen
*screen
, D3DQUERYTYPE type
)
79 const unsigned ptype
= d3dquerytype_to_pipe_query(screen
, type
);
81 user_assert(ptype
!= ~0, D3DERR_INVALIDCALL
);
83 if (ptype
== PIPE_QUERY_TYPES
) {
84 DBG("Query type %u (%s) not supported.\n",
85 type
, nine_D3DQUERYTYPE_to_str(type
));
86 return D3DERR_NOTAVAILABLE
;
92 NineQuery9_ctor( struct NineQuery9
*This
,
93 struct NineUnknownParams
*pParams
,
96 struct pipe_context
*pipe
= pParams
->device
->pipe
;
97 const unsigned ptype
= d3dquerytype_to_pipe_query(pParams
->device
->screen
, Type
);
100 DBG("This=%p pParams=%p Type=%d\n", This
, pParams
, Type
);
102 hr
= NineUnknown_ctor(&This
->base
, pParams
);
106 This
->state
= NINE_QUERY_STATE_FRESH
;
109 user_assert(ptype
!= ~0, D3DERR_INVALIDCALL
);
111 if (ptype
< PIPE_QUERY_TYPES
) {
112 This
->pq
= pipe
->create_query(pipe
, ptype
, 0);
114 return E_OUTOFMEMORY
;
116 assert(0); /* we have checked this case before */
120 Type
== D3DQUERYTYPE_EVENT
||
121 Type
== D3DQUERYTYPE_RESOURCEMANAGER
||
122 Type
== D3DQUERYTYPE_TIMESTAMP
||
123 Type
== D3DQUERYTYPE_TIMESTAMPFREQ
||
124 Type
== D3DQUERYTYPE_VCACHE
||
125 Type
== D3DQUERYTYPE_VERTEXSTATS
;
127 This
->result_size
= nine_query_result_size(Type
);
133 NineQuery9_dtor( struct NineQuery9
*This
)
135 struct pipe_context
*pipe
= This
->base
.device
->pipe
;
138 if (This
->state
== NINE_QUERY_STATE_RUNNING
)
139 pipe
->end_query(pipe
, This
->pq
);
140 pipe
->destroy_query(pipe
, This
->pq
);
143 NineUnknown_dtor(&This
->base
);
147 NineQuery9_GetType( struct NineQuery9
*This
)
153 NineQuery9_GetDataSize( struct NineQuery9
*This
)
155 return This
->result_size
;
159 NineQuery9_Issue( struct NineQuery9
*This
,
162 struct pipe_context
*pipe
= This
->base
.device
->pipe
;
164 DBG("This=%p dwIssueFlags=%d\n", This
, dwIssueFlags
);
166 user_assert((dwIssueFlags
== D3DISSUE_BEGIN
&& !This
->instant
) ||
167 (dwIssueFlags
== 0) ||
168 (dwIssueFlags
== D3DISSUE_END
), D3DERR_INVALIDCALL
);
170 if (dwIssueFlags
== D3DISSUE_BEGIN
) {
171 if (This
->state
== NINE_QUERY_STATE_RUNNING
) {
172 pipe
->end_query(pipe
, This
->pq
);
174 pipe
->begin_query(pipe
, This
->pq
);
175 This
->state
= NINE_QUERY_STATE_RUNNING
;
177 if (This
->state
!= NINE_QUERY_STATE_RUNNING
&&
178 This
->type
!= D3DQUERYTYPE_EVENT
&&
179 This
->type
!= D3DQUERYTYPE_TIMESTAMP
)
180 pipe
->begin_query(pipe
, This
->pq
);
181 pipe
->end_query(pipe
, This
->pq
);
182 This
->state
= NINE_QUERY_STATE_ENDED
;
187 union nine_query_result
189 D3DDEVINFO_D3DVERTEXSTATS vertexstats
;
196 NineQuery9_GetData( struct NineQuery9
*This
,
199 DWORD dwGetDataFlags
)
201 struct pipe_context
*pipe
= This
->base
.device
->pipe
;
204 union pipe_query_result presult
;
205 union nine_query_result nresult
;
207 DBG("This=%p pData=%p dwSize=%d dwGetDataFlags=%d\n",
208 This
, pData
, dwSize
, dwGetDataFlags
);
210 /* according to spec we should return D3DERR_INVALIDCALL here, but
211 * wine returns S_FALSE because it is apparently the behaviour
213 user_assert(This
->state
!= NINE_QUERY_STATE_RUNNING
, S_FALSE
);
214 user_assert(dwSize
== 0 || pData
, D3DERR_INVALIDCALL
);
215 user_assert(dwGetDataFlags
== 0 ||
216 dwGetDataFlags
== D3DGETDATA_FLUSH
, D3DERR_INVALIDCALL
);
218 if (This
->state
== NINE_QUERY_STATE_FRESH
)
221 /* Note: We ignore dwGetDataFlags, because get_query_result will
222 * flush automatically if needed */
224 ok
= pipe
->get_query_result(pipe
, This
->pq
, FALSE
, &presult
);
226 if (!ok
) return S_FALSE
;
231 switch (This
->type
) {
232 case D3DQUERYTYPE_EVENT
:
233 nresult
.b
= presult
.b
;
235 case D3DQUERYTYPE_OCCLUSION
:
236 nresult
.dw
= presult
.u64
;
238 case D3DQUERYTYPE_TIMESTAMP
:
239 nresult
.u64
= presult
.u64
;
241 case D3DQUERYTYPE_TIMESTAMPDISJOINT
:
242 nresult
.b
= presult
.timestamp_disjoint
.disjoint
;
244 case D3DQUERYTYPE_TIMESTAMPFREQ
:
245 nresult
.u64
= presult
.timestamp_disjoint
.frequency
;
247 case D3DQUERYTYPE_VERTEXSTATS
:
248 nresult
.vertexstats
.NumRenderedTriangles
=
249 presult
.pipeline_statistics
.c_invocations
;
250 nresult
.vertexstats
.NumExtraClippingTriangles
=
251 presult
.pipeline_statistics
.c_primitives
;
257 memcpy(pData
, &nresult
, MIN2(sizeof(nresult
), dwSize
));
262 IDirect3DQuery9Vtbl NineQuery9_vtable
= {
263 (void *)NineUnknown_QueryInterface
,
264 (void *)NineUnknown_AddRef
,
265 (void *)NineUnknown_Release
,
266 (void *)NineUnknown_GetDevice
, /* actually part of Query9 iface */
267 (void *)NineQuery9_GetType
,
268 (void *)NineQuery9_GetDataSize
,
269 (void *)NineQuery9_Issue
,
270 (void *)NineQuery9_GetData
273 static const GUID
*NineQuery9_IIDs
[] = {
274 &IID_IDirect3DQuery9
,
280 NineQuery9_new( struct NineDevice9
*pDevice
,
281 struct NineQuery9
**ppOut
,
284 NINE_DEVICE_CHILD_NEW(Query9
, ppOut
, pDevice
, Type
);