2 * Copyright 2005 Oliver Stieber
3 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
4 * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
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.
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.
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
23 #include "wine/port.h"
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
28 static UINT64
get_query_result64(GLuint id
, const struct wined3d_gl_info
*gl_info
)
30 if (gl_info
->supported
[ARB_TIMER_QUERY
])
33 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, &result
));
39 GL_EXTCALL(glGetQueryObjectuiv(id
, GL_QUERY_RESULT
, &result
));
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
)
49 query
->parent
= parent
;
50 query
->parent_ops
= parent_ops
;
51 query
->device
= device
;
52 query
->state
= QUERY_CREATED
;
55 query
->data_size
= data_size
;
56 query
->query_ops
= query_ops
;
57 list_init(&query
->poll_list_entry
);
60 static struct wined3d_event_query
*wined3d_event_query_from_query(struct wined3d_query
*query
)
62 return CONTAINING_RECORD(query
, struct wined3d_event_query
, query
);
65 static struct wined3d_occlusion_query
*wined3d_occlusion_query_from_query(struct wined3d_query
*query
)
67 return CONTAINING_RECORD(query
, struct wined3d_occlusion_query
, query
);
70 static struct wined3d_timestamp_query
*wined3d_timestamp_query_from_query(struct wined3d_query
*query
)
72 return CONTAINING_RECORD(query
, struct wined3d_timestamp_query
, query
);
75 static struct wined3d_so_statistics_query
*wined3d_so_statistics_query_from_query(struct wined3d_query
*query
)
77 return CONTAINING_RECORD(query
, struct wined3d_so_statistics_query
, query
);
80 static struct wined3d_pipeline_statistics_query
*wined3d_pipeline_statistics_query_from_query(
81 struct wined3d_query
*query
)
83 return CONTAINING_RECORD(query
, struct wined3d_pipeline_statistics_query
, query
);
86 static BOOL
wined3d_fence_supported(const struct wined3d_gl_info
*gl_info
)
88 return gl_info
->supported
[ARB_SYNC
] || gl_info
->supported
[NV_FENCE
] || gl_info
->supported
[APPLE_FENCE
];
91 static enum wined3d_fence_result
wined3d_fence_test(const struct wined3d_fence
*fence
,
92 const struct wined3d_device
*device
, DWORD flags
)
94 const struct wined3d_gl_info
*gl_info
;
95 struct wined3d_context
*context
;
96 enum wined3d_fence_result ret
;
99 TRACE("fence %p, device %p, flags %#x.\n", fence
, device
, flags
);
103 TRACE("Fence not issued.\n");
104 return WINED3D_FENCE_NOT_STARTED
;
107 if (!(context
= context_reacquire(device
, fence
->context
)))
109 if (!fence
->context
->gl_info
->supported
[ARB_SYNC
])
111 WARN("Fence tested from wrong thread.\n");
112 return WINED3D_FENCE_WRONG_THREAD
;
114 context
= context_acquire(device
, NULL
, 0);
116 gl_info
= context
->gl_info
;
118 if (gl_info
->supported
[ARB_SYNC
])
120 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
121 (flags
& WINED3DGETDATA_FLUSH
) ? GL_SYNC_FLUSH_COMMANDS_BIT
: 0, 0));
122 checkGLcall("glClientWaitSync");
126 case GL_ALREADY_SIGNALED
:
127 case GL_CONDITION_SATISFIED
:
128 ret
= WINED3D_FENCE_OK
;
131 case GL_TIMEOUT_EXPIRED
:
132 ret
= WINED3D_FENCE_WAITING
;
137 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
138 ret
= WINED3D_FENCE_ERROR
;
141 else if (gl_info
->supported
[APPLE_FENCE
])
143 fence_result
= GL_EXTCALL(glTestFenceAPPLE(fence
->object
.id
));
144 checkGLcall("glTestFenceAPPLE");
146 ret
= WINED3D_FENCE_OK
;
148 ret
= WINED3D_FENCE_WAITING
;
150 else if (gl_info
->supported
[NV_FENCE
])
152 fence_result
= GL_EXTCALL(glTestFenceNV(fence
->object
.id
));
153 checkGLcall("glTestFenceNV");
155 ret
= WINED3D_FENCE_OK
;
157 ret
= WINED3D_FENCE_WAITING
;
161 ERR("Fence created despite lack of GL support.\n");
162 ret
= WINED3D_FENCE_ERROR
;
165 context_release(context
);
169 enum wined3d_fence_result
wined3d_fence_wait(const struct wined3d_fence
*fence
,
170 const struct wined3d_device
*device
)
172 const struct wined3d_gl_info
*gl_info
;
173 struct wined3d_context
*context
;
174 enum wined3d_fence_result ret
;
176 TRACE("fence %p, device %p.\n", fence
, device
);
180 TRACE("Fence not issued.\n");
181 return WINED3D_FENCE_NOT_STARTED
;
183 gl_info
= fence
->context
->gl_info
;
185 if (!(context
= context_reacquire(device
, fence
->context
)))
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
190 if (!gl_info
->supported
[ARB_SYNC
])
192 WARN("Fence finished from wrong thread.\n");
193 return WINED3D_FENCE_WRONG_THREAD
;
195 context
= context_acquire(device
, NULL
, 0);
197 gl_info
= context
->gl_info
;
199 if (gl_info
->supported
[ARB_SYNC
])
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).
205 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
206 GL_SYNC_FLUSH_COMMANDS_BIT
, ~(GLuint64
)0 >> 1));
207 checkGLcall("glClientWaitSync");
211 case GL_ALREADY_SIGNALED
:
212 case GL_CONDITION_SATISFIED
:
213 ret
= WINED3D_FENCE_OK
;
216 /* We don't expect a timeout for a ~292 year wait */
218 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
219 ret
= WINED3D_FENCE_ERROR
;
222 else if (context
->gl_info
->supported
[APPLE_FENCE
])
224 GL_EXTCALL(glFinishFenceAPPLE(fence
->object
.id
));
225 checkGLcall("glFinishFenceAPPLE");
226 ret
= WINED3D_FENCE_OK
;
228 else if (context
->gl_info
->supported
[NV_FENCE
])
230 GL_EXTCALL(glFinishFenceNV(fence
->object
.id
));
231 checkGLcall("glFinishFenceNV");
232 ret
= WINED3D_FENCE_OK
;
236 ERR("Fence created without GL support.\n");
237 ret
= WINED3D_FENCE_ERROR
;
240 context_release(context
);
244 void wined3d_fence_issue(struct wined3d_fence
*fence
, const struct wined3d_device
*device
)
246 struct wined3d_context
*context
= NULL
;
247 const struct wined3d_gl_info
*gl_info
;
249 if (fence
->context
&& !(context
= context_reacquire(device
, fence
->context
))
250 && !fence
->context
->gl_info
->supported
[ARB_SYNC
])
251 context_free_fence(fence
);
253 context
= context_acquire(device
, NULL
, 0);
254 gl_info
= context
->gl_info
;
256 context_alloc_fence(context
, fence
);
258 if (gl_info
->supported
[ARB_SYNC
])
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");
266 else if (gl_info
->supported
[APPLE_FENCE
])
268 GL_EXTCALL(glSetFenceAPPLE(fence
->object
.id
));
269 checkGLcall("glSetFenceAPPLE");
271 else if (gl_info
->supported
[NV_FENCE
])
273 GL_EXTCALL(glSetFenceNV(fence
->object
.id
, GL_ALL_COMPLETED_NV
));
274 checkGLcall("glSetFenceNV");
277 context_release(context
);
280 static void wined3d_fence_free(struct wined3d_fence
*fence
)
283 context_free_fence(fence
);
286 void wined3d_fence_destroy(struct wined3d_fence
*fence
)
288 wined3d_fence_free(fence
);
289 HeapFree(GetProcessHeap(), 0, fence
);
292 static HRESULT
wined3d_fence_init(struct wined3d_fence
*fence
, const struct wined3d_gl_info
*gl_info
)
294 if (!wined3d_fence_supported(gl_info
))
296 WARN("Fences not supported.\n");
297 return WINED3DERR_NOTAVAILABLE
;
303 HRESULT
wined3d_fence_create(struct wined3d_device
*device
, struct wined3d_fence
**fence
)
305 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
306 struct wined3d_fence
*object
;
309 TRACE("device %p, fence %p.\n", device
, fence
);
311 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
312 return E_OUTOFMEMORY
;
314 if (FAILED(hr
= wined3d_fence_init(object
, gl_info
)))
316 HeapFree(GetProcessHeap(), 0, object
);
320 TRACE("Created fence %p.\n", object
);
326 ULONG CDECL
wined3d_query_incref(struct wined3d_query
*query
)
328 ULONG refcount
= InterlockedIncrement(&query
->ref
);
330 TRACE("%p increasing refcount to %u.\n", query
, refcount
);
335 static void wined3d_query_destroy_object(void *object
)
337 struct wined3d_query
*query
= object
;
339 if (!list_empty(&query
->poll_list_entry
))
340 list_remove(&query
->poll_list_entry
);
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
);
349 ULONG CDECL
wined3d_query_decref(struct wined3d_query
*query
)
351 ULONG refcount
= InterlockedDecrement(&query
->ref
);
353 TRACE("%p decreasing refcount to %u.\n", query
, refcount
);
357 query
->parent_ops
->wined3d_object_destroyed(query
->parent
);
358 wined3d_cs_destroy_object(query
->device
->cs
, wined3d_query_destroy_object
, query
);
364 HRESULT CDECL
wined3d_query_get_data(struct wined3d_query
*query
,
365 void *data
, UINT data_size
, DWORD flags
)
367 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
368 query
, data
, data_size
, flags
);
371 WARN("Ignoring flags %#x.\n", flags
);
373 if (query
->state
== QUERY_BUILDING
)
375 WARN("Query is building, returning S_FALSE.\n");
379 if (query
->state
== QUERY_CREATED
)
381 WARN("Query wasn't started yet.\n");
382 return WINED3DERR_INVALIDCALL
;
385 if (!query
->device
->cs
->thread
)
387 if (!query
->query_ops
->query_poll(query
, flags
))
390 else if (query
->counter_main
!= query
->counter_retrieved
)
392 if (flags
& WINED3DGETDATA_FLUSH
)
393 wined3d_cs_emit_flush(query
->device
->cs
);
398 memcpy(data
, query
->data
, min(data_size
, query
->data_size
));
403 UINT CDECL
wined3d_query_get_data_size(const struct wined3d_query
*query
)
405 TRACE("query %p.\n", query
);
407 return query
->data_size
;
410 HRESULT CDECL
wined3d_query_issue(struct wined3d_query
*query
, DWORD flags
)
412 TRACE("query %p, flags %#x.\n", query
, flags
);
414 if (flags
& WINED3DISSUE_END
)
415 ++query
->counter_main
;
417 wined3d_cs_emit_query_issue(query
->device
->cs
, query
, flags
);
419 if (flags
& WINED3DISSUE_BEGIN
)
420 query
->state
= QUERY_BUILDING
;
422 query
->state
= QUERY_SIGNALLED
;
427 static BOOL
wined3d_occlusion_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
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
;
435 TRACE("query %p, flags %#x.\n", query
, flags
);
437 if (!(context
= context_reacquire(device
, oq
->context
)))
439 FIXME("%p Wrong thread, returning 1.\n", query
);
443 gl_info
= context
->gl_info
;
445 GL_EXTCALL(glGetQueryObjectuiv(oq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
446 TRACE("Available %#x.\n", available
);
450 oq
->samples
= get_query_result64(oq
->id
, gl_info
);
451 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq
->samples
));
454 checkGLcall("poll occlusion query");
455 context_release(context
);
460 static BOOL
wined3d_event_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
462 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
463 enum wined3d_fence_result ret
;
465 TRACE("query %p, flags %#x.\n", query
, flags
);
467 ret
= wined3d_fence_test(&event_query
->fence
, query
->device
, flags
);
470 case WINED3D_FENCE_OK
:
471 case WINED3D_FENCE_NOT_STARTED
:
472 return event_query
->signalled
= TRUE
;
474 case WINED3D_FENCE_WAITING
:
475 return event_query
->signalled
= FALSE
;
477 case WINED3D_FENCE_WRONG_THREAD
:
478 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query
);
479 return event_query
->signalled
= TRUE
;
481 case WINED3D_FENCE_ERROR
:
482 ERR("The GL event query failed.\n");
483 return event_query
->signalled
= TRUE
;
486 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret
);
487 return event_query
->signalled
= TRUE
;
491 void * CDECL
wined3d_query_get_parent(const struct wined3d_query
*query
)
493 TRACE("query %p.\n", query
);
495 return query
->parent
;
498 enum wined3d_query_type CDECL
wined3d_query_get_type(const struct wined3d_query
*query
)
500 TRACE("query %p.\n", query
);
505 static BOOL
wined3d_event_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
507 TRACE("query %p, flags %#x.\n", query
, flags
);
509 if (flags
& WINED3DISSUE_END
)
511 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
513 wined3d_fence_issue(&event_query
->fence
, query
->device
);
516 else if (flags
& WINED3DISSUE_BEGIN
)
518 /* Started implicitly at query creation. */
519 ERR("Event query issued with START flag - what to do?\n");
525 static BOOL
wined3d_occlusion_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
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
;
533 TRACE("query %p, flags %#x.\n", query
, flags
);
535 /* This is allowed according to MSDN and our tests. Reset the query and
537 if (flags
& WINED3DISSUE_BEGIN
)
541 if ((context
= context_reacquire(device
, oq
->context
)))
543 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
544 checkGLcall("glEndQuery()");
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
);
557 context_free_occlusion_query(oq
);
558 context
= context_acquire(device
, NULL
, 0);
559 context_alloc_occlusion_query(context
, oq
);
562 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED
, oq
->id
));
563 checkGLcall("glBeginQuery()");
565 context_release(context
);
568 if (flags
& WINED3DISSUE_END
)
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. */
575 if ((context
= context_reacquire(device
, oq
->context
)))
577 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
578 checkGLcall("glEndQuery()");
580 context_release(context
);
585 FIXME("Wrong thread, can't end query.\n");
594 static BOOL
wined3d_timestamp_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
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
;
603 TRACE("query %p, flags %#x.\n", query
, flags
);
605 if (!(context
= context_reacquire(device
, tq
->context
)))
607 FIXME("%p Wrong thread, returning 1.\n", query
);
611 gl_info
= context
->gl_info
;
613 GL_EXTCALL(glGetQueryObjectuiv(tq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
614 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
615 TRACE("available %#x.\n", available
);
619 GL_EXTCALL(glGetQueryObjectui64v(tq
->id
, GL_QUERY_RESULT
, ×tamp
));
620 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
621 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp
));
622 tq
->timestamp
= timestamp
;
625 context_release(context
);
630 static BOOL
wined3d_timestamp_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
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
;
636 TRACE("query %p, flags %#x.\n", query
, flags
);
638 if (flags
& WINED3DISSUE_BEGIN
)
640 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
642 if (flags
& WINED3DISSUE_END
)
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
);
659 static BOOL
wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
661 TRACE("query %p, flags %#x.\n", query
, flags
);
666 static BOOL
wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
668 TRACE("query %p, flags %#x.\n", query
, flags
);
673 static BOOL
wined3d_so_statistics_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
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
;
681 TRACE("query %p, flags %#x.\n", query
, flags
);
683 if (!(context
= context_reacquire(device
, pq
->context
)))
685 FIXME("%p Wrong thread, returning 0 primitives.\n", query
);
686 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
689 gl_info
= context
->gl_info
;
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
);
697 if (written_available
&& generated_available
)
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
));
706 checkGLcall("poll SO statistics query");
707 context_release(context
);
709 return written_available
&& generated_available
;
712 static BOOL
wined3d_so_statistics_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
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
;
720 TRACE("query %p, flags %#x.\n", query
, flags
);
722 if (flags
& WINED3DISSUE_BEGIN
)
726 if ((context
= context_reacquire(device
, pq
->context
)))
728 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
, pq
->stream_idx
));
729 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED
, pq
->stream_idx
));
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
);
742 context_free_so_statistics_query(pq
);
743 context
= context_acquire(device
, NULL
, 0);
744 context_alloc_so_statistics_query(context
, pq
);
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");
753 context_release(context
);
756 if (flags
& WINED3DISSUE_END
)
760 if ((context
= context_reacquire(device
, pq
->context
)))
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");
766 context_release(context
);
771 FIXME("Wrong thread, can't end query.\n");
780 static BOOL
wined3d_pipeline_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
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
;
789 TRACE("query %p, flags %#x.\n", query
, flags
);
791 if (!(context
= context_reacquire(device
, pq
->context
)))
793 FIXME("%p Wrong thread.\n", query
);
794 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
797 gl_info
= context
->gl_info
;
799 for (i
= 0; i
< ARRAY_SIZE(pq
->u
.id
); ++i
)
801 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.id
[i
], GL_QUERY_RESULT_AVAILABLE
, &available
));
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
);
821 checkGLcall("poll pipeline statistics query");
822 context_release(context
);
826 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query
*query
,
827 struct wined3d_context
*context
)
829 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
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");
845 static BOOL
wined3d_pipeline_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
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
;
853 TRACE("query %p, flags %#x.\n", query
, flags
);
855 if (flags
& WINED3DISSUE_BEGIN
)
859 if ((context
= context_reacquire(device
, pq
->context
)))
861 wined3d_pipeline_statistics_query_end(pq
, context
);
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
);
874 context_free_pipeline_statistics_query(pq
);
875 context
= context_acquire(device
, NULL
, 0);
876 context_alloc_pipeline_statistics_query(context
, pq
);
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");
892 context_release(context
);
895 if (flags
& WINED3DISSUE_END
)
899 if ((context
= context_reacquire(device
, pq
->context
)))
901 wined3d_pipeline_statistics_query_end(pq
, context
);
902 context_release(context
);
907 FIXME("Wrong thread, can't end query.\n");
916 static void wined3d_event_query_ops_destroy(struct wined3d_query
*query
)
918 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
920 wined3d_fence_free(&event_query
->fence
);
921 HeapFree(GetProcessHeap(), 0, event_query
);
924 static const struct wined3d_query_ops event_query_ops
=
926 wined3d_event_query_ops_poll
,
927 wined3d_event_query_ops_issue
,
928 wined3d_event_query_ops_destroy
,
931 static HRESULT
wined3d_event_query_create(struct wined3d_device
*device
,
932 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
933 struct wined3d_query
**query
)
935 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
936 struct wined3d_event_query
*object
;
939 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
940 device
, type
, parent
, parent_ops
, query
);
942 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
943 return E_OUTOFMEMORY
;
945 if (FAILED(hr
= wined3d_fence_init(&object
->fence
, gl_info
)))
947 WARN("Event queries not supported.\n");
948 HeapFree(GetProcessHeap(), 0, object
);
952 wined3d_query_init(&object
->query
, device
, type
, &object
->signalled
,
953 sizeof(object
->signalled
), &event_query_ops
, parent
, parent_ops
);
955 TRACE("Created query %p.\n", object
);
956 *query
= &object
->query
;
961 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query
*query
)
963 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
966 context_free_occlusion_query(oq
);
967 HeapFree(GetProcessHeap(), 0, oq
);
970 static const struct wined3d_query_ops occlusion_query_ops
=
972 wined3d_occlusion_query_ops_poll
,
973 wined3d_occlusion_query_ops_issue
,
974 wined3d_occlusion_query_ops_destroy
,
977 static HRESULT
wined3d_occlusion_query_create(struct wined3d_device
*device
,
978 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
979 struct wined3d_query
**query
)
981 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
982 struct wined3d_occlusion_query
*object
;
984 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
985 device
, type
, parent
, parent_ops
, query
);
987 if (!gl_info
->supported
[ARB_OCCLUSION_QUERY
])
989 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
990 return WINED3DERR_NOTAVAILABLE
;
993 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
994 return E_OUTOFMEMORY
;
996 wined3d_query_init(&object
->query
, device
, type
, &object
->samples
,
997 sizeof(object
->samples
), &occlusion_query_ops
, parent
, parent_ops
);
999 TRACE("Created query %p.\n", object
);
1000 *query
= &object
->query
;
1005 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query
*query
)
1007 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
1010 context_free_timestamp_query(tq
);
1011 HeapFree(GetProcessHeap(), 0, tq
);
1014 static const struct wined3d_query_ops timestamp_query_ops
=
1016 wined3d_timestamp_query_ops_poll
,
1017 wined3d_timestamp_query_ops_issue
,
1018 wined3d_timestamp_query_ops_destroy
,
1021 static HRESULT
wined3d_timestamp_query_create(struct wined3d_device
*device
,
1022 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1023 struct wined3d_query
**query
)
1025 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1026 struct wined3d_timestamp_query
*object
;
1028 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1029 device
, type
, parent
, parent_ops
, query
);
1031 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1033 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1034 return WINED3DERR_NOTAVAILABLE
;
1037 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
1038 return E_OUTOFMEMORY
;
1040 wined3d_query_init(&object
->query
, device
, type
, &object
->timestamp
,
1041 sizeof(object
->timestamp
), ×tamp_query_ops
, parent
, parent_ops
);
1043 TRACE("Created query %p.\n", object
);
1044 *query
= &object
->query
;
1049 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query
*query
)
1051 HeapFree(GetProcessHeap(), 0, query
);
1054 static const struct wined3d_query_ops timestamp_disjoint_query_ops
=
1056 wined3d_timestamp_disjoint_query_ops_poll
,
1057 wined3d_timestamp_disjoint_query_ops_issue
,
1058 wined3d_timestamp_disjoint_query_ops_destroy
,
1061 static HRESULT
wined3d_timestamp_disjoint_query_create(struct wined3d_device
*device
,
1062 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1063 struct wined3d_query
**query
)
1065 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1066 struct wined3d_query
*object
;
1068 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1069 device
, type
, parent
, parent_ops
, query
);
1071 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1073 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1074 return WINED3DERR_NOTAVAILABLE
;
1077 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
1078 return E_OUTOFMEMORY
;
1080 if (type
== WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
)
1082 static const struct wined3d_query_data_timestamp_disjoint disjoint_data
= {1000 * 1000 * 1000, FALSE
};
1084 wined3d_query_init(object
, device
, type
, &disjoint_data
,
1085 sizeof(disjoint_data
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1089 static const UINT64 freq
= 1000 * 1000 * 1000;
1091 wined3d_query_init(object
, device
, type
, &freq
,
1092 sizeof(freq
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1095 TRACE("Created query %p.\n", object
);
1101 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query
*query
)
1103 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
1106 context_free_so_statistics_query(pq
);
1107 HeapFree(GetProcessHeap(), 0, pq
);
1110 static const struct wined3d_query_ops so_statistics_query_ops
=
1112 wined3d_so_statistics_query_ops_poll
,
1113 wined3d_so_statistics_query_ops_issue
,
1114 wined3d_so_statistics_query_ops_destroy
,
1117 static HRESULT
wined3d_so_statistics_query_create(struct wined3d_device
*device
,
1118 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1119 struct wined3d_query
**query
)
1121 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1122 struct wined3d_so_statistics_query
*object
;
1123 unsigned int stream_idx
;
1125 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
<= type
&& type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1126 stream_idx
= type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
;
1128 return WINED3DERR_NOTAVAILABLE
;
1130 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1131 device
, type
, parent
, parent_ops
, query
);
1133 if (!gl_info
->supported
[WINED3D_GL_PRIMITIVE_QUERY
])
1135 WARN("OpenGL implementation does not support primitive queries.\n");
1136 return WINED3DERR_NOTAVAILABLE
;
1138 if (!gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
1140 WARN("OpenGL implementation does not support indexed queries.\n");
1141 return WINED3DERR_NOTAVAILABLE
;
1144 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
1145 return E_OUTOFMEMORY
;
1147 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1148 sizeof(object
->statistics
), &so_statistics_query_ops
, parent
, parent_ops
);
1149 object
->stream_idx
= stream_idx
;
1151 TRACE("Created query %p.\n", object
);
1152 *query
= &object
->query
;
1157 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query
*query
)
1159 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
1161 context_free_pipeline_statistics_query(pq
);
1162 HeapFree(GetProcessHeap(), 0, pq
);
1165 static const struct wined3d_query_ops pipeline_query_ops
=
1167 wined3d_pipeline_query_ops_poll
,
1168 wined3d_pipeline_query_ops_issue
,
1169 wined3d_pipeline_query_ops_destroy
,
1172 static HRESULT
wined3d_pipeline_query_create(struct wined3d_device
*device
,
1173 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1174 struct wined3d_query
**query
)
1176 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1177 struct wined3d_pipeline_statistics_query
*object
;
1179 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1180 device
, type
, parent
, parent_ops
, query
);
1182 if (!gl_info
->supported
[ARB_PIPELINE_STATISTICS_QUERY
])
1184 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1185 return WINED3DERR_NOTAVAILABLE
;
1188 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
1189 return E_OUTOFMEMORY
;
1191 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1192 sizeof(object
->statistics
), &pipeline_query_ops
, parent
, parent_ops
);
1194 TRACE("Created query %p.\n", object
);
1195 *query
= &object
->query
;
1200 HRESULT CDECL
wined3d_query_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1201 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1203 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1204 device
, type
, parent
, parent_ops
, query
);
1208 case WINED3D_QUERY_TYPE_EVENT
:
1209 return wined3d_event_query_create(device
, type
, parent
, parent_ops
, query
);
1211 case WINED3D_QUERY_TYPE_OCCLUSION
:
1212 return wined3d_occlusion_query_create(device
, type
, parent
, parent_ops
, query
);
1214 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1215 return wined3d_timestamp_query_create(device
, type
, parent
, parent_ops
, query
);
1217 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1218 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ
:
1219 return wined3d_timestamp_disjoint_query_create(device
, type
, parent
, parent_ops
, query
);
1221 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1222 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1223 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1224 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1225 return wined3d_so_statistics_query_create(device
, type
, parent
, parent_ops
, query
);
1227 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1228 return wined3d_pipeline_query_create(device
, type
, parent
, parent_ops
, query
);
1231 FIXME("Unhandled query type %#x.\n", type
);
1232 return WINED3DERR_NOTAVAILABLE
;