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
21 #include "wined3d_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
25 static void wined3d_query_buffer_invalidate(struct wined3d_query
*query
)
27 /* map[0] != map[1]: exact values do not have any significance. */
28 query
->map_ptr
[0] = 0;
29 query
->map_ptr
[1] = ~(UINT64
)0;
32 static BOOL
wined3d_query_buffer_is_valid(struct wined3d_query
*query
)
34 return query
->map_ptr
[0] == query
->map_ptr
[1];
37 static void wined3d_query_create_buffer_object(struct wined3d_context_gl
*context_gl
, struct wined3d_query
*query
)
39 const GLuint map_flags
= GL_MAP_READ_BIT
| GL_MAP_WRITE_BIT
| GL_MAP_PERSISTENT_BIT
| GL_MAP_COHERENT_BIT
;
40 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
43 GL_EXTCALL(glGenBuffers(1, &buffer_object
));
44 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, buffer_object
));
45 GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER
, sizeof(query
->map_ptr
[0]) * 2, NULL
, map_flags
));
46 query
->map_ptr
= GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER
, 0, sizeof(query
->map_ptr
[0]) * 2, map_flags
));
47 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, 0));
48 checkGLcall("query buffer object creation");
50 wined3d_query_buffer_invalidate(query
);
51 query
->buffer_object
= buffer_object
;
54 void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl
*context_gl
, struct wined3d_query
*query
)
56 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
58 GL_EXTCALL(glDeleteBuffers(1, &query
->buffer_object
));
59 checkGLcall("query buffer object destruction");
61 query
->buffer_object
= 0;
62 query
->map_ptr
= NULL
;
65 /* From ARB_occlusion_query: "Querying the state for a given occlusion query
66 * forces that occlusion query to complete within a finite amount of time."
67 * In practice, that means drivers flush when retrieving
68 * GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
69 * significant number of queries. Using a persistently mapped query buffer
70 * object allows us to avoid these implicit flushes. An additional benefit is
71 * that it allows us to poll the query status from the application-thread
72 * instead of from the csmt-thread. */
73 static BOOL
wined3d_query_buffer_queue_result(struct wined3d_context_gl
*context_gl
,
74 struct wined3d_query
*query
, GLuint id
)
76 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
79 if (!gl_info
->supported
[ARB_QUERY_BUFFER_OBJECT
] || !gl_info
->supported
[ARB_BUFFER_STORAGE
])
81 /* Don't use query buffers without CSMT, mainly for simplicity. */
82 if (!context_gl
->c
.device
->cs
->thread
)
85 if (query
->buffer_object
)
87 /* If there's still a query result in-flight for the existing buffer
88 * object (i.e., the query was restarted before we received its
89 * result), we can't reuse the existing buffer object. */
90 if (wined3d_query_buffer_is_valid(query
))
91 wined3d_query_buffer_invalidate(query
);
93 wined3d_query_gl_destroy_buffer_object(context_gl
, query
);
96 if (!query
->buffer_object
)
97 wined3d_query_create_buffer_object(context_gl
, query
);
99 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, query
->buffer_object
));
100 /* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
101 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, (void *)0));
102 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, (void *)sizeof(query
->map_ptr
[0])));
103 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, 0));
104 checkGLcall("queue query result");
106 /* ARB_buffer_storage requires the client to call FenceSync with
107 * SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
108 * is not enforced by Mesa.
110 tmp_sync
= GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE
, 0));
111 GL_EXTCALL(glDeleteSync(tmp_sync
));
112 checkGLcall("query buffer sync");
117 static UINT64
get_query_result64(GLuint id
, const struct wined3d_gl_info
*gl_info
)
119 if (gl_info
->supported
[ARB_TIMER_QUERY
])
122 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, &result
));
128 GL_EXTCALL(glGetQueryObjectuiv(id
, GL_QUERY_RESULT
, &result
));
133 static void wined3d_query_init(struct wined3d_query
*query
, struct wined3d_device
*device
,
134 enum wined3d_query_type type
, const void *data
, DWORD data_size
,
135 const struct wined3d_query_ops
*query_ops
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
138 query
->parent
= parent
;
139 query
->parent_ops
= parent_ops
;
140 query
->device
= device
;
141 query
->state
= QUERY_CREATED
;
144 query
->data_size
= data_size
;
145 query
->query_ops
= query_ops
;
146 query
->poll_in_cs
= !!device
->cs
->thread
;
147 list_init(&query
->poll_list_entry
);
150 static struct wined3d_event_query
*wined3d_event_query_from_query(struct wined3d_query
*query
)
152 return CONTAINING_RECORD(query
, struct wined3d_event_query
, query
);
155 static struct wined3d_occlusion_query
*wined3d_occlusion_query_from_query(struct wined3d_query
*query
)
157 return CONTAINING_RECORD(query
, struct wined3d_occlusion_query
, query
);
160 static struct wined3d_timestamp_query
*wined3d_timestamp_query_from_query(struct wined3d_query
*query
)
162 return CONTAINING_RECORD(query
, struct wined3d_timestamp_query
, query
);
165 static struct wined3d_so_statistics_query
*wined3d_so_statistics_query_from_query(struct wined3d_query
*query
)
167 return CONTAINING_RECORD(query
, struct wined3d_so_statistics_query
, query
);
170 static struct wined3d_pipeline_statistics_query
*wined3d_pipeline_statistics_query_from_query(
171 struct wined3d_query
*query
)
173 return CONTAINING_RECORD(query
, struct wined3d_pipeline_statistics_query
, query
);
176 static BOOL
wined3d_fence_supported(const struct wined3d_gl_info
*gl_info
)
178 return gl_info
->supported
[ARB_SYNC
] || gl_info
->supported
[NV_FENCE
] || gl_info
->supported
[APPLE_FENCE
];
181 enum wined3d_fence_result
wined3d_fence_test(const struct wined3d_fence
*fence
,
182 struct wined3d_device
*device
, DWORD flags
)
184 const struct wined3d_gl_info
*gl_info
;
185 struct wined3d_context_gl
*context_gl
;
186 enum wined3d_fence_result ret
;
189 TRACE("fence %p, device %p, flags %#x.\n", fence
, device
, flags
);
191 if (!fence
->context_gl
)
193 TRACE("Fence not issued.\n");
194 return WINED3D_FENCE_NOT_STARTED
;
197 if (!(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
)))
199 if (!fence
->context_gl
->gl_info
->supported
[ARB_SYNC
])
201 WARN("Fence tested from wrong thread.\n");
202 return WINED3D_FENCE_WRONG_THREAD
;
204 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
206 gl_info
= context_gl
->gl_info
;
208 if (gl_info
->supported
[ARB_SYNC
])
210 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
211 (flags
& WINED3DGETDATA_FLUSH
) ? GL_SYNC_FLUSH_COMMANDS_BIT
: 0, 0));
212 checkGLcall("glClientWaitSync");
216 case GL_ALREADY_SIGNALED
:
217 case GL_CONDITION_SATISFIED
:
218 ret
= WINED3D_FENCE_OK
;
221 case GL_TIMEOUT_EXPIRED
:
222 ret
= WINED3D_FENCE_WAITING
;
227 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
228 ret
= WINED3D_FENCE_ERROR
;
231 else if (gl_info
->supported
[APPLE_FENCE
])
233 fence_result
= GL_EXTCALL(glTestFenceAPPLE(fence
->object
.id
));
234 checkGLcall("glTestFenceAPPLE");
236 ret
= WINED3D_FENCE_OK
;
238 ret
= WINED3D_FENCE_WAITING
;
240 else if (gl_info
->supported
[NV_FENCE
])
242 fence_result
= GL_EXTCALL(glTestFenceNV(fence
->object
.id
));
243 checkGLcall("glTestFenceNV");
245 ret
= WINED3D_FENCE_OK
;
247 ret
= WINED3D_FENCE_WAITING
;
251 ERR("Fence created despite lack of GL support.\n");
252 ret
= WINED3D_FENCE_ERROR
;
255 context_release(&context_gl
->c
);
259 enum wined3d_fence_result
wined3d_fence_wait(const struct wined3d_fence
*fence
,
260 struct wined3d_device
*device
)
262 const struct wined3d_gl_info
*gl_info
;
263 struct wined3d_context_gl
*context_gl
;
264 enum wined3d_fence_result ret
;
266 TRACE("fence %p, device %p.\n", fence
, device
);
268 if (!fence
->context_gl
)
270 TRACE("Fence not issued.\n");
271 return WINED3D_FENCE_NOT_STARTED
;
273 gl_info
= fence
->context_gl
->gl_info
;
275 if (!(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
)))
277 /* A glFinish does not reliably wait for draws in other contexts. The caller has
278 * to find its own way to cope with the thread switch
280 if (!gl_info
->supported
[ARB_SYNC
])
282 WARN("Fence finished from wrong thread.\n");
283 return WINED3D_FENCE_WRONG_THREAD
;
285 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
287 gl_info
= context_gl
->gl_info
;
289 if (gl_info
->supported
[ARB_SYNC
])
291 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
292 * possibly because macOS internally adds some slop to the timer. To avoid this,
293 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
295 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
296 GL_SYNC_FLUSH_COMMANDS_BIT
, ~(GLuint64
)0 >> 1));
297 checkGLcall("glClientWaitSync");
301 case GL_ALREADY_SIGNALED
:
302 case GL_CONDITION_SATISFIED
:
303 ret
= WINED3D_FENCE_OK
;
306 /* We don't expect a timeout for a ~292 year wait */
308 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
309 ret
= WINED3D_FENCE_ERROR
;
312 else if (gl_info
->supported
[APPLE_FENCE
])
314 GL_EXTCALL(glFinishFenceAPPLE(fence
->object
.id
));
315 checkGLcall("glFinishFenceAPPLE");
316 ret
= WINED3D_FENCE_OK
;
318 else if (gl_info
->supported
[NV_FENCE
])
320 GL_EXTCALL(glFinishFenceNV(fence
->object
.id
));
321 checkGLcall("glFinishFenceNV");
322 ret
= WINED3D_FENCE_OK
;
326 ERR("Fence created without GL support.\n");
327 ret
= WINED3D_FENCE_ERROR
;
330 context_release(&context_gl
->c
);
334 void wined3d_fence_issue(struct wined3d_fence
*fence
, struct wined3d_device
*device
)
336 struct wined3d_context_gl
*context_gl
= NULL
;
337 const struct wined3d_gl_info
*gl_info
;
339 if (fence
->context_gl
&& !(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
))
340 && !fence
->context_gl
->gl_info
->supported
[ARB_SYNC
])
341 wined3d_context_gl_free_fence(fence
);
343 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
344 gl_info
= context_gl
->gl_info
;
345 if (!fence
->context_gl
)
346 wined3d_context_gl_alloc_fence(context_gl
, fence
);
348 if (gl_info
->supported
[ARB_SYNC
])
350 if (fence
->object
.sync
)
351 GL_EXTCALL(glDeleteSync(fence
->object
.sync
));
352 checkGLcall("glDeleteSync");
353 fence
->object
.sync
= GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE
, 0));
354 checkGLcall("glFenceSync");
356 else if (gl_info
->supported
[APPLE_FENCE
])
358 GL_EXTCALL(glSetFenceAPPLE(fence
->object
.id
));
359 checkGLcall("glSetFenceAPPLE");
361 else if (gl_info
->supported
[NV_FENCE
])
363 GL_EXTCALL(glSetFenceNV(fence
->object
.id
, GL_ALL_COMPLETED_NV
));
364 checkGLcall("glSetFenceNV");
367 context_release(&context_gl
->c
);
370 static void wined3d_fence_free(struct wined3d_fence
*fence
)
372 if (fence
->context_gl
)
373 wined3d_context_gl_free_fence(fence
);
376 void wined3d_fence_destroy(struct wined3d_fence
*fence
)
378 wined3d_fence_free(fence
);
382 static HRESULT
wined3d_fence_init(struct wined3d_fence
*fence
, const struct wined3d_gl_info
*gl_info
)
384 if (!wined3d_fence_supported(gl_info
))
386 WARN("Fences not supported.\n");
387 return WINED3DERR_NOTAVAILABLE
;
393 HRESULT
wined3d_fence_create(struct wined3d_device
*device
, struct wined3d_fence
**fence
)
395 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
396 struct wined3d_fence
*object
;
399 TRACE("device %p, fence %p.\n", device
, fence
);
401 if (!(object
= heap_alloc_zero(sizeof(*object
))))
402 return E_OUTOFMEMORY
;
404 if (FAILED(hr
= wined3d_fence_init(object
, gl_info
)))
410 TRACE("Created fence %p.\n", object
);
416 ULONG CDECL
wined3d_query_incref(struct wined3d_query
*query
)
418 ULONG refcount
= InterlockedIncrement(&query
->ref
);
420 TRACE("%p increasing refcount to %u.\n", query
, refcount
);
425 static void wined3d_query_destroy_object(void *object
)
427 struct wined3d_query
*query
= object
;
429 TRACE("query %p.\n", query
);
431 if (!list_empty(&query
->poll_list_entry
))
432 list_remove(&query
->poll_list_entry
);
435 ULONG CDECL
wined3d_query_decref(struct wined3d_query
*query
)
437 ULONG refcount
= InterlockedDecrement(&query
->ref
);
439 TRACE("%p decreasing refcount to %u.\n", query
, refcount
);
443 struct wined3d_device
*device
= query
->device
;
445 wined3d_mutex_lock();
446 query
->parent_ops
->wined3d_object_destroyed(query
->parent
);
447 wined3d_cs_destroy_object(device
->cs
, wined3d_query_destroy_object
, query
);
448 device
->adapter
->adapter_ops
->adapter_destroy_query(query
);
449 wined3d_mutex_unlock();
455 HRESULT CDECL
wined3d_query_get_data(struct wined3d_query
*query
,
456 void *data
, UINT data_size
, DWORD flags
)
458 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
459 query
, data
, data_size
, flags
);
461 if (query
->state
== QUERY_BUILDING
)
463 WARN("Query is building, returning S_FALSE.\n");
467 if (query
->state
== QUERY_CREATED
)
469 WARN("Query wasn't started yet.\n");
470 return WINED3DERR_INVALIDCALL
;
473 if (query
->counter_main
!= query
->counter_retrieved
474 || (query
->buffer_object
&& !wined3d_query_buffer_is_valid(query
)))
476 if (flags
& WINED3DGETDATA_FLUSH
&& !query
->device
->cs
->queries_flushed
)
477 query
->device
->cs
->c
.ops
->flush(&query
->device
->cs
->c
);
480 else if (!query
->poll_in_cs
&& !query
->query_ops
->query_poll(query
, flags
))
485 if (query
->buffer_object
)
486 query
->data
= query
->map_ptr
;
489 memcpy(data
, query
->data
, min(data_size
, query
->data_size
));
494 UINT CDECL
wined3d_query_get_data_size(const struct wined3d_query
*query
)
496 TRACE("query %p.\n", query
);
498 return query
->data_size
;
501 HRESULT CDECL
wined3d_query_issue(struct wined3d_query
*query
, DWORD flags
)
503 TRACE("query %p, flags %#x.\n", query
, flags
);
505 wined3d_device_context_issue_query(&query
->device
->cs
->c
, query
, flags
);
510 static BOOL
wined3d_occlusion_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
512 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
513 const struct wined3d_gl_info
*gl_info
;
514 struct wined3d_context_gl
*context_gl
;
517 TRACE("query %p, flags %#x.\n", query
, flags
);
519 if (!(context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
521 FIXME("%p Wrong thread, returning 1.\n", query
);
525 gl_info
= context_gl
->gl_info
;
527 GL_EXTCALL(glGetQueryObjectuiv(oq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
528 TRACE("Available %#x.\n", available
);
532 oq
->samples
= get_query_result64(oq
->id
, gl_info
);
533 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq
->samples
));
536 checkGLcall("poll occlusion query");
537 context_release(&context_gl
->c
);
542 static BOOL
wined3d_event_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
544 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
545 enum wined3d_fence_result ret
;
547 TRACE("query %p, flags %#x.\n", query
, flags
);
549 ret
= wined3d_fence_test(&event_query
->fence
, query
->device
, flags
);
552 case WINED3D_FENCE_OK
:
553 case WINED3D_FENCE_NOT_STARTED
:
554 return event_query
->signalled
= TRUE
;
556 case WINED3D_FENCE_WAITING
:
557 return event_query
->signalled
= FALSE
;
559 case WINED3D_FENCE_WRONG_THREAD
:
560 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query
);
561 return event_query
->signalled
= TRUE
;
563 case WINED3D_FENCE_ERROR
:
564 ERR("The GL event query failed.\n");
565 return event_query
->signalled
= TRUE
;
568 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret
);
569 return event_query
->signalled
= TRUE
;
573 void * CDECL
wined3d_query_get_parent(const struct wined3d_query
*query
)
575 TRACE("query %p.\n", query
);
577 return query
->parent
;
580 enum wined3d_query_type CDECL
wined3d_query_get_type(const struct wined3d_query
*query
)
582 TRACE("query %p.\n", query
);
587 static BOOL
wined3d_event_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
589 TRACE("query %p, flags %#x.\n", query
, flags
);
591 if (flags
& WINED3DISSUE_END
)
593 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
595 wined3d_fence_issue(&event_query
->fence
, query
->device
);
598 else if (flags
& WINED3DISSUE_BEGIN
)
600 /* Started implicitly at query creation. */
601 ERR("Event query issued with START flag - what to do?\n");
607 static BOOL
wined3d_occlusion_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
609 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
610 struct wined3d_device
*device
= query
->device
;
611 const struct wined3d_gl_info
*gl_info
;
612 struct wined3d_context_gl
*context_gl
;
615 TRACE("query %p, flags %#x.\n", query
, flags
);
617 /* This is allowed according to MSDN and our tests. Reset the query and
619 if (flags
& WINED3DISSUE_BEGIN
)
623 if ((context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
625 gl_info
= context_gl
->gl_info
;
626 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
627 checkGLcall("glEndQuery()");
631 FIXME("Wrong thread, can't restart query.\n");
632 wined3d_context_gl_free_occlusion_query(oq
);
633 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
634 wined3d_context_gl_alloc_occlusion_query(context_gl
, oq
);
640 wined3d_context_gl_free_occlusion_query(oq
);
641 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
642 wined3d_context_gl_alloc_occlusion_query(context_gl
, oq
);
644 gl_info
= context_gl
->gl_info
;
646 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED
, oq
->id
));
647 checkGLcall("glBeginQuery()");
649 context_release(&context_gl
->c
);
652 if (flags
& WINED3DISSUE_END
)
654 /* MSDN says END on a non-building occlusion query returns an error,
655 * but our tests show that it returns OK. But OpenGL doesn't like it,
656 * so avoid generating an error. */
659 if ((context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
661 gl_info
= context_gl
->gl_info
;
662 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
663 checkGLcall("glEndQuery()");
664 wined3d_query_buffer_queue_result(context_gl
, query
, oq
->id
);
666 context_release(&context_gl
->c
);
671 FIXME("Wrong thread, can't end query.\n");
680 static BOOL
wined3d_timestamp_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
682 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
683 const struct wined3d_gl_info
*gl_info
;
684 struct wined3d_context_gl
*context_gl
;
688 TRACE("query %p, flags %#x.\n", query
, flags
);
690 if (!(context_gl
= wined3d_context_gl_reacquire(tq
->context_gl
)))
692 FIXME("%p Wrong thread, returning 1.\n", query
);
696 gl_info
= context_gl
->gl_info
;
698 GL_EXTCALL(glGetQueryObjectuiv(tq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
699 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
700 TRACE("available %#x.\n", available
);
704 GL_EXTCALL(glGetQueryObjectui64v(tq
->id
, GL_QUERY_RESULT
, ×tamp
));
705 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
706 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp
));
707 tq
->timestamp
= timestamp
;
710 context_release(&context_gl
->c
);
715 static BOOL
wined3d_timestamp_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
717 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
718 const struct wined3d_gl_info
*gl_info
;
719 struct wined3d_context_gl
*context_gl
;
721 TRACE("query %p, flags %#x.\n", query
, flags
);
723 if (flags
& WINED3DISSUE_BEGIN
)
725 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
727 if (flags
& WINED3DISSUE_END
)
730 wined3d_context_gl_free_timestamp_query(tq
);
731 context_gl
= wined3d_context_gl(context_acquire(query
->device
, NULL
, 0));
732 gl_info
= context_gl
->gl_info
;
733 wined3d_context_gl_alloc_timestamp_query(context_gl
, tq
);
734 GL_EXTCALL(glQueryCounter(tq
->id
, GL_TIMESTAMP
));
735 checkGLcall("glQueryCounter()");
736 context_release(&context_gl
->c
);
744 static BOOL
wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
746 TRACE("query %p, flags %#x.\n", query
, flags
);
751 static BOOL
wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
753 TRACE("query %p, flags %#x.\n", query
, flags
);
758 static BOOL
wined3d_so_statistics_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
760 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
761 GLuint written_available
, generated_available
;
762 const struct wined3d_gl_info
*gl_info
;
763 struct wined3d_context_gl
*context_gl
;
765 TRACE("query %p, flags %#x.\n", query
, flags
);
767 if (!(context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
769 FIXME("%p Wrong thread, returning 0 primitives.\n", query
);
770 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
773 gl_info
= context_gl
->gl_info
;
775 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.query
.written
,
776 GL_QUERY_RESULT_AVAILABLE
, &written_available
));
777 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.query
.generated
,
778 GL_QUERY_RESULT_AVAILABLE
, &generated_available
));
779 TRACE("Available %#x, %#x.\n", written_available
, generated_available
);
781 if (written_available
&& generated_available
)
783 pq
->statistics
.primitives_written
= get_query_result64(pq
->u
.query
.written
, gl_info
);
784 pq
->statistics
.primitives_generated
= get_query_result64(pq
->u
.query
.generated
, gl_info
);
785 TRACE("Returning %s, %s primitives.\n",
786 wine_dbgstr_longlong(pq
->statistics
.primitives_written
),
787 wine_dbgstr_longlong(pq
->statistics
.primitives_generated
));
790 checkGLcall("poll SO statistics query");
791 context_release(&context_gl
->c
);
793 return written_available
&& generated_available
;
796 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query
*query
,
797 struct wined3d_context_gl
*context_gl
)
799 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
801 if (gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
803 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
, query
->stream_idx
));
804 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED
, query
->stream_idx
));
808 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
));
809 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED
));
811 checkGLcall("end query");
814 static BOOL
wined3d_so_statistics_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
816 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
817 struct wined3d_device
*device
= query
->device
;
818 const struct wined3d_gl_info
*gl_info
;
819 struct wined3d_context_gl
*context_gl
;
822 TRACE("query %p, flags %#x.\n", query
, flags
);
824 if (flags
& WINED3DISSUE_BEGIN
)
828 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
830 wined3d_so_statistics_query_end(pq
, context_gl
);
834 FIXME("Wrong thread, can't restart query.\n");
835 wined3d_context_gl_free_so_statistics_query(pq
);
836 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
837 wined3d_context_gl_alloc_so_statistics_query(context_gl
, pq
);
843 wined3d_context_gl_free_so_statistics_query(pq
);
844 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
845 wined3d_context_gl_alloc_so_statistics_query(context_gl
, pq
);
847 gl_info
= context_gl
->gl_info
;
849 if (gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
851 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
,
852 pq
->stream_idx
, pq
->u
.query
.written
));
853 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED
,
854 pq
->stream_idx
, pq
->u
.query
.generated
));
858 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
,
859 pq
->u
.query
.written
));
860 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED
,
861 pq
->u
.query
.generated
));
863 checkGLcall("begin query");
865 context_release(&context_gl
->c
);
868 if (flags
& WINED3DISSUE_END
)
872 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
874 wined3d_so_statistics_query_end(pq
, context_gl
);
876 context_release(&context_gl
->c
);
881 FIXME("Wrong thread, can't end query.\n");
890 static BOOL
wined3d_pipeline_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
892 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
893 const struct wined3d_gl_info
*gl_info
;
894 struct wined3d_context_gl
*context_gl
;
898 TRACE("query %p, flags %#x.\n", query
, flags
);
900 if (!(context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
902 FIXME("%p Wrong thread.\n", query
);
903 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
906 gl_info
= context_gl
->gl_info
;
908 for (i
= 0; i
< ARRAY_SIZE(pq
->u
.id
); ++i
)
910 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.id
[i
], GL_QUERY_RESULT_AVAILABLE
, &available
));
917 pq
->statistics
.vertices_submitted
= get_query_result64(pq
->u
.query
.vertices
, gl_info
);
918 pq
->statistics
.primitives_submitted
= get_query_result64(pq
->u
.query
.primitives
, gl_info
);
919 pq
->statistics
.vs_invocations
= get_query_result64(pq
->u
.query
.vertex_shader
, gl_info
);
920 pq
->statistics
.hs_invocations
= get_query_result64(pq
->u
.query
.tess_control_shader
, gl_info
);
921 pq
->statistics
.ds_invocations
= get_query_result64(pq
->u
.query
.tess_eval_shader
, gl_info
);
922 pq
->statistics
.gs_invocations
= get_query_result64(pq
->u
.query
.geometry_shader
, gl_info
);
923 pq
->statistics
.gs_primitives
= get_query_result64(pq
->u
.query
.geometry_primitives
, gl_info
);
924 pq
->statistics
.ps_invocations
= get_query_result64(pq
->u
.query
.fragment_shader
, gl_info
);
925 pq
->statistics
.cs_invocations
= get_query_result64(pq
->u
.query
.compute_shader
, gl_info
);
926 pq
->statistics
.clipping_input_primitives
= get_query_result64(pq
->u
.query
.clipping_input
, gl_info
);
927 pq
->statistics
.clipping_output_primitives
= get_query_result64(pq
->u
.query
.clipping_output
, gl_info
);
930 checkGLcall("poll pipeline statistics query");
931 context_release(&context_gl
->c
);
935 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query
*query
,
936 struct wined3d_context_gl
*context_gl
)
938 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
940 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB
));
941 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB
));
942 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB
));
943 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB
));
944 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB
));
945 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS
));
946 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB
));
947 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB
));
948 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB
));
949 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB
));
950 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB
));
951 checkGLcall("end query");
954 static BOOL
wined3d_pipeline_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
956 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
957 struct wined3d_device
*device
= query
->device
;
958 const struct wined3d_gl_info
*gl_info
;
959 struct wined3d_context_gl
*context_gl
;
962 TRACE("query %p, flags %#x.\n", query
, flags
);
964 if (flags
& WINED3DISSUE_BEGIN
)
968 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
970 wined3d_pipeline_statistics_query_end(pq
, context_gl
);
974 FIXME("Wrong thread, can't restart query.\n");
975 wined3d_context_gl_free_pipeline_statistics_query(pq
);
976 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
977 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl
, pq
);
983 wined3d_context_gl_free_pipeline_statistics_query(pq
);
984 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
985 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl
, pq
);
987 gl_info
= context_gl
->gl_info
;
989 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB
, pq
->u
.query
.vertices
));
990 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB
, pq
->u
.query
.primitives
));
991 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.vertex_shader
));
992 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB
, pq
->u
.query
.tess_control_shader
));
993 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.tess_eval_shader
));
994 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS
, pq
->u
.query
.geometry_shader
));
995 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB
, pq
->u
.query
.geometry_primitives
));
996 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.fragment_shader
));
997 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.compute_shader
));
998 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB
, pq
->u
.query
.clipping_input
));
999 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB
, pq
->u
.query
.clipping_output
));
1000 checkGLcall("begin query");
1002 context_release(&context_gl
->c
);
1005 if (flags
& WINED3DISSUE_END
)
1009 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
1011 wined3d_pipeline_statistics_query_end(pq
, context_gl
);
1012 context_release(&context_gl
->c
);
1017 FIXME("Wrong thread, can't end query.\n");
1020 pq
->started
= FALSE
;
1026 static void wined3d_event_query_ops_destroy(struct wined3d_query
*query
)
1028 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
1030 wined3d_fence_free(&event_query
->fence
);
1031 heap_free(event_query
);
1034 static const struct wined3d_query_ops event_query_ops
=
1036 wined3d_event_query_ops_poll
,
1037 wined3d_event_query_ops_issue
,
1038 wined3d_event_query_ops_destroy
,
1041 static HRESULT
wined3d_event_query_create(struct wined3d_device
*device
,
1042 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1043 struct wined3d_query
**query
)
1045 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1046 struct wined3d_event_query
*object
;
1049 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1050 device
, type
, parent
, parent_ops
, query
);
1052 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1053 return E_OUTOFMEMORY
;
1055 if (FAILED(hr
= wined3d_fence_init(&object
->fence
, gl_info
)))
1057 WARN("Event queries not supported.\n");
1062 wined3d_query_init(&object
->query
, device
, type
, &object
->signalled
,
1063 sizeof(object
->signalled
), &event_query_ops
, parent
, parent_ops
);
1065 TRACE("Created query %p.\n", object
);
1066 *query
= &object
->query
;
1071 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query
*query
)
1073 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
1076 wined3d_context_gl_free_occlusion_query(oq
);
1080 static const struct wined3d_query_ops occlusion_query_ops
=
1082 wined3d_occlusion_query_ops_poll
,
1083 wined3d_occlusion_query_ops_issue
,
1084 wined3d_occlusion_query_ops_destroy
,
1087 static HRESULT
wined3d_occlusion_query_create(struct wined3d_device
*device
,
1088 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1089 struct wined3d_query
**query
)
1091 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1092 struct wined3d_occlusion_query
*object
;
1094 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1095 device
, type
, parent
, parent_ops
, query
);
1097 if (!gl_info
->supported
[ARB_OCCLUSION_QUERY
])
1099 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1100 return WINED3DERR_NOTAVAILABLE
;
1103 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1104 return E_OUTOFMEMORY
;
1106 wined3d_query_init(&object
->query
, device
, type
, &object
->samples
,
1107 sizeof(object
->samples
), &occlusion_query_ops
, parent
, parent_ops
);
1109 TRACE("Created query %p.\n", object
);
1110 *query
= &object
->query
;
1115 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query
*query
)
1117 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
1120 wined3d_context_gl_free_timestamp_query(tq
);
1124 static const struct wined3d_query_ops timestamp_query_ops
=
1126 wined3d_timestamp_query_ops_poll
,
1127 wined3d_timestamp_query_ops_issue
,
1128 wined3d_timestamp_query_ops_destroy
,
1131 static HRESULT
wined3d_timestamp_query_create(struct wined3d_device
*device
,
1132 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1133 struct wined3d_query
**query
)
1135 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1136 struct wined3d_timestamp_query
*object
;
1138 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1139 device
, type
, parent
, parent_ops
, query
);
1141 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1143 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1144 return WINED3DERR_NOTAVAILABLE
;
1147 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1148 return E_OUTOFMEMORY
;
1150 wined3d_query_init(&object
->query
, device
, type
, &object
->timestamp
,
1151 sizeof(object
->timestamp
), ×tamp_query_ops
, parent
, parent_ops
);
1153 TRACE("Created query %p.\n", object
);
1154 *query
= &object
->query
;
1159 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query
*query
)
1164 static const struct wined3d_query_ops timestamp_disjoint_query_ops
=
1166 wined3d_timestamp_disjoint_query_ops_poll
,
1167 wined3d_timestamp_disjoint_query_ops_issue
,
1168 wined3d_timestamp_disjoint_query_ops_destroy
,
1171 static HRESULT
wined3d_timestamp_disjoint_query_create(struct wined3d_device
*device
,
1172 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1173 struct wined3d_query
**query
)
1175 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1176 struct wined3d_query
*object
;
1178 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1179 device
, type
, parent
, parent_ops
, query
);
1181 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1183 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1184 return WINED3DERR_NOTAVAILABLE
;
1187 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1188 return E_OUTOFMEMORY
;
1190 if (type
== WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
)
1192 static const struct wined3d_query_data_timestamp_disjoint disjoint_data
= {1000 * 1000 * 1000, FALSE
};
1194 wined3d_query_init(object
, device
, type
, &disjoint_data
,
1195 sizeof(disjoint_data
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1199 static const UINT64 freq
= 1000 * 1000 * 1000;
1201 wined3d_query_init(object
, device
, type
, &freq
,
1202 sizeof(freq
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1205 TRACE("Created query %p.\n", object
);
1211 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query
*query
)
1213 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
1216 wined3d_context_gl_free_so_statistics_query(pq
);
1220 static const struct wined3d_query_ops so_statistics_query_ops
=
1222 wined3d_so_statistics_query_ops_poll
,
1223 wined3d_so_statistics_query_ops_issue
,
1224 wined3d_so_statistics_query_ops_destroy
,
1227 static HRESULT
wined3d_so_statistics_query_create(struct wined3d_device
*device
,
1228 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1229 struct wined3d_query
**query
)
1231 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1232 struct wined3d_so_statistics_query
*object
;
1233 unsigned int stream_idx
;
1235 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
<= type
&& type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1236 stream_idx
= type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
;
1237 else if (type
== WINED3D_QUERY_TYPE_SO_STATISTICS
)
1240 return WINED3DERR_NOTAVAILABLE
;
1242 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1243 device
, type
, parent
, parent_ops
, query
);
1245 if (!gl_info
->supported
[WINED3D_GL_PRIMITIVE_QUERY
])
1247 WARN("OpenGL implementation does not support primitive queries.\n");
1248 return WINED3DERR_NOTAVAILABLE
;
1250 if (stream_idx
&& !gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
1252 WARN("OpenGL implementation does not support indexed queries.\n");
1253 return WINED3DERR_NOTAVAILABLE
;
1256 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1257 return E_OUTOFMEMORY
;
1259 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1260 sizeof(object
->statistics
), &so_statistics_query_ops
, parent
, parent_ops
);
1261 object
->stream_idx
= stream_idx
;
1263 TRACE("Created query %p.\n", object
);
1264 *query
= &object
->query
;
1269 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query
*query
)
1271 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
1273 wined3d_context_gl_free_pipeline_statistics_query(pq
);
1277 static const struct wined3d_query_ops pipeline_query_ops
=
1279 wined3d_pipeline_query_ops_poll
,
1280 wined3d_pipeline_query_ops_issue
,
1281 wined3d_pipeline_query_ops_destroy
,
1284 static HRESULT
wined3d_pipeline_query_create(struct wined3d_device
*device
,
1285 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1286 struct wined3d_query
**query
)
1288 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1289 struct wined3d_pipeline_statistics_query
*object
;
1291 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1292 device
, type
, parent
, parent_ops
, query
);
1294 if (!gl_info
->supported
[ARB_PIPELINE_STATISTICS_QUERY
])
1296 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1297 return WINED3DERR_NOTAVAILABLE
;
1300 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1301 return E_OUTOFMEMORY
;
1303 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1304 sizeof(object
->statistics
), &pipeline_query_ops
, parent
, parent_ops
);
1306 TRACE("Created query %p.\n", object
);
1307 *query
= &object
->query
;
1312 HRESULT
wined3d_query_gl_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1313 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1315 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1316 device
, type
, parent
, parent_ops
, query
);
1320 case WINED3D_QUERY_TYPE_EVENT
:
1321 return wined3d_event_query_create(device
, type
, parent
, parent_ops
, query
);
1323 case WINED3D_QUERY_TYPE_OCCLUSION
:
1324 return wined3d_occlusion_query_create(device
, type
, parent
, parent_ops
, query
);
1326 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1327 return wined3d_timestamp_query_create(device
, type
, parent
, parent_ops
, query
);
1329 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1330 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ
:
1331 return wined3d_timestamp_disjoint_query_create(device
, type
, parent
, parent_ops
, query
);
1333 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1334 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1335 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1336 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1337 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1338 return wined3d_so_statistics_query_create(device
, type
, parent
, parent_ops
, query
);
1340 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1341 return wined3d_pipeline_query_create(device
, type
, parent
, parent_ops
, query
);
1344 FIXME("Unhandled query type %#x.\n", type
);
1345 return WINED3DERR_NOTAVAILABLE
;
1349 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk
*pool_vk
, size_t idx
,
1350 struct wined3d_context_vk
*context_vk
)
1352 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1353 * outside of a render pass. Queue the query to be reset at the very end of the current
1354 * command buffer instead. */
1355 wined3d_bitmap_set(pool_vk
->completed
, idx
);
1356 if (list_empty(&pool_vk
->completed_entry
))
1357 list_add_tail(&context_vk
->completed_query_pools
, &pool_vk
->completed_entry
);
1360 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk
*pool_vk
, size_t *idx
)
1362 if ((*idx
= wined3d_bitmap_ffz(pool_vk
->allocated
, WINED3D_QUERY_POOL_SIZE
, 0)) > WINED3D_QUERY_POOL_SIZE
)
1364 wined3d_bitmap_set(pool_vk
->allocated
, *idx
);
1369 void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk
*context_vk
, struct wined3d_query_pool_vk
*pool_vk
,
1370 uint32_t start
, uint32_t count
)
1372 unsigned int idx
, end
= start
+ count
;
1374 for (idx
= start
; idx
< end
; ++idx
)
1375 wined3d_bitmap_clear(pool_vk
->allocated
, idx
);
1377 if (list_empty(&pool_vk
->entry
))
1378 list_add_tail(pool_vk
->free_list
, &pool_vk
->entry
);
1381 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk
*pool_vk
, struct wined3d_context_vk
*context_vk
)
1383 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(context_vk
->c
.device
);
1384 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1386 VK_CALL(vkDestroyQueryPool(device_vk
->vk_device
, pool_vk
->vk_query_pool
, NULL
));
1387 if (pool_vk
->vk_event
)
1388 VK_CALL(vkDestroyEvent(device_vk
->vk_device
, pool_vk
->vk_event
, NULL
));
1389 list_remove(&pool_vk
->entry
);
1390 list_remove(&pool_vk
->completed_entry
);
1393 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk
*pool_vk
,
1394 struct wined3d_context_vk
*context_vk
, enum wined3d_query_type type
, struct list
*free_pools
)
1396 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(context_vk
->c
.device
);
1397 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1398 VkQueryPoolCreateInfo pool_info
;
1401 list_init(&pool_vk
->entry
);
1402 list_init(&pool_vk
->completed_entry
);
1403 pool_vk
->free_list
= free_pools
;
1405 pool_info
.sType
= VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO
;
1406 pool_info
.pNext
= NULL
;
1407 pool_info
.flags
= 0;
1408 pool_info
.queryCount
= WINED3D_QUERY_POOL_SIZE
;
1412 case WINED3D_QUERY_TYPE_OCCLUSION
:
1413 pool_info
.queryType
= VK_QUERY_TYPE_OCCLUSION
;
1414 pool_info
.pipelineStatistics
= 0;
1417 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1418 pool_info
.queryType
= VK_QUERY_TYPE_TIMESTAMP
;
1419 pool_info
.pipelineStatistics
= 0;
1422 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1423 pool_info
.queryType
= VK_QUERY_TYPE_PIPELINE_STATISTICS
;
1424 pool_info
.pipelineStatistics
= VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1425 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1426 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1427 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1428 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1429 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1430 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1431 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1432 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1433 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1434 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT
;
1437 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1438 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1439 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1440 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1441 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1442 pool_info
.queryType
= VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
;
1443 pool_info
.pipelineStatistics
= 0;
1447 FIXME("Unhandled query type %#x.\n", type
);
1451 if ((vr
= VK_CALL(vkCreateQueryPool(device_vk
->vk_device
, &pool_info
, NULL
, &pool_vk
->vk_query_pool
))) < 0)
1453 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr
));
1457 list_add_head(free_pools
, &pool_vk
->entry
);
1462 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk
*query_vk
,
1463 struct wined3d_device_vk
*device_vk
, const struct wined3d_query_pool_idx_vk
*pool_idx
)
1465 const struct wined3d_query_data_pipeline_statistics
*ps_tmp
;
1466 const struct wined3d_vk_info
*vk_info
= &device_vk
->vk_info
;
1467 struct wined3d_query_data_pipeline_statistics
*ps_result
;
1473 struct wined3d_query_data_pipeline_statistics pipeline_statistics
;
1474 struct wined3d_query_data_so_statistics so_statistics
;
1477 if (pool_idx
->pool_vk
->vk_event
)
1479 /* Check if the pool's initial reset command executed. */
1480 vr
= VK_CALL(vkGetEventStatus(device_vk
->vk_device
,
1481 pool_idx
->pool_vk
->vk_event
));
1482 if (vr
== VK_EVENT_RESET
)
1484 else if (vr
!= VK_EVENT_SET
)
1486 ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr
));
1491 if ((vr
= VK_CALL(vkGetQueryPoolResults(device_vk
->vk_device
, pool_idx
->pool_vk
->vk_query_pool
,
1492 pool_idx
->idx
, 1, sizeof(tmp
), &tmp
, sizeof(tmp
), VK_QUERY_RESULT_64_BIT
))) < 0)
1494 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr
));
1498 if (vr
== VK_NOT_READY
)
1501 result
= (void *)query_vk
->q
.data
;
1502 switch (query_vk
->q
.type
)
1504 case WINED3D_QUERY_TYPE_OCCLUSION
:
1505 result
->occlusion
+= tmp
.occlusion
;
1508 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1509 result
->timestamp
= tmp
.timestamp
;
1512 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1513 ps_result
= &result
->pipeline_statistics
;
1514 ps_tmp
= &tmp
.pipeline_statistics
;
1515 ps_result
->vertices_submitted
+= ps_tmp
->vertices_submitted
;
1516 ps_result
->primitives_submitted
+= ps_tmp
->primitives_submitted
;
1517 ps_result
->vs_invocations
+= ps_tmp
->vs_invocations
;
1518 ps_result
->gs_invocations
+= ps_tmp
->gs_invocations
;
1519 ps_result
->gs_primitives
+= ps_tmp
->gs_primitives
;
1520 ps_result
->clipping_input_primitives
+= ps_tmp
->clipping_input_primitives
;
1521 ps_result
->clipping_output_primitives
+= ps_tmp
->clipping_output_primitives
;
1522 ps_result
->ps_invocations
+= ps_tmp
->ps_invocations
;
1523 ps_result
->hs_invocations
+= ps_tmp
->hs_invocations
;
1524 ps_result
->ds_invocations
+= ps_tmp
->ds_invocations
;
1525 ps_result
->cs_invocations
+= ps_tmp
->cs_invocations
;
1528 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1529 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1530 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1531 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1532 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1533 result
->so_statistics
.primitives_written
+= tmp
.so_statistics
.primitives_written
;
1534 result
->so_statistics
.primitives_generated
+= tmp
.so_statistics
.primitives_generated
;
1538 FIXME("Unhandled query type %#x.\n", query_vk
->q
.type
);
1545 static void wined3d_query_vk_begin(struct wined3d_query_vk
*query_vk
,
1546 struct wined3d_context_vk
*context_vk
, VkCommandBuffer vk_command_buffer
)
1548 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1549 struct wined3d_query_pool_vk
*pool_vk
;
1552 pool_vk
= query_vk
->pool_idx
.pool_vk
;
1553 idx
= query_vk
->pool_idx
.idx
;
1555 if (query_vk
->q
.type
>= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1556 && query_vk
->q
.type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1557 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
,
1558 query_vk
->control_flags
, query_vk
->q
.type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
));
1560 VK_CALL(vkCmdBeginQuery(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
, query_vk
->control_flags
));
1561 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1564 static void wined3d_query_vk_end(struct wined3d_query_vk
*query_vk
,
1565 struct wined3d_context_vk
*context_vk
, VkCommandBuffer vk_command_buffer
)
1567 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1568 struct wined3d_query_pool_vk
*pool_vk
;
1571 pool_vk
= query_vk
->pool_idx
.pool_vk
;
1572 idx
= query_vk
->pool_idx
.idx
;
1574 if (query_vk
->q
.type
>= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1575 && query_vk
->q
.type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1576 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer
, pool_vk
->vk_query_pool
,
1577 idx
, query_vk
->q
.type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
));
1579 VK_CALL(vkCmdEndQuery(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
));
1582 void wined3d_query_vk_resume(struct wined3d_query_vk
*query_vk
, struct wined3d_context_vk
*context_vk
)
1584 VkCommandBuffer vk_command_buffer
= context_vk
->current_command_buffer
.vk_command_buffer
;
1586 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1587 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
;
1590 void wined3d_query_vk_suspend(struct wined3d_query_vk
*query_vk
, struct wined3d_context_vk
*context_vk
)
1592 VkCommandBuffer vk_command_buffer
= context_vk
->current_command_buffer
.vk_command_buffer
;
1594 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1596 if (!wined3d_array_reserve((void **)&query_vk
->pending
, &query_vk
->pending_size
,
1597 query_vk
->pending_count
+ 1, sizeof(*query_vk
->pending
)))
1599 ERR("Failed to allocate entry.\n");
1603 query_vk
->pending
[query_vk
->pending_count
++] = query_vk
->pool_idx
;
1604 query_vk
->pool_idx
.pool_vk
= NULL
;
1605 query_vk
->flags
&= ~WINED3D_QUERY_VK_FLAG_ACTIVE
;
1608 static BOOL
wined3d_query_vk_poll(struct wined3d_query
*query
, uint32_t flags
)
1610 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1611 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1614 memset((void *)query
->data
, 0, query
->data_size
);
1616 if (query_vk
->pool_idx
.pool_vk
&& !wined3d_query_vk_accumulate_data(query_vk
, device_vk
, &query_vk
->pool_idx
))
1619 for (i
= 0; i
< query_vk
->pending_count
; ++i
)
1621 if (!wined3d_query_vk_accumulate_data(query_vk
, device_vk
, &query_vk
->pending
[i
]))
1628 if ((flags
& WINED3DGETDATA_FLUSH
) && !query
->device
->cs
->queries_flushed
)
1629 query
->device
->cs
->c
.ops
->flush(&query
->device
->cs
->c
);
1634 static void wined3d_query_vk_remove_pending_queries(struct wined3d_context_vk
*context_vk
,
1635 struct wined3d_query_vk
*query_vk
)
1639 for (i
= 0; i
< query_vk
->pending_count
; ++i
)
1640 wined3d_query_pool_vk_mark_complete(query_vk
->pending
[i
].pool_vk
, query_vk
->pending
[i
].idx
, context_vk
);
1642 query_vk
->pending_count
= 0;
1645 static BOOL
wined3d_query_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1647 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1648 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1649 struct wined3d_context_vk
*context_vk
;
1650 VkCommandBuffer vk_command_buffer
;
1653 TRACE("query %p, flags %#x.\n", query
, flags
);
1655 if (flags
& WINED3DISSUE_BEGIN
)
1657 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1659 if (query_vk
->pending_count
)
1660 wined3d_query_vk_remove_pending_queries(context_vk
, query_vk
);
1661 vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1662 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1664 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_ACTIVE
)
1665 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1666 list_remove(&query_vk
->entry
);
1668 if (query_vk
->pool_idx
.pool_vk
)
1669 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
,
1670 query_vk
->pool_idx
.idx
, context_vk
);
1672 if (!wined3d_context_vk_allocate_query(context_vk
, query_vk
->q
.type
, &query_vk
->pool_idx
))
1674 ERR("Failed to allocate new query.\n");
1678 /* A query needs to either begin and end inside a single render pass
1679 * or begin and end outside of a render pass. Occlusion queries, if
1680 * issued outside of a render pass, are queued up and only begun when
1681 * a render pass is started, to avoid interrupting the render pass
1682 * when the query ends. */
1683 if (context_vk
->vk_render_pass
)
1685 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1686 list_add_head(&context_vk
->render_pass_queries
, &query_vk
->entry
);
1687 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
| WINED3D_QUERY_VK_FLAG_RENDER_PASS
;
1689 else if (query
->type
== WINED3D_QUERY_TYPE_OCCLUSION
)
1691 list_add_head(&context_vk
->render_pass_queries
, &query_vk
->entry
);
1692 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_RENDER_PASS
;
1696 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1697 list_add_head(&context_vk
->active_queries
, &query_vk
->entry
);
1698 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
;
1701 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_STARTED
;
1702 context_release(&context_vk
->c
);
1704 if (flags
& WINED3DISSUE_END
&& query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1706 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1708 /* If the query was already ended because the command buffer was
1709 * flushed or the render pass ended, we don't need to end it here. */
1710 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_ACTIVE
)
1712 vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1713 if (!(query_vk
->flags
& WINED3D_QUERY_VK_FLAG_RENDER_PASS
))
1714 wined3d_context_vk_end_current_render_pass(context_vk
);
1715 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1717 else if (query_vk
->pool_idx
.pool_vk
)
1719 /* It was queued, but never activated. */
1720 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
,
1721 query_vk
->pool_idx
.idx
, context_vk
);
1722 query_vk
->pool_idx
.pool_vk
= NULL
;
1724 list_remove(&query_vk
->entry
);
1725 query_vk
->flags
= 0;
1728 context_release(&context_vk
->c
);
1734 static void wined3d_query_vk_destroy(struct wined3d_query
*query
)
1736 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1737 struct wined3d_context_vk
*context_vk
;
1739 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1740 list_remove(&query_vk
->entry
);
1741 context_vk
= wined3d_context_vk(context_acquire(query_vk
->q
.device
, NULL
, 0));
1742 wined3d_query_vk_remove_pending_queries(context_vk
, query_vk
);
1743 if (query_vk
->pool_idx
.pool_vk
)
1744 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
, query_vk
->pool_idx
.idx
, context_vk
);
1745 if (query_vk
->vk_event
)
1746 wined3d_context_vk_destroy_vk_event(context_vk
, query_vk
->vk_event
, query_vk
->command_buffer_id
);
1747 context_release(&context_vk
->c
);
1748 heap_free(query_vk
->pending
);
1749 heap_free(query_vk
);
1752 static const struct wined3d_query_ops wined3d_query_vk_ops
=
1754 .query_poll
= wined3d_query_vk_poll
,
1755 .query_issue
= wined3d_query_vk_issue
,
1756 .query_destroy
= wined3d_query_vk_destroy
,
1759 static BOOL
wined3d_query_event_vk_poll(struct wined3d_query
*query
, uint32_t flags
)
1761 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1762 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1763 const struct wined3d_vk_info
*vk_info
= &device_vk
->vk_info
;
1766 signalled
= VK_CALL(vkGetEventStatus(device_vk
->vk_device
, query_vk
->vk_event
))
1768 if (!signalled
&& (flags
& WINED3DGETDATA_FLUSH
) && !query
->device
->cs
->queries_flushed
)
1769 query
->device
->cs
->c
.ops
->flush(&query
->device
->cs
->c
);
1770 return *(BOOL
*)query
->data
= signalled
;
1773 static BOOL
wined3d_query_event_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1775 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1776 const struct wined3d_vk_info
*vk_info
= &device_vk
->vk_info
;
1777 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1778 struct wined3d_context_vk
*context_vk
;
1779 VkEventCreateInfo create_info
;
1782 TRACE("query %p, flags %#x.\n", query
, flags
);
1784 if (flags
& WINED3DISSUE_END
)
1786 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1787 wined3d_context_vk_end_current_render_pass(context_vk
);
1789 if (query_vk
->vk_event
)
1791 if (query_vk
->command_buffer_id
> context_vk
->completed_command_buffer_id
)
1793 /* Cannot reuse this event, as it may still get signalled by previous usage. */
1794 /* Throw it away and create a new one, but if that happens a lot we may want to pool instead. */
1795 wined3d_context_vk_destroy_vk_event(context_vk
, query_vk
->vk_event
, query_vk
->command_buffer_id
);
1796 query_vk
->vk_event
= VK_NULL_HANDLE
;
1800 VK_CALL(vkResetEvent(device_vk
->vk_device
, query_vk
->vk_event
));
1804 if (!query_vk
->vk_event
)
1806 create_info
.sType
= VK_STRUCTURE_TYPE_EVENT_CREATE_INFO
;
1807 create_info
.pNext
= NULL
;
1808 create_info
.flags
= 0;
1810 vr
= VK_CALL(vkCreateEvent(device_vk
->vk_device
, &create_info
, NULL
, &query_vk
->vk_event
));
1811 if (vr
!= VK_SUCCESS
)
1813 ERR("Failed to create Vulkan event, vr %s\n", wined3d_debug_vkresult(vr
));
1814 context_release(&context_vk
->c
);
1819 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1820 VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk
), query_vk
->vk_event
,
1821 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
));
1822 context_release(&context_vk
->c
);
1830 static const struct wined3d_query_ops wined3d_query_event_vk_ops
=
1832 .query_poll
= wined3d_query_event_vk_poll
,
1833 .query_issue
= wined3d_query_event_vk_issue
,
1834 .query_destroy
= wined3d_query_vk_destroy
,
1837 static BOOL
wined3d_query_timestamp_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1839 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1840 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1841 const struct wined3d_vk_info
*vk_info
;
1842 struct wined3d_context_vk
*context_vk
;
1843 VkCommandBuffer command_buffer
;
1845 TRACE("query %p, flags %#x.\n", query
, flags
);
1847 if (flags
& WINED3DISSUE_BEGIN
)
1848 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1850 if (flags
& WINED3DISSUE_END
)
1852 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1853 vk_info
= context_vk
->vk_info
;
1855 command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1856 if (query_vk
->pool_idx
.pool_vk
)
1857 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
, query_vk
->pool_idx
.idx
, context_vk
);
1858 if (!wined3d_context_vk_allocate_query(context_vk
, query_vk
->q
.type
, &query_vk
->pool_idx
))
1860 ERR("Failed to allocate new query.\n");
1863 VK_CALL(vkCmdWriteTimestamp(command_buffer
, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
,
1864 query_vk
->pool_idx
.pool_vk
->vk_query_pool
, query_vk
->pool_idx
.idx
));
1865 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1867 context_release(&context_vk
->c
);
1875 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops
=
1877 .query_poll
= wined3d_query_vk_poll
,
1878 .query_issue
= wined3d_query_timestamp_vk_issue
,
1879 .query_destroy
= wined3d_query_vk_destroy
,
1882 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops
=
1884 .query_poll
= wined3d_timestamp_disjoint_query_ops_poll
,
1885 .query_issue
= wined3d_timestamp_disjoint_query_ops_issue
,
1886 .query_destroy
= wined3d_query_vk_destroy
,
1889 HRESULT
wined3d_query_vk_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1890 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1892 struct wined3d_query_data_timestamp_disjoint
*disjoint_data
;
1893 const struct wined3d_query_ops
*ops
= &wined3d_query_vk_ops
;
1894 struct wined3d_query_vk
*query_vk
;
1895 unsigned int data_size
;
1898 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1899 device
, type
, parent
, parent_ops
, query
);
1903 case WINED3D_QUERY_TYPE_EVENT
:
1904 ops
= &wined3d_query_event_vk_ops
;
1905 data_size
= sizeof(BOOL
);
1908 case WINED3D_QUERY_TYPE_OCCLUSION
:
1909 data_size
= sizeof(uint64_t);
1912 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1913 if (!wined3d_device_vk(device
)->timestamp_bits
)
1915 WARN("Timestamp queries not supported.\n");
1916 return WINED3DERR_NOTAVAILABLE
;
1918 ops
= &wined3d_query_timestamp_vk_ops
;
1919 data_size
= sizeof(uint64_t);
1922 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1923 if (!wined3d_device_vk(device
)->timestamp_bits
)
1925 WARN("Timestamp queries not supported.\n");
1926 return WINED3DERR_NOTAVAILABLE
;
1928 ops
= &wined3d_query_timestamp_disjoint_vk_ops
;
1929 data_size
= sizeof(struct wined3d_query_data_timestamp_disjoint
);
1932 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1933 data_size
= sizeof(struct wined3d_query_data_pipeline_statistics
);
1936 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1937 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1938 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1939 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1940 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1941 if (!wined3d_adapter_vk(device
->adapter
)->vk_info
.supported
[WINED3D_VK_EXT_TRANSFORM_FEEDBACK
])
1943 WARN("Stream output queries not supported.\n");
1944 return WINED3DERR_NOTAVAILABLE
;
1946 data_size
= sizeof(struct wined3d_query_data_so_statistics
);
1950 FIXME("Unhandled query type %#x.\n", type
);
1951 return WINED3DERR_NOTAVAILABLE
;
1954 if (!(query_vk
= heap_alloc_zero(sizeof(*query_vk
) + data_size
)))
1955 return E_OUTOFMEMORY
;
1956 data
= query_vk
+ 1;
1958 wined3d_query_init(&query_vk
->q
, device
, type
, data
, data_size
, ops
, parent
, parent_ops
);
1959 query_vk
->q
.poll_in_cs
= false;
1963 case WINED3D_QUERY_TYPE_OCCLUSION
:
1964 query_vk
->control_flags
= VK_QUERY_CONTROL_PRECISE_BIT
;
1967 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1968 disjoint_data
= data
;
1969 disjoint_data
->frequency
= 1000000000 / wined3d_adapter_vk(device
->adapter
)->device_limits
.timestampPeriod
;
1970 disjoint_data
->disjoint
= FALSE
;
1977 TRACE("Created query %p.\n", query_vk
);
1978 *query
= &query_vk
->q
;
1983 HRESULT CDECL
wined3d_query_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1984 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1986 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1987 device
, type
, parent
, parent_ops
, query
);
1989 return device
->adapter
->adapter_ops
->adapter_create_query(device
, type
, parent
, parent_ops
, query
);