0cb3d2eac8271266e6604b9c0ebc828f6556a149
[mesa.git] / src / gallium / state_trackers / nine / query9.c
1 /*
2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
3 *
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:
10 *
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
13 * Software.
14 *
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. */
22
23 #include "device9.h"
24 #include "query9.h"
25 #include "nine_helpers.h"
26 #include "pipe/p_context.h"
27 #include "util/u_math.h"
28 #include "nine_dump.h"
29
30 #define DBG_CHANNEL DBG_QUERY
31
32 #define QUERY_TYPE_MAP_CASE(a, b) case D3DQUERYTYPE_##a: return PIPE_QUERY_##b
33 static inline unsigned
34 d3dquerytype_to_pipe_query(D3DQUERYTYPE type)
35 {
36 switch (type) {
37 QUERY_TYPE_MAP_CASE(EVENT, GPU_FINISHED);
38 QUERY_TYPE_MAP_CASE(OCCLUSION, OCCLUSION_COUNTER);
39 QUERY_TYPE_MAP_CASE(TIMESTAMP, TIMESTAMP);
40 QUERY_TYPE_MAP_CASE(TIMESTAMPDISJOINT, TIMESTAMP_DISJOINT);
41 QUERY_TYPE_MAP_CASE(TIMESTAMPFREQ, TIMESTAMP_DISJOINT);
42 QUERY_TYPE_MAP_CASE(VERTEXSTATS, PIPELINE_STATISTICS);
43 case D3DQUERYTYPE_VCACHE:
44 case D3DQUERYTYPE_RESOURCEMANAGER:
45 case D3DQUERYTYPE_PIPELINETIMINGS:
46 case D3DQUERYTYPE_INTERFACETIMINGS:
47 case D3DQUERYTYPE_VERTEXTIMINGS:
48 case D3DQUERYTYPE_PIXELTIMINGS:
49 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
50 case D3DQUERYTYPE_CACHEUTILIZATION:
51 return PIPE_QUERY_TYPES;
52 default:
53 return ~0;
54 }
55 }
56
57 #define GET_DATA_SIZE_CASE2(a, b) case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_##b)
58 #define GET_DATA_SIZE_CASET(a, b) case D3DQUERYTYPE_##a: return sizeof(b)
59 static INLINE DWORD
60 nine_query_result_size(D3DQUERYTYPE type)
61 {
62 switch (type) {
63 GET_DATA_SIZE_CASE2(VERTEXSTATS, D3DVERTEXSTATS);
64 GET_DATA_SIZE_CASET(EVENT, BOOL);
65 GET_DATA_SIZE_CASET(OCCLUSION, DWORD);
66 GET_DATA_SIZE_CASET(TIMESTAMP, UINT64);
67 GET_DATA_SIZE_CASET(TIMESTAMPDISJOINT, BOOL);
68 GET_DATA_SIZE_CASET(TIMESTAMPFREQ, UINT64);
69 default:
70 assert(0);
71 return 0;
72 }
73 }
74
75 HRESULT
76 nine_is_query_supported(D3DQUERYTYPE type)
77 {
78 const unsigned ptype = d3dquerytype_to_pipe_query(type);
79
80 user_assert(ptype != ~0, D3DERR_INVALIDCALL);
81
82 if (ptype == PIPE_QUERY_TYPES) {
83 DBG("Query type %u (%s) not supported.\n",
84 type, nine_D3DQUERYTYPE_to_str(type));
85 return D3DERR_NOTAVAILABLE;
86 }
87 return D3D_OK;
88 }
89
90 HRESULT
91 NineQuery9_ctor( struct NineQuery9 *This,
92 struct NineUnknownParams *pParams,
93 D3DQUERYTYPE Type )
94 {
95 struct pipe_context *pipe = pParams->device->pipe;
96 const unsigned ptype = d3dquerytype_to_pipe_query(Type);
97 HRESULT hr;
98
99 DBG("This=%p pParams=%p Type=%d\n", This, pParams, Type);
100
101 hr = NineUnknown_ctor(&This->base, pParams);
102 if (FAILED(hr))
103 return hr;
104
105 This->state = NINE_QUERY_STATE_FRESH;
106 This->type = Type;
107
108 user_assert(ptype != ~0, D3DERR_INVALIDCALL);
109
110 if (ptype < PIPE_QUERY_TYPES) {
111 This->pq = pipe->create_query(pipe, ptype, 0);
112 if (!This->pq)
113 return E_OUTOFMEMORY;
114 } else {
115 assert(0); /* we have checked this case before */
116 }
117
118 This->instant =
119 Type == D3DQUERYTYPE_EVENT ||
120 Type == D3DQUERYTYPE_RESOURCEMANAGER ||
121 Type == D3DQUERYTYPE_TIMESTAMP ||
122 Type == D3DQUERYTYPE_TIMESTAMPFREQ ||
123 Type == D3DQUERYTYPE_VCACHE ||
124 Type == D3DQUERYTYPE_VERTEXSTATS;
125
126 This->result_size = nine_query_result_size(Type);
127
128 return D3D_OK;
129 }
130
131 void
132 NineQuery9_dtor( struct NineQuery9 *This )
133 {
134 struct pipe_context *pipe = This->base.device->pipe;
135
136 if (This->pq) {
137 if (This->state == NINE_QUERY_STATE_RUNNING)
138 pipe->end_query(pipe, This->pq);
139 pipe->destroy_query(pipe, This->pq);
140 }
141
142 NineUnknown_dtor(&This->base);
143 }
144
145 D3DQUERYTYPE WINAPI
146 NineQuery9_GetType( struct NineQuery9 *This )
147 {
148 return This->type;
149 }
150
151 DWORD WINAPI
152 NineQuery9_GetDataSize( struct NineQuery9 *This )
153 {
154 return This->result_size;
155 }
156
157 HRESULT WINAPI
158 NineQuery9_Issue( struct NineQuery9 *This,
159 DWORD dwIssueFlags )
160 {
161 struct pipe_context *pipe = This->base.device->pipe;
162
163 DBG("This=%p dwIssueFlags=%d\n", This, dwIssueFlags);
164
165 user_assert((dwIssueFlags == D3DISSUE_BEGIN && !This->instant) ||
166 (dwIssueFlags == 0) ||
167 (dwIssueFlags == D3DISSUE_END), D3DERR_INVALIDCALL);
168
169 if (dwIssueFlags == D3DISSUE_BEGIN) {
170 if (This->state == NINE_QUERY_STATE_RUNNING) {
171 pipe->end_query(pipe, This->pq);
172 }
173 pipe->begin_query(pipe, This->pq);
174 This->state = NINE_QUERY_STATE_RUNNING;
175 } else {
176 if (This->state == NINE_QUERY_STATE_RUNNING) {
177 pipe->end_query(pipe, This->pq);
178 This->state = NINE_QUERY_STATE_ENDED;
179 }
180 }
181 return D3D_OK;
182 }
183
184 union nine_query_result
185 {
186 D3DDEVINFO_D3DVERTEXSTATS vertexstats;
187 DWORD dw;
188 BOOL b;
189 UINT64 u64;
190 };
191
192 HRESULT WINAPI
193 NineQuery9_GetData( struct NineQuery9 *This,
194 void *pData,
195 DWORD dwSize,
196 DWORD dwGetDataFlags )
197 {
198 struct pipe_context *pipe = This->base.device->pipe;
199 boolean ok;
200 unsigned i;
201 union pipe_query_result presult;
202 union nine_query_result nresult;
203
204 DBG("This=%p pData=%p dwSize=%d dwGetDataFlags=%d\n",
205 This, pData, dwSize, dwGetDataFlags);
206
207 user_assert(This->state != NINE_QUERY_STATE_RUNNING, D3DERR_INVALIDCALL);
208 user_assert(dwSize == 0 || pData, D3DERR_INVALIDCALL);
209 user_assert(dwGetDataFlags == 0 ||
210 dwGetDataFlags == D3DGETDATA_FLUSH, D3DERR_INVALIDCALL);
211
212 if (This->state == NINE_QUERY_STATE_FRESH)
213 return S_OK;
214
215 ok = pipe->get_query_result(pipe, This->pq, FALSE, &presult);
216 if (!ok) {
217 if (dwGetDataFlags) {
218 if (This->state != NINE_QUERY_STATE_FLUSHED)
219 pipe->flush(pipe, NULL, 0);
220 This->state = NINE_QUERY_STATE_FLUSHED;
221 }
222 return S_FALSE;
223 }
224
225 if (!dwSize)
226 return S_OK;
227
228 switch (This->type) {
229 case D3DQUERYTYPE_EVENT:
230 nresult.b = presult.b;
231 break;
232 case D3DQUERYTYPE_OCCLUSION:
233 nresult.dw = presult.u64;
234 break;
235 case D3DQUERYTYPE_TIMESTAMP:
236 nresult.u64 = presult.u64;
237 break;
238 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
239 nresult.b = presult.timestamp_disjoint.disjoint;
240 break;
241 case D3DQUERYTYPE_TIMESTAMPFREQ:
242 nresult.u64 = presult.timestamp_disjoint.frequency;
243 break;
244 case D3DQUERYTYPE_VERTEXSTATS:
245 nresult.vertexstats.NumRenderedTriangles =
246 presult.pipeline_statistics.c_invocations;
247 nresult.vertexstats.NumExtraClippingTriangles =
248 presult.pipeline_statistics.c_primitives;
249 break;
250 default:
251 assert(0);
252 break;
253 }
254 memcpy(pData, &nresult, MIN2(sizeof(nresult), dwSize));
255
256 return S_OK;
257 }
258
259 IDirect3DQuery9Vtbl NineQuery9_vtable = {
260 (void *)NineUnknown_QueryInterface,
261 (void *)NineUnknown_AddRef,
262 (void *)NineUnknown_Release,
263 (void *)NineUnknown_GetDevice, /* actually part of Query9 iface */
264 (void *)NineQuery9_GetType,
265 (void *)NineQuery9_GetDataSize,
266 (void *)NineQuery9_Issue,
267 (void *)NineQuery9_GetData
268 };
269
270 static const GUID *NineQuery9_IIDs[] = {
271 &IID_IDirect3DQuery9,
272 &IID_IUnknown,
273 NULL
274 };
275
276 HRESULT
277 NineQuery9_new( struct NineDevice9 *pDevice,
278 struct NineQuery9 **ppOut,
279 D3DQUERYTYPE Type )
280 {
281 NINE_DEVICE_CHILD_NEW(Query9, ppOut, pDevice, Type);
282 }