Merge PR #283 "[USBPORT] Transaction Translator (TT) support bringup"
[reactos.git] / dll / directx / wine / wined3d / query.c
1 /*
2 * Copyright 2005 Oliver Stieber
3 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
4 * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wined3d_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27
28 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
29 {
30 if (gl_info->supported[ARB_TIMER_QUERY])
31 {
32 GLuint64 result;
33 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
34 return result;
35 }
36 else
37 {
38 GLuint result;
39 GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
40 return result;
41 }
42 }
43
44 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
45 enum wined3d_query_type type, const void *data, DWORD data_size,
46 const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops)
47 {
48 query->ref = 1;
49 query->parent = parent;
50 query->parent_ops = parent_ops;
51 query->device = device;
52 query->state = QUERY_CREATED;
53 query->type = type;
54 query->data = data;
55 query->data_size = data_size;
56 query->query_ops = query_ops;
57 list_init(&query->poll_list_entry);
58 }
59
60 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
61 {
62 return CONTAINING_RECORD(query, struct wined3d_event_query, query);
63 }
64
65 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
66 {
67 return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
68 }
69
70 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
71 {
72 return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
73 }
74
75 static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
76 {
77 return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
78 }
79
80 static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query(
81 struct wined3d_query *query)
82 {
83 return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query);
84 }
85
86 static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info)
87 {
88 return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
89 }
90
91 static enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
92 const struct wined3d_device *device, DWORD flags)
93 {
94 const struct wined3d_gl_info *gl_info;
95 struct wined3d_context *context;
96 enum wined3d_fence_result ret;
97 BOOL fence_result;
98
99 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
100
101 if (!fence->context)
102 {
103 TRACE("Fence not issued.\n");
104 return WINED3D_FENCE_NOT_STARTED;
105 }
106
107 if (!(context = context_reacquire(device, fence->context)))
108 {
109 if (!fence->context->gl_info->supported[ARB_SYNC])
110 {
111 WARN("Fence tested from wrong thread.\n");
112 return WINED3D_FENCE_WRONG_THREAD;
113 }
114 context = context_acquire(device, NULL, 0);
115 }
116 gl_info = context->gl_info;
117
118 if (gl_info->supported[ARB_SYNC])
119 {
120 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
121 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
122 checkGLcall("glClientWaitSync");
123
124 switch (gl_ret)
125 {
126 case GL_ALREADY_SIGNALED:
127 case GL_CONDITION_SATISFIED:
128 ret = WINED3D_FENCE_OK;
129 break;
130
131 case GL_TIMEOUT_EXPIRED:
132 ret = WINED3D_FENCE_WAITING;
133 break;
134
135 case GL_WAIT_FAILED:
136 default:
137 ERR("glClientWaitSync returned %#x.\n", gl_ret);
138 ret = WINED3D_FENCE_ERROR;
139 }
140 }
141 else if (gl_info->supported[APPLE_FENCE])
142 {
143 fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
144 checkGLcall("glTestFenceAPPLE");
145 if (fence_result)
146 ret = WINED3D_FENCE_OK;
147 else
148 ret = WINED3D_FENCE_WAITING;
149 }
150 else if (gl_info->supported[NV_FENCE])
151 {
152 fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
153 checkGLcall("glTestFenceNV");
154 if (fence_result)
155 ret = WINED3D_FENCE_OK;
156 else
157 ret = WINED3D_FENCE_WAITING;
158 }
159 else
160 {
161 ERR("Fence created despite lack of GL support.\n");
162 ret = WINED3D_FENCE_ERROR;
163 }
164
165 context_release(context);
166 return ret;
167 }
168
169 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
170 const struct wined3d_device *device)
171 {
172 const struct wined3d_gl_info *gl_info;
173 struct wined3d_context *context;
174 enum wined3d_fence_result ret;
175
176 TRACE("fence %p, device %p.\n", fence, device);
177
178 if (!fence->context)
179 {
180 TRACE("Fence not issued.\n");
181 return WINED3D_FENCE_NOT_STARTED;
182 }
183 gl_info = fence->context->gl_info;
184
185 if (!(context = context_reacquire(device, fence->context)))
186 {
187 /* A glFinish does not reliably wait for draws in other contexts. The caller has
188 * to find its own way to cope with the thread switch
189 */
190 if (!gl_info->supported[ARB_SYNC])
191 {
192 WARN("Fence finished from wrong thread.\n");
193 return WINED3D_FENCE_WRONG_THREAD;
194 }
195 context = context_acquire(device, NULL, 0);
196 }
197 gl_info = context->gl_info;
198
199 if (gl_info->supported[ARB_SYNC])
200 {
201 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
202 * possibly because macOS internally adds some slop to the timer. To avoid this,
203 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
204 */
205 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
206 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
207 checkGLcall("glClientWaitSync");
208
209 switch (gl_ret)
210 {
211 case GL_ALREADY_SIGNALED:
212 case GL_CONDITION_SATISFIED:
213 ret = WINED3D_FENCE_OK;
214 break;
215
216 /* We don't expect a timeout for a ~292 year wait */
217 default:
218 ERR("glClientWaitSync returned %#x.\n", gl_ret);
219 ret = WINED3D_FENCE_ERROR;
220 }
221 }
222 else if (context->gl_info->supported[APPLE_FENCE])
223 {
224 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
225 checkGLcall("glFinishFenceAPPLE");
226 ret = WINED3D_FENCE_OK;
227 }
228 else if (context->gl_info->supported[NV_FENCE])
229 {
230 GL_EXTCALL(glFinishFenceNV(fence->object.id));
231 checkGLcall("glFinishFenceNV");
232 ret = WINED3D_FENCE_OK;
233 }
234 else
235 {
236 ERR("Fence created without GL support.\n");
237 ret = WINED3D_FENCE_ERROR;
238 }
239
240 context_release(context);
241 return ret;
242 }
243
244 void wined3d_fence_issue(struct wined3d_fence *fence, const struct wined3d_device *device)
245 {
246 struct wined3d_context *context = NULL;
247 const struct wined3d_gl_info *gl_info;
248
249 if (fence->context && !(context = context_reacquire(device, fence->context))
250 && !fence->context->gl_info->supported[ARB_SYNC])
251 context_free_fence(fence);
252 if (!context)
253 context = context_acquire(device, NULL, 0);
254 gl_info = context->gl_info;
255 if (!fence->context)
256 context_alloc_fence(context, fence);
257
258 if (gl_info->supported[ARB_SYNC])
259 {
260 if (fence->object.sync)
261 GL_EXTCALL(glDeleteSync(fence->object.sync));
262 checkGLcall("glDeleteSync");
263 fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
264 checkGLcall("glFenceSync");
265 }
266 else if (gl_info->supported[APPLE_FENCE])
267 {
268 GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
269 checkGLcall("glSetFenceAPPLE");
270 }
271 else if (gl_info->supported[NV_FENCE])
272 {
273 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
274 checkGLcall("glSetFenceNV");
275 }
276
277 context_release(context);
278 }
279
280 static void wined3d_fence_free(struct wined3d_fence *fence)
281 {
282 if (fence->context)
283 context_free_fence(fence);
284 }
285
286 void wined3d_fence_destroy(struct wined3d_fence *fence)
287 {
288 wined3d_fence_free(fence);
289 heap_free(fence);
290 }
291
292 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
293 {
294 if (!wined3d_fence_supported(gl_info))
295 {
296 WARN("Fences not supported.\n");
297 return WINED3DERR_NOTAVAILABLE;
298 }
299
300 return WINED3D_OK;
301 }
302
303 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
304 {
305 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
306 struct wined3d_fence *object;
307 HRESULT hr;
308
309 TRACE("device %p, fence %p.\n", device, fence);
310
311 if (!(object = heap_alloc_zero(sizeof(*object))))
312 return E_OUTOFMEMORY;
313
314 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
315 {
316 heap_free(object);
317 return hr;
318 }
319
320 TRACE("Created fence %p.\n", object);
321 *fence = object;
322
323 return WINED3D_OK;
324 }
325
326 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
327 {
328 ULONG refcount = InterlockedIncrement(&query->ref);
329
330 TRACE("%p increasing refcount to %u.\n", query, refcount);
331
332 return refcount;
333 }
334
335 static void wined3d_query_destroy_object(void *object)
336 {
337 struct wined3d_query *query = object;
338
339 if (!list_empty(&query->poll_list_entry))
340 list_remove(&query->poll_list_entry);
341
342 /* Queries are specific to the GL context that created them. Not
343 * deleting the query will obviously leak it, but that's still better
344 * than potentially deleting a different query with the same id in this
345 * context, and (still) leaking the actual query. */
346 query->query_ops->query_destroy(query);
347 }
348
349 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
350 {
351 ULONG refcount = InterlockedDecrement(&query->ref);
352
353 TRACE("%p decreasing refcount to %u.\n", query, refcount);
354
355 if (!refcount)
356 {
357 query->parent_ops->wined3d_object_destroyed(query->parent);
358 wined3d_cs_destroy_object(query->device->cs, wined3d_query_destroy_object, query);
359 }
360
361 return refcount;
362 }
363
364 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
365 void *data, UINT data_size, DWORD flags)
366 {
367 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
368 query, data, data_size, flags);
369
370 if (flags)
371 WARN("Ignoring flags %#x.\n", flags);
372
373 if (query->state == QUERY_BUILDING)
374 {
375 WARN("Query is building, returning S_FALSE.\n");
376 return S_FALSE;
377 }
378
379 if (query->state == QUERY_CREATED)
380 {
381 WARN("Query wasn't started yet.\n");
382 return WINED3DERR_INVALIDCALL;
383 }
384
385 if (!query->device->cs->thread)
386 {
387 if (!query->query_ops->query_poll(query, flags))
388 return S_FALSE;
389 }
390 else if (query->counter_main != query->counter_retrieved)
391 {
392 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
393 wined3d_cs_emit_flush(query->device->cs);
394 return S_FALSE;
395 }
396
397 if (data)
398 memcpy(data, query->data, min(data_size, query->data_size));
399
400 return S_OK;
401 }
402
403 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
404 {
405 TRACE("query %p.\n", query);
406
407 return query->data_size;
408 }
409
410 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
411 {
412 TRACE("query %p, flags %#x.\n", query, flags);
413
414 if (flags & WINED3DISSUE_END)
415 ++query->counter_main;
416
417 wined3d_cs_emit_query_issue(query->device->cs, query, flags);
418
419 if (flags & WINED3DISSUE_BEGIN)
420 query->state = QUERY_BUILDING;
421 else
422 query->state = QUERY_SIGNALLED;
423
424 return WINED3D_OK;
425 }
426
427 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags)
428 {
429 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
430 struct wined3d_device *device = query->device;
431 const struct wined3d_gl_info *gl_info;
432 struct wined3d_context *context;
433 GLuint available;
434
435 TRACE("query %p, flags %#x.\n", query, flags);
436
437 if (!(context = context_reacquire(device, oq->context)))
438 {
439 FIXME("%p Wrong thread, returning 1.\n", query);
440 oq->samples = 1;
441 return TRUE;
442 }
443 gl_info = context->gl_info;
444
445 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
446 TRACE("Available %#x.\n", available);
447
448 if (available)
449 {
450 oq->samples = get_query_result64(oq->id, gl_info);
451 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
452 }
453
454 checkGLcall("poll occlusion query");
455 context_release(context);
456
457 return available;
458 }
459
460 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags)
461 {
462 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
463 enum wined3d_fence_result ret;
464
465 TRACE("query %p, flags %#x.\n", query, flags);
466
467 ret = wined3d_fence_test(&event_query->fence, query->device, flags);
468 switch (ret)
469 {
470 case WINED3D_FENCE_OK:
471 case WINED3D_FENCE_NOT_STARTED:
472 return event_query->signalled = TRUE;
473
474 case WINED3D_FENCE_WAITING:
475 return event_query->signalled = FALSE;
476
477 case WINED3D_FENCE_WRONG_THREAD:
478 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
479 return event_query->signalled = TRUE;
480
481 case WINED3D_FENCE_ERROR:
482 ERR("The GL event query failed.\n");
483 return event_query->signalled = TRUE;
484
485 default:
486 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
487 return event_query->signalled = TRUE;
488 }
489 }
490
491 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
492 {
493 TRACE("query %p.\n", query);
494
495 return query->parent;
496 }
497
498 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
499 {
500 TRACE("query %p.\n", query);
501
502 return query->type;
503 }
504
505 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
506 {
507 TRACE("query %p, flags %#x.\n", query, flags);
508
509 if (flags & WINED3DISSUE_END)
510 {
511 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
512
513 wined3d_fence_issue(&event_query->fence, query->device);
514 return TRUE;
515 }
516 else if (flags & WINED3DISSUE_BEGIN)
517 {
518 /* Started implicitly at query creation. */
519 ERR("Event query issued with START flag - what to do?\n");
520 }
521
522 return FALSE;
523 }
524
525 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
526 {
527 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
528 struct wined3d_device *device = query->device;
529 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
530 struct wined3d_context *context;
531 BOOL poll = FALSE;
532
533 TRACE("query %p, flags %#x.\n", query, flags);
534
535 /* This is allowed according to MSDN and our tests. Reset the query and
536 * restart. */
537 if (flags & WINED3DISSUE_BEGIN)
538 {
539 if (oq->started)
540 {
541 if ((context = context_reacquire(device, oq->context)))
542 {
543 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
544 checkGLcall("glEndQuery()");
545 }
546 else
547 {
548 FIXME("Wrong thread, can't restart query.\n");
549 context_free_occlusion_query(oq);
550 context = context_acquire(device, NULL, 0);
551 context_alloc_occlusion_query(context, oq);
552 }
553 }
554 else
555 {
556 if (oq->context)
557 context_free_occlusion_query(oq);
558 context = context_acquire(device, NULL, 0);
559 context_alloc_occlusion_query(context, oq);
560 }
561
562 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
563 checkGLcall("glBeginQuery()");
564
565 context_release(context);
566 oq->started = TRUE;
567 }
568 if (flags & WINED3DISSUE_END)
569 {
570 /* MSDN says END on a non-building occlusion query returns an error,
571 * but our tests show that it returns OK. But OpenGL doesn't like it,
572 * so avoid generating an error. */
573 if (oq->started)
574 {
575 if ((context = context_reacquire(device, oq->context)))
576 {
577 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
578 checkGLcall("glEndQuery()");
579
580 context_release(context);
581 poll = TRUE;
582 }
583 else
584 {
585 FIXME("Wrong thread, can't end query.\n");
586 }
587 }
588 oq->started = FALSE;
589 }
590
591 return poll;
592 }
593
594 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
595 {
596 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
597 struct wined3d_device *device = query->device;
598 const struct wined3d_gl_info *gl_info;
599 struct wined3d_context *context;
600 GLuint64 timestamp;
601 GLuint available;
602
603 TRACE("query %p, flags %#x.\n", query, flags);
604
605 if (!(context = context_reacquire(device, tq->context)))
606 {
607 FIXME("%p Wrong thread, returning 1.\n", query);
608 tq->timestamp = 1;
609 return TRUE;
610 }
611 gl_info = context->gl_info;
612
613 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
614 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
615 TRACE("available %#x.\n", available);
616
617 if (available)
618 {
619 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
620 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
621 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
622 tq->timestamp = timestamp;
623 }
624
625 context_release(context);
626
627 return available;
628 }
629
630 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
631 {
632 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
633 const struct wined3d_gl_info *gl_info;
634 struct wined3d_context *context;
635
636 TRACE("query %p, flags %#x.\n", query, flags);
637
638 if (flags & WINED3DISSUE_BEGIN)
639 {
640 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
641 }
642 if (flags & WINED3DISSUE_END)
643 {
644 if (tq->context)
645 context_free_timestamp_query(tq);
646 context = context_acquire(query->device, NULL, 0);
647 gl_info = context->gl_info;
648 context_alloc_timestamp_query(context, tq);
649 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
650 checkGLcall("glQueryCounter()");
651 context_release(context);
652
653 return TRUE;
654 }
655
656 return FALSE;
657 }
658
659 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
660 {
661 TRACE("query %p, flags %#x.\n", query, flags);
662
663 return TRUE;
664 }
665
666 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
667 {
668 TRACE("query %p, flags %#x.\n", query, flags);
669
670 return FALSE;
671 }
672
673 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
674 {
675 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
676 struct wined3d_device *device = query->device;
677 GLuint written_available, generated_available;
678 const struct wined3d_gl_info *gl_info;
679 struct wined3d_context *context;
680
681 TRACE("query %p, flags %#x.\n", query, flags);
682
683 if (!(context = context_reacquire(device, pq->context)))
684 {
685 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
686 memset(&pq->statistics, 0, sizeof(pq->statistics));
687 return TRUE;
688 }
689 gl_info = context->gl_info;
690
691 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
692 GL_QUERY_RESULT_AVAILABLE, &written_available));
693 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
694 GL_QUERY_RESULT_AVAILABLE, &generated_available));
695 TRACE("Available %#x, %#x.\n", written_available, generated_available);
696
697 if (written_available && generated_available)
698 {
699 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
700 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
701 TRACE("Returning %s, %s primitives.\n",
702 wine_dbgstr_longlong(pq->statistics.primitives_written),
703 wine_dbgstr_longlong(pq->statistics.primitives_generated));
704 }
705
706 checkGLcall("poll SO statistics query");
707 context_release(context);
708
709 return written_available && generated_available;
710 }
711
712 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
713 {
714 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
715 struct wined3d_device *device = query->device;
716 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
717 struct wined3d_context *context;
718 BOOL poll = FALSE;
719
720 TRACE("query %p, flags %#x.\n", query, flags);
721
722 if (flags & WINED3DISSUE_BEGIN)
723 {
724 if (pq->started)
725 {
726 if ((context = context_reacquire(device, pq->context)))
727 {
728 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
729 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
730 }
731 else
732 {
733 FIXME("Wrong thread, can't restart query.\n");
734 context_free_so_statistics_query(pq);
735 context = context_acquire(device, NULL, 0);
736 context_alloc_so_statistics_query(context, pq);
737 }
738 }
739 else
740 {
741 if (pq->context)
742 context_free_so_statistics_query(pq);
743 context = context_acquire(device, NULL, 0);
744 context_alloc_so_statistics_query(context, pq);
745 }
746
747 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
748 pq->stream_idx, pq->u.query.written));
749 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
750 pq->stream_idx, pq->u.query.generated));
751 checkGLcall("begin query");
752
753 context_release(context);
754 pq->started = TRUE;
755 }
756 if (flags & WINED3DISSUE_END)
757 {
758 if (pq->started)
759 {
760 if ((context = context_reacquire(device, pq->context)))
761 {
762 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
763 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
764 checkGLcall("end query");
765
766 context_release(context);
767 poll = TRUE;
768 }
769 else
770 {
771 FIXME("Wrong thread, can't end query.\n");
772 }
773 }
774 pq->started = FALSE;
775 }
776
777 return poll;
778 }
779
780 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
781 {
782 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
783 struct wined3d_device *device = query->device;
784 const struct wined3d_gl_info *gl_info;
785 struct wined3d_context *context;
786 GLuint available;
787 int i;
788
789 TRACE("query %p, flags %#x.\n", query, flags);
790
791 if (!(context = context_reacquire(device, pq->context)))
792 {
793 FIXME("%p Wrong thread.\n", query);
794 memset(&pq->statistics, 0, sizeof(pq->statistics));
795 return TRUE;
796 }
797 gl_info = context->gl_info;
798
799 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
800 {
801 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
802 if (!available)
803 break;
804 }
805
806 if (available)
807 {
808 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
809 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
810 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
811 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
812 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
813 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
814 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
815 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
816 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
817 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
818 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
819 }
820
821 checkGLcall("poll pipeline statistics query");
822 context_release(context);
823 return available;
824 }
825
826 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
827 struct wined3d_context *context)
828 {
829 const struct wined3d_gl_info *gl_info = context->gl_info;
830
831 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
832 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
833 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
834 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
835 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
836 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
837 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
838 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
839 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
840 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
841 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
842 checkGLcall("end query");
843 }
844
845 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
846 {
847 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
848 struct wined3d_device *device = query->device;
849 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
850 struct wined3d_context *context;
851 BOOL poll = FALSE;
852
853 TRACE("query %p, flags %#x.\n", query, flags);
854
855 if (flags & WINED3DISSUE_BEGIN)
856 {
857 if (pq->started)
858 {
859 if ((context = context_reacquire(device, pq->context)))
860 {
861 wined3d_pipeline_statistics_query_end(pq, context);
862 }
863 else
864 {
865 FIXME("Wrong thread, can't restart query.\n");
866 context_free_pipeline_statistics_query(pq);
867 context = context_acquire(device, NULL, 0);
868 context_alloc_pipeline_statistics_query(context, pq);
869 }
870 }
871 else
872 {
873 if (pq->context)
874 context_free_pipeline_statistics_query(pq);
875 context = context_acquire(device, NULL, 0);
876 context_alloc_pipeline_statistics_query(context, pq);
877 }
878
879 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
880 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
881 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
882 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
883 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
884 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
885 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
886 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
887 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
888 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
889 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
890 checkGLcall("begin query");
891
892 context_release(context);
893 pq->started = TRUE;
894 }
895 if (flags & WINED3DISSUE_END)
896 {
897 if (pq->started)
898 {
899 if ((context = context_reacquire(device, pq->context)))
900 {
901 wined3d_pipeline_statistics_query_end(pq, context);
902 context_release(context);
903 poll = TRUE;
904 }
905 else
906 {
907 FIXME("Wrong thread, can't end query.\n");
908 }
909 }
910 pq->started = FALSE;
911 }
912
913 return poll;
914 }
915
916 static BOOL wined3d_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
917 {
918 TRACE("query %p, flags %#x.\n", query, flags);
919
920 return TRUE;
921 }
922
923 static BOOL wined3d_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
924 {
925 FIXME("query %p, flags %#x.\n", query, flags);
926
927 return FALSE;
928 }
929
930 static BOOL wined3d_overflow_query_ops_poll(struct wined3d_query *query, DWORD flags)
931 {
932 TRACE("query %p, flags %#x.\n", query, flags);
933
934 return TRUE;
935 }
936
937 static BOOL wined3d_overflow_query_ops_issue(struct wined3d_query *query, DWORD flags)
938 {
939 FIXME("query %p, flags %#x.\n", query, flags);
940
941 return FALSE;
942 }
943
944 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
945 {
946 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
947
948 wined3d_fence_free(&event_query->fence);
949 heap_free(event_query);
950 }
951
952 static const struct wined3d_query_ops event_query_ops =
953 {
954 wined3d_event_query_ops_poll,
955 wined3d_event_query_ops_issue,
956 wined3d_event_query_ops_destroy,
957 };
958
959 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
960 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
961 struct wined3d_query **query)
962 {
963 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
964 struct wined3d_event_query *object;
965 HRESULT hr;
966
967 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
968 device, type, parent, parent_ops, query);
969
970 if (!(object = heap_alloc_zero(sizeof(*object))))
971 return E_OUTOFMEMORY;
972
973 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
974 {
975 WARN("Event queries not supported.\n");
976 heap_free(object);
977 return hr;
978 }
979
980 wined3d_query_init(&object->query, device, type, &object->signalled,
981 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
982
983 TRACE("Created query %p.\n", object);
984 *query = &object->query;
985
986 return WINED3D_OK;
987 }
988
989 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
990 {
991 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
992
993 if (oq->context)
994 context_free_occlusion_query(oq);
995 heap_free(oq);
996 }
997
998 static const struct wined3d_query_ops occlusion_query_ops =
999 {
1000 wined3d_occlusion_query_ops_poll,
1001 wined3d_occlusion_query_ops_issue,
1002 wined3d_occlusion_query_ops_destroy,
1003 };
1004
1005 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
1006 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1007 struct wined3d_query **query)
1008 {
1009 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1010 struct wined3d_occlusion_query *object;
1011
1012 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1013 device, type, parent, parent_ops, query);
1014
1015 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
1016 {
1017 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1018 return WINED3DERR_NOTAVAILABLE;
1019 }
1020
1021 if (!(object = heap_alloc_zero(sizeof(*object))))
1022 return E_OUTOFMEMORY;
1023
1024 wined3d_query_init(&object->query, device, type, &object->samples,
1025 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1026
1027 TRACE("Created query %p.\n", object);
1028 *query = &object->query;
1029
1030 return WINED3D_OK;
1031 }
1032
1033 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1034 {
1035 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1036
1037 if (tq->context)
1038 context_free_timestamp_query(tq);
1039 heap_free(tq);
1040 }
1041
1042 static const struct wined3d_query_ops timestamp_query_ops =
1043 {
1044 wined3d_timestamp_query_ops_poll,
1045 wined3d_timestamp_query_ops_issue,
1046 wined3d_timestamp_query_ops_destroy,
1047 };
1048
1049 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1050 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1051 struct wined3d_query **query)
1052 {
1053 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1054 struct wined3d_timestamp_query *object;
1055
1056 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1057 device, type, parent, parent_ops, query);
1058
1059 if (!gl_info->supported[ARB_TIMER_QUERY])
1060 {
1061 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1062 return WINED3DERR_NOTAVAILABLE;
1063 }
1064
1065 if (!(object = heap_alloc_zero(sizeof(*object))))
1066 return E_OUTOFMEMORY;
1067
1068 wined3d_query_init(&object->query, device, type, &object->timestamp,
1069 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1070
1071 TRACE("Created query %p.\n", object);
1072 *query = &object->query;
1073
1074 return WINED3D_OK;
1075 }
1076
1077 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1078 {
1079 heap_free(query);
1080 }
1081
1082 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1083 {
1084 wined3d_timestamp_disjoint_query_ops_poll,
1085 wined3d_timestamp_disjoint_query_ops_issue,
1086 wined3d_timestamp_disjoint_query_ops_destroy,
1087 };
1088
1089 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1090 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1091 struct wined3d_query **query)
1092 {
1093 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1094 struct wined3d_query *object;
1095
1096 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1097 device, type, parent, parent_ops, query);
1098
1099 if (!gl_info->supported[ARB_TIMER_QUERY])
1100 {
1101 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1102 return WINED3DERR_NOTAVAILABLE;
1103 }
1104
1105 if (!(object = heap_alloc_zero(sizeof(*object))))
1106 return E_OUTOFMEMORY;
1107
1108 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1109 {
1110 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1111
1112 wined3d_query_init(object, device, type, &disjoint_data,
1113 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1114 }
1115 else
1116 {
1117 static const UINT64 freq = 1000 * 1000 * 1000;
1118
1119 wined3d_query_init(object, device, type, &freq,
1120 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1121 }
1122
1123 TRACE("Created query %p.\n", object);
1124 *query = object;
1125
1126 return WINED3D_OK;
1127 }
1128
1129 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1130 {
1131 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1132
1133 if (pq->context)
1134 context_free_so_statistics_query(pq);
1135 heap_free(pq);
1136 }
1137
1138 static const struct wined3d_query_ops so_statistics_query_ops =
1139 {
1140 wined3d_so_statistics_query_ops_poll,
1141 wined3d_so_statistics_query_ops_issue,
1142 wined3d_so_statistics_query_ops_destroy,
1143 };
1144
1145 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1146 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1147 struct wined3d_query **query)
1148 {
1149 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1150 struct wined3d_so_statistics_query *object;
1151 unsigned int stream_idx;
1152
1153 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1154 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1155 else
1156 return WINED3DERR_NOTAVAILABLE;
1157
1158 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1159 device, type, parent, parent_ops, query);
1160
1161 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1162 {
1163 WARN("OpenGL implementation does not support primitive queries.\n");
1164 return WINED3DERR_NOTAVAILABLE;
1165 }
1166 if (!gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1167 {
1168 WARN("OpenGL implementation does not support indexed queries.\n");
1169 return WINED3DERR_NOTAVAILABLE;
1170 }
1171
1172 if (!(object = heap_alloc_zero(sizeof(*object))))
1173 return E_OUTOFMEMORY;
1174
1175 wined3d_query_init(&object->query, device, type, &object->statistics,
1176 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1177 object->stream_idx = stream_idx;
1178
1179 TRACE("Created query %p.\n", object);
1180 *query = &object->query;
1181
1182 return WINED3D_OK;
1183 }
1184
1185 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1186 {
1187 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1188 if (pq->context)
1189 context_free_pipeline_statistics_query(pq);
1190 heap_free(pq);
1191 }
1192
1193 static const struct wined3d_query_ops pipeline_query_ops =
1194 {
1195 wined3d_pipeline_query_ops_poll,
1196 wined3d_pipeline_query_ops_issue,
1197 wined3d_pipeline_query_ops_destroy,
1198 };
1199
1200 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1201 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1202 struct wined3d_query **query)
1203 {
1204 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1205 struct wined3d_pipeline_statistics_query *object;
1206
1207 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1208 device, type, parent, parent_ops, query);
1209
1210 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1211 {
1212 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1213 return WINED3DERR_NOTAVAILABLE;
1214 }
1215
1216 if (!(object = heap_alloc_zero(sizeof(*object))))
1217 return E_OUTOFMEMORY;
1218
1219 wined3d_query_init(&object->query, device, type, &object->statistics,
1220 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1221
1222 TRACE("Created query %p.\n", object);
1223 *query = &object->query;
1224
1225 return WINED3D_OK;
1226 }
1227
1228 static void wined3d_statistics_query_ops_destroy(struct wined3d_query *query)
1229 {
1230 HeapFree(GetProcessHeap(), 0, query);
1231 }
1232
1233 static const struct wined3d_query_ops statistics_query_ops =
1234 {
1235 wined3d_statistics_query_ops_poll,
1236 wined3d_statistics_query_ops_issue,
1237 wined3d_statistics_query_ops_destroy,
1238 };
1239
1240 static HRESULT wined3d_statistics_query_create(struct wined3d_device *device,
1241 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1242 struct wined3d_query **query)
1243 {
1244 static const struct wined3d_query_data_so_statistics statistics = { 1, 1 };
1245 struct wined3d_query *object;
1246
1247 FIXME("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
1248
1249 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1250 return E_OUTOFMEMORY;
1251
1252 wined3d_query_init(object, device, type, &statistics,
1253 sizeof(statistics), &statistics_query_ops, parent, parent_ops);
1254
1255 TRACE("Created query %p.\n", object);
1256 *query = object;
1257
1258 return WINED3D_OK;
1259 }
1260
1261 static void wined3d_overflow_query_ops_destroy(struct wined3d_query *query)
1262 {
1263 HeapFree(GetProcessHeap(), 0, query);
1264 }
1265
1266 static const struct wined3d_query_ops overflow_query_ops =
1267 {
1268 wined3d_overflow_query_ops_poll,
1269 wined3d_overflow_query_ops_issue,
1270 wined3d_overflow_query_ops_destroy,
1271 };
1272
1273 static HRESULT wined3d_overflow_query_create(struct wined3d_device *device,
1274 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1275 struct wined3d_query **query)
1276 {
1277 static const BOOL overflow = FALSE;
1278 struct wined3d_query *object;
1279
1280 FIXME("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
1281
1282 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1283 return E_OUTOFMEMORY;
1284
1285 wined3d_query_init(object, device, type, &overflow,
1286 sizeof(overflow), &overflow_query_ops, parent, parent_ops);
1287
1288 TRACE("Created query %p.\n", object);
1289 *query = object;
1290
1291 return WINED3D_OK;
1292 }
1293
1294 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1295 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1296 {
1297 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1298 device, type, parent, parent_ops, query);
1299
1300 switch (type)
1301 {
1302 case WINED3D_QUERY_TYPE_EVENT:
1303 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1304
1305 case WINED3D_QUERY_TYPE_OCCLUSION:
1306 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1307
1308 case WINED3D_QUERY_TYPE_TIMESTAMP:
1309 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1310
1311 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1312 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1313 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1314
1315 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1316 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1317 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1318 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1319 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1320
1321 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1322 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1323
1324 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1325 return wined3d_statistics_query_create(device, type, parent, parent_ops, query);
1326
1327 case WINED3D_QUERY_TYPE_SO_OVERFLOW:
1328 return wined3d_overflow_query_create(device, type, parent, parent_ops, query);
1329
1330 default:
1331 FIXME("Unhandled query type %#x.\n", type);
1332 return WINED3DERR_NOTAVAILABLE;
1333 }
1334 }