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"
22 #include "wined3d_gl.h"
23 #include "wined3d_vk.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
27 static void wined3d_query_buffer_invalidate(struct wined3d_query
*query
)
29 /* map[0] != map[1]: exact values do not have any significance. */
30 query
->map_ptr
[0] = 0;
31 query
->map_ptr
[1] = ~(UINT64
)0;
34 static BOOL
wined3d_query_buffer_is_valid(struct wined3d_query
*query
)
36 return query
->map_ptr
[0] == query
->map_ptr
[1];
39 static void wined3d_query_create_buffer_object(struct wined3d_context_gl
*context_gl
, struct wined3d_query
*query
)
41 const GLuint map_flags
= GL_MAP_READ_BIT
| GL_MAP_WRITE_BIT
| GL_MAP_PERSISTENT_BIT
| GL_MAP_COHERENT_BIT
;
42 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
45 GL_EXTCALL(glGenBuffers(1, &buffer_object
));
46 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, buffer_object
));
47 GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER
, sizeof(query
->map_ptr
[0]) * 2, NULL
, map_flags
));
48 query
->map_ptr
= GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER
, 0, sizeof(query
->map_ptr
[0]) * 2, map_flags
));
49 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, 0));
50 checkGLcall("query buffer object creation");
52 wined3d_query_buffer_invalidate(query
);
53 query
->buffer_object
= buffer_object
;
56 void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl
*context_gl
, struct wined3d_query
*query
)
58 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
60 GL_EXTCALL(glDeleteBuffers(1, &query
->buffer_object
));
61 checkGLcall("query buffer object destruction");
63 query
->buffer_object
= 0;
64 query
->map_ptr
= NULL
;
67 /* From ARB_occlusion_query: "Querying the state for a given occlusion query
68 * forces that occlusion query to complete within a finite amount of time."
69 * In practice, that means drivers flush when retrieving
70 * GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
71 * significant number of queries. Using a persistently mapped query buffer
72 * object allows us to avoid these implicit flushes. An additional benefit is
73 * that it allows us to poll the query status from the application-thread
74 * instead of from the csmt-thread. */
75 static BOOL
wined3d_query_buffer_queue_result(struct wined3d_context_gl
*context_gl
,
76 struct wined3d_query
*query
, GLuint id
)
78 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
81 if (!gl_info
->supported
[ARB_QUERY_BUFFER_OBJECT
] || !gl_info
->supported
[ARB_BUFFER_STORAGE
])
83 /* Don't use query buffers without CSMT, mainly for simplicity. */
84 if (!context_gl
->c
.device
->cs
->thread
)
87 if (query
->buffer_object
)
89 /* If there's still a query result in-flight for the existing buffer
90 * object (i.e., the query was restarted before we received its
91 * result), we can't reuse the existing buffer object. */
92 if (wined3d_query_buffer_is_valid(query
))
93 wined3d_query_buffer_invalidate(query
);
95 wined3d_query_gl_destroy_buffer_object(context_gl
, query
);
98 if (!query
->buffer_object
)
99 wined3d_query_create_buffer_object(context_gl
, query
);
101 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, query
->buffer_object
));
102 /* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
103 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, (void *)0));
104 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, (void *)sizeof(query
->map_ptr
[0])));
105 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, 0));
106 checkGLcall("queue query result");
108 /* ARB_buffer_storage requires the client to call FenceSync with
109 * SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
110 * is not enforced by Mesa.
112 tmp_sync
= GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE
, 0));
113 GL_EXTCALL(glDeleteSync(tmp_sync
));
114 checkGLcall("query buffer sync");
119 static UINT64
get_query_result64(GLuint id
, const struct wined3d_gl_info
*gl_info
)
121 if (gl_info
->supported
[ARB_TIMER_QUERY
])
124 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, &result
));
130 GL_EXTCALL(glGetQueryObjectuiv(id
, GL_QUERY_RESULT
, &result
));
135 static void wined3d_query_init(struct wined3d_query
*query
, struct wined3d_device
*device
,
136 enum wined3d_query_type type
, const void *data
, DWORD data_size
,
137 const struct wined3d_query_ops
*query_ops
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
140 query
->parent
= parent
;
141 query
->parent_ops
= parent_ops
;
142 query
->device
= device
;
143 query
->state
= QUERY_CREATED
;
146 query
->data_size
= data_size
;
147 query
->query_ops
= query_ops
;
148 query
->poll_in_cs
= !!device
->cs
->thread
;
149 list_init(&query
->poll_list_entry
);
152 static struct wined3d_event_query
*wined3d_event_query_from_query(struct wined3d_query
*query
)
154 return CONTAINING_RECORD(query
, struct wined3d_event_query
, query
);
157 static struct wined3d_occlusion_query
*wined3d_occlusion_query_from_query(struct wined3d_query
*query
)
159 return CONTAINING_RECORD(query
, struct wined3d_occlusion_query
, query
);
162 static struct wined3d_timestamp_query
*wined3d_timestamp_query_from_query(struct wined3d_query
*query
)
164 return CONTAINING_RECORD(query
, struct wined3d_timestamp_query
, query
);
167 static struct wined3d_so_statistics_query
*wined3d_so_statistics_query_from_query(struct wined3d_query
*query
)
169 return CONTAINING_RECORD(query
, struct wined3d_so_statistics_query
, query
);
172 static struct wined3d_pipeline_statistics_query
*wined3d_pipeline_statistics_query_from_query(
173 struct wined3d_query
*query
)
175 return CONTAINING_RECORD(query
, struct wined3d_pipeline_statistics_query
, query
);
178 enum wined3d_fence_result
wined3d_fence_test(const struct wined3d_fence
*fence
,
179 struct wined3d_device
*device
, uint32_t flags
)
181 const struct wined3d_gl_info
*gl_info
;
182 struct wined3d_context_gl
*context_gl
;
183 enum wined3d_fence_result ret
;
186 TRACE("fence %p, device %p, flags %#x.\n", fence
, device
, flags
);
188 if (!fence
->context_gl
)
190 TRACE("Fence not issued.\n");
191 return WINED3D_FENCE_NOT_STARTED
;
194 if (!(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
)))
196 if (!fence
->context_gl
->gl_info
->supported
[ARB_SYNC
])
198 WARN("Fence tested from wrong thread.\n");
199 return WINED3D_FENCE_WRONG_THREAD
;
201 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
203 gl_info
= context_gl
->gl_info
;
205 if (gl_info
->supported
[ARB_SYNC
])
207 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
208 (flags
& WINED3DGETDATA_FLUSH
) ? GL_SYNC_FLUSH_COMMANDS_BIT
: 0, 0));
209 checkGLcall("glClientWaitSync");
213 case GL_ALREADY_SIGNALED
:
214 case GL_CONDITION_SATISFIED
:
215 ret
= WINED3D_FENCE_OK
;
218 case GL_TIMEOUT_EXPIRED
:
219 ret
= WINED3D_FENCE_WAITING
;
224 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
225 ret
= WINED3D_FENCE_ERROR
;
228 else if (gl_info
->supported
[APPLE_FENCE
])
230 fence_result
= GL_EXTCALL(glTestFenceAPPLE(fence
->object
.id
));
231 checkGLcall("glTestFenceAPPLE");
233 ret
= WINED3D_FENCE_OK
;
235 ret
= WINED3D_FENCE_WAITING
;
237 else if (gl_info
->supported
[NV_FENCE
])
239 fence_result
= GL_EXTCALL(glTestFenceNV(fence
->object
.id
));
240 checkGLcall("glTestFenceNV");
242 ret
= WINED3D_FENCE_OK
;
244 ret
= WINED3D_FENCE_WAITING
;
248 ERR("Fence created despite lack of GL support.\n");
249 ret
= WINED3D_FENCE_ERROR
;
252 context_release(&context_gl
->c
);
256 enum wined3d_fence_result
wined3d_fence_wait(const struct wined3d_fence
*fence
,
257 struct wined3d_device
*device
)
259 const struct wined3d_gl_info
*gl_info
;
260 struct wined3d_context_gl
*context_gl
;
261 enum wined3d_fence_result ret
;
263 TRACE("fence %p, device %p.\n", fence
, device
);
265 if (!fence
->context_gl
)
267 TRACE("Fence not issued.\n");
268 return WINED3D_FENCE_NOT_STARTED
;
270 gl_info
= fence
->context_gl
->gl_info
;
272 if (!(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
)))
274 /* A glFinish does not reliably wait for draws in other contexts. The caller has
275 * to find its own way to cope with the thread switch
277 if (!gl_info
->supported
[ARB_SYNC
])
279 WARN("Fence finished from wrong thread.\n");
280 return WINED3D_FENCE_WRONG_THREAD
;
282 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
284 gl_info
= context_gl
->gl_info
;
286 if (gl_info
->supported
[ARB_SYNC
])
288 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
289 * possibly because macOS internally adds some slop to the timer. To avoid this,
290 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
292 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
293 GL_SYNC_FLUSH_COMMANDS_BIT
, ~(GLuint64
)0 >> 1));
294 checkGLcall("glClientWaitSync");
298 case GL_ALREADY_SIGNALED
:
299 case GL_CONDITION_SATISFIED
:
300 ret
= WINED3D_FENCE_OK
;
303 /* We don't expect a timeout for a ~292 year wait */
305 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
306 ret
= WINED3D_FENCE_ERROR
;
309 else if (gl_info
->supported
[APPLE_FENCE
])
311 GL_EXTCALL(glFinishFenceAPPLE(fence
->object
.id
));
312 checkGLcall("glFinishFenceAPPLE");
313 ret
= WINED3D_FENCE_OK
;
315 else if (gl_info
->supported
[NV_FENCE
])
317 GL_EXTCALL(glFinishFenceNV(fence
->object
.id
));
318 checkGLcall("glFinishFenceNV");
319 ret
= WINED3D_FENCE_OK
;
323 ERR("Fence created without GL support.\n");
324 ret
= WINED3D_FENCE_ERROR
;
327 context_release(&context_gl
->c
);
331 void wined3d_fence_issue(struct wined3d_fence
*fence
, struct wined3d_device
*device
)
333 struct wined3d_context_gl
*context_gl
= NULL
;
334 const struct wined3d_gl_info
*gl_info
;
336 if (fence
->context_gl
&& !(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
))
337 && !fence
->context_gl
->gl_info
->supported
[ARB_SYNC
])
338 wined3d_context_gl_free_fence(fence
);
340 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
341 gl_info
= context_gl
->gl_info
;
342 if (!fence
->context_gl
)
343 wined3d_context_gl_alloc_fence(context_gl
, fence
);
345 if (gl_info
->supported
[ARB_SYNC
])
347 if (fence
->object
.sync
)
348 GL_EXTCALL(glDeleteSync(fence
->object
.sync
));
349 checkGLcall("glDeleteSync");
350 fence
->object
.sync
= GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE
, 0));
351 checkGLcall("glFenceSync");
353 else if (gl_info
->supported
[APPLE_FENCE
])
355 GL_EXTCALL(glSetFenceAPPLE(fence
->object
.id
));
356 checkGLcall("glSetFenceAPPLE");
358 else if (gl_info
->supported
[NV_FENCE
])
360 GL_EXTCALL(glSetFenceNV(fence
->object
.id
, GL_ALL_COMPLETED_NV
));
361 checkGLcall("glSetFenceNV");
364 context_release(&context_gl
->c
);
367 static void wined3d_fence_free(struct wined3d_fence
*fence
)
369 if (fence
->context_gl
)
370 wined3d_context_gl_free_fence(fence
);
373 void wined3d_fence_destroy(struct wined3d_fence
*fence
)
375 wined3d_fence_free(fence
);
379 static HRESULT
wined3d_fence_init(struct wined3d_fence
*fence
, const struct wined3d_gl_info
*gl_info
)
381 if (!wined3d_fence_supported(gl_info
))
383 WARN("Fences not supported.\n");
384 return WINED3DERR_NOTAVAILABLE
;
390 HRESULT
wined3d_fence_create(struct wined3d_device
*device
, struct wined3d_fence
**fence
)
392 const struct wined3d_gl_info
*gl_info
= &wined3d_adapter_gl(device
->adapter
)->gl_info
;
393 struct wined3d_fence
*object
;
396 TRACE("device %p, fence %p.\n", device
, fence
);
398 if (!(object
= heap_alloc_zero(sizeof(*object
))))
399 return E_OUTOFMEMORY
;
401 if (FAILED(hr
= wined3d_fence_init(object
, gl_info
)))
407 TRACE("Created fence %p.\n", object
);
413 ULONG CDECL
wined3d_query_incref(struct wined3d_query
*query
)
415 unsigned int refcount
= InterlockedIncrement(&query
->ref
);
417 TRACE("%p increasing refcount to %u.\n", query
, refcount
);
422 static void wined3d_query_destroy_object(void *object
)
424 struct wined3d_query
*query
= object
;
426 TRACE("query %p.\n", query
);
428 if (!list_empty(&query
->poll_list_entry
))
429 list_remove(&query
->poll_list_entry
);
432 ULONG CDECL
wined3d_query_decref(struct wined3d_query
*query
)
434 unsigned int refcount
= InterlockedDecrement(&query
->ref
);
436 TRACE("%p decreasing refcount to %u.\n", query
, refcount
);
440 struct wined3d_device
*device
= query
->device
;
442 wined3d_mutex_lock();
443 query
->parent_ops
->wined3d_object_destroyed(query
->parent
);
444 wined3d_cs_destroy_object(device
->cs
, wined3d_query_destroy_object
, query
);
445 device
->adapter
->adapter_ops
->adapter_destroy_query(query
);
446 wined3d_mutex_unlock();
452 HRESULT CDECL
wined3d_query_get_data(struct wined3d_query
*query
,
453 void *data
, UINT data_size
, uint32_t flags
)
455 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
456 query
, data
, data_size
, flags
);
458 if (query
->state
== QUERY_BUILDING
)
460 WARN("Query is building, returning S_FALSE.\n");
464 if (query
->state
== QUERY_CREATED
)
466 WARN("Query wasn't started yet.\n");
467 return WINED3DERR_INVALIDCALL
;
470 if (query
->counter_main
!= query
->counter_retrieved
471 || (query
->buffer_object
&& !wined3d_query_buffer_is_valid(query
)))
473 if (flags
& WINED3DGETDATA_FLUSH
&& !query
->device
->cs
->queries_flushed
)
474 query
->device
->cs
->c
.ops
->flush(&query
->device
->cs
->c
);
477 else if (!query
->poll_in_cs
&& !query
->query_ops
->query_poll(query
, flags
))
482 if (query
->buffer_object
)
483 query
->data
= query
->map_ptr
;
486 memcpy(data
, query
->data
, min(data_size
, query
->data_size
));
491 UINT CDECL
wined3d_query_get_data_size(const struct wined3d_query
*query
)
493 TRACE("query %p.\n", query
);
495 return query
->data_size
;
498 HRESULT CDECL
wined3d_query_issue(struct wined3d_query
*query
, uint32_t flags
)
500 TRACE("query %p, flags %#x.\n", query
, flags
);
502 wined3d_device_context_issue_query(&query
->device
->cs
->c
, query
, flags
);
507 static BOOL
wined3d_occlusion_query_ops_poll(struct wined3d_query
*query
, uint32_t flags
)
509 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
510 const struct wined3d_gl_info
*gl_info
;
511 struct wined3d_context_gl
*context_gl
;
514 TRACE("query %p, flags %#x.\n", query
, flags
);
516 if (!(context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
518 FIXME("%p Wrong thread, returning 1.\n", query
);
522 gl_info
= context_gl
->gl_info
;
524 GL_EXTCALL(glGetQueryObjectuiv(oq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
525 TRACE("Available %#x.\n", available
);
529 oq
->samples
= get_query_result64(oq
->id
, gl_info
);
530 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq
->samples
));
533 checkGLcall("poll occlusion query");
534 context_release(&context_gl
->c
);
539 static BOOL
wined3d_event_query_ops_poll(struct wined3d_query
*query
, uint32_t flags
)
541 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
542 enum wined3d_fence_result ret
;
544 TRACE("query %p, flags %#x.\n", query
, flags
);
546 ret
= wined3d_fence_test(&event_query
->fence
, query
->device
, flags
);
549 case WINED3D_FENCE_OK
:
550 case WINED3D_FENCE_NOT_STARTED
:
551 return event_query
->signalled
= TRUE
;
553 case WINED3D_FENCE_WAITING
:
554 return event_query
->signalled
= FALSE
;
556 case WINED3D_FENCE_WRONG_THREAD
:
557 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query
);
558 return event_query
->signalled
= TRUE
;
560 case WINED3D_FENCE_ERROR
:
561 ERR("The GL event query failed.\n");
562 return event_query
->signalled
= TRUE
;
565 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret
);
566 return event_query
->signalled
= TRUE
;
570 void * CDECL
wined3d_query_get_parent(const struct wined3d_query
*query
)
572 TRACE("query %p.\n", query
);
574 return query
->parent
;
577 enum wined3d_query_type CDECL
wined3d_query_get_type(const struct wined3d_query
*query
)
579 TRACE("query %p.\n", query
);
584 static BOOL
wined3d_event_query_ops_issue(struct wined3d_query
*query
, uint32_t flags
)
586 TRACE("query %p, flags %#x.\n", query
, flags
);
588 if (flags
& WINED3DISSUE_END
)
590 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
592 wined3d_fence_issue(&event_query
->fence
, query
->device
);
595 else if (flags
& WINED3DISSUE_BEGIN
)
597 /* Started implicitly at query creation. */
598 ERR("Event query issued with START flag - what to do?\n");
604 static BOOL
wined3d_occlusion_query_ops_issue(struct wined3d_query
*query
, uint32_t flags
)
606 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
607 struct wined3d_device
*device
= query
->device
;
608 const struct wined3d_gl_info
*gl_info
;
609 struct wined3d_context_gl
*context_gl
;
612 TRACE("query %p, flags %#x.\n", query
, flags
);
614 /* This is allowed according to MSDN and our tests. Reset the query and
616 if (flags
& WINED3DISSUE_BEGIN
)
620 if ((context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
622 gl_info
= context_gl
->gl_info
;
623 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
624 checkGLcall("glEndQuery()");
628 FIXME("Wrong thread, can't restart query.\n");
629 wined3d_context_gl_free_occlusion_query(oq
);
630 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
631 wined3d_context_gl_alloc_occlusion_query(context_gl
, oq
);
637 wined3d_context_gl_free_occlusion_query(oq
);
638 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
639 wined3d_context_gl_alloc_occlusion_query(context_gl
, oq
);
641 gl_info
= context_gl
->gl_info
;
643 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED
, oq
->id
));
644 checkGLcall("glBeginQuery()");
646 context_release(&context_gl
->c
);
649 if (flags
& WINED3DISSUE_END
)
651 /* MSDN says END on a non-building occlusion query returns an error,
652 * but our tests show that it returns OK. But OpenGL doesn't like it,
653 * so avoid generating an error. */
656 if ((context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
658 gl_info
= context_gl
->gl_info
;
659 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
660 checkGLcall("glEndQuery()");
661 wined3d_query_buffer_queue_result(context_gl
, query
, oq
->id
);
663 context_release(&context_gl
->c
);
668 FIXME("Wrong thread, can't end query.\n");
677 static BOOL
wined3d_timestamp_query_ops_poll(struct wined3d_query
*query
, uint32_t flags
)
679 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
680 const struct wined3d_gl_info
*gl_info
;
681 struct wined3d_context_gl
*context_gl
;
685 TRACE("query %p, flags %#x.\n", query
, flags
);
687 if (!(context_gl
= wined3d_context_gl_reacquire(tq
->context_gl
)))
689 FIXME("%p Wrong thread, returning 1.\n", query
);
693 gl_info
= context_gl
->gl_info
;
695 GL_EXTCALL(glGetQueryObjectuiv(tq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
696 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
697 TRACE("available %#x.\n", available
);
701 GL_EXTCALL(glGetQueryObjectui64v(tq
->id
, GL_QUERY_RESULT
, ×tamp
));
702 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
703 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp
));
704 tq
->timestamp
= timestamp
;
707 context_release(&context_gl
->c
);
712 static BOOL
wined3d_timestamp_query_ops_issue(struct wined3d_query
*query
, uint32_t flags
)
714 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
715 const struct wined3d_gl_info
*gl_info
;
716 struct wined3d_context_gl
*context_gl
;
718 TRACE("query %p, flags %#x.\n", query
, flags
);
720 if (flags
& WINED3DISSUE_BEGIN
)
722 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
724 if (flags
& WINED3DISSUE_END
)
727 wined3d_context_gl_free_timestamp_query(tq
);
728 context_gl
= wined3d_context_gl(context_acquire(query
->device
, NULL
, 0));
729 gl_info
= context_gl
->gl_info
;
730 wined3d_context_gl_alloc_timestamp_query(context_gl
, tq
);
731 GL_EXTCALL(glQueryCounter(tq
->id
, GL_TIMESTAMP
));
732 checkGLcall("glQueryCounter()");
733 context_release(&context_gl
->c
);
741 static BOOL
wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query
*query
, uint32_t flags
)
743 TRACE("query %p, flags %#x.\n", query
, flags
);
748 static BOOL
wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query
*query
, uint32_t flags
)
750 TRACE("query %p, flags %#x.\n", query
, flags
);
755 static BOOL
wined3d_so_statistics_query_ops_poll(struct wined3d_query
*query
, uint32_t flags
)
757 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
758 GLuint written_available
, generated_available
;
759 const struct wined3d_gl_info
*gl_info
;
760 struct wined3d_context_gl
*context_gl
;
762 TRACE("query %p, flags %#x.\n", query
, flags
);
764 if (!(context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
766 FIXME("%p Wrong thread, returning 0 primitives.\n", query
);
767 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
770 gl_info
= context_gl
->gl_info
;
772 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.query
.written
,
773 GL_QUERY_RESULT_AVAILABLE
, &written_available
));
774 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.query
.generated
,
775 GL_QUERY_RESULT_AVAILABLE
, &generated_available
));
776 TRACE("Available %#x, %#x.\n", written_available
, generated_available
);
778 if (written_available
&& generated_available
)
780 pq
->statistics
.primitives_written
= get_query_result64(pq
->u
.query
.written
, gl_info
);
781 pq
->statistics
.primitives_generated
= get_query_result64(pq
->u
.query
.generated
, gl_info
);
782 TRACE("Returning %s, %s primitives.\n",
783 wine_dbgstr_longlong(pq
->statistics
.primitives_written
),
784 wine_dbgstr_longlong(pq
->statistics
.primitives_generated
));
787 checkGLcall("poll SO statistics query");
788 context_release(&context_gl
->c
);
790 return written_available
&& generated_available
;
793 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query
*query
,
794 struct wined3d_context_gl
*context_gl
)
796 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
798 if (gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
800 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
, query
->stream_idx
));
801 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED
, query
->stream_idx
));
805 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
));
806 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED
));
808 checkGLcall("end query");
811 static BOOL
wined3d_so_statistics_query_ops_issue(struct wined3d_query
*query
, uint32_t flags
)
813 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
814 struct wined3d_device
*device
= query
->device
;
815 const struct wined3d_gl_info
*gl_info
;
816 struct wined3d_context_gl
*context_gl
;
819 TRACE("query %p, flags %#x.\n", query
, flags
);
821 if (flags
& WINED3DISSUE_BEGIN
)
825 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
827 wined3d_so_statistics_query_end(pq
, context_gl
);
831 FIXME("Wrong thread, can't restart query.\n");
832 wined3d_context_gl_free_so_statistics_query(pq
);
833 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
834 wined3d_context_gl_alloc_so_statistics_query(context_gl
, pq
);
840 wined3d_context_gl_free_so_statistics_query(pq
);
841 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
842 wined3d_context_gl_alloc_so_statistics_query(context_gl
, pq
);
844 gl_info
= context_gl
->gl_info
;
846 if (gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
848 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
,
849 pq
->stream_idx
, pq
->u
.query
.written
));
850 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED
,
851 pq
->stream_idx
, pq
->u
.query
.generated
));
855 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
,
856 pq
->u
.query
.written
));
857 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED
,
858 pq
->u
.query
.generated
));
860 checkGLcall("begin query");
862 context_release(&context_gl
->c
);
865 if (flags
& WINED3DISSUE_END
)
869 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
871 wined3d_so_statistics_query_end(pq
, context_gl
);
873 context_release(&context_gl
->c
);
878 FIXME("Wrong thread, can't end query.\n");
887 static BOOL
wined3d_pipeline_query_ops_poll(struct wined3d_query
*query
, uint32_t flags
)
889 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
890 const struct wined3d_gl_info
*gl_info
;
891 struct wined3d_context_gl
*context_gl
;
895 TRACE("query %p, flags %#x.\n", query
, flags
);
897 if (!(context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
899 FIXME("%p Wrong thread.\n", query
);
900 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
903 gl_info
= context_gl
->gl_info
;
905 for (i
= 0; i
< ARRAY_SIZE(pq
->u
.id
); ++i
)
907 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.id
[i
], GL_QUERY_RESULT_AVAILABLE
, &available
));
914 pq
->statistics
.vertices_submitted
= get_query_result64(pq
->u
.query
.vertices
, gl_info
);
915 pq
->statistics
.primitives_submitted
= get_query_result64(pq
->u
.query
.primitives
, gl_info
);
916 pq
->statistics
.vs_invocations
= get_query_result64(pq
->u
.query
.vertex_shader
, gl_info
);
917 pq
->statistics
.hs_invocations
= get_query_result64(pq
->u
.query
.tess_control_shader
, gl_info
);
918 pq
->statistics
.ds_invocations
= get_query_result64(pq
->u
.query
.tess_eval_shader
, gl_info
);
919 pq
->statistics
.gs_invocations
= get_query_result64(pq
->u
.query
.geometry_shader
, gl_info
);
920 pq
->statistics
.gs_primitives
= get_query_result64(pq
->u
.query
.geometry_primitives
, gl_info
);
921 pq
->statistics
.ps_invocations
= get_query_result64(pq
->u
.query
.fragment_shader
, gl_info
);
922 pq
->statistics
.cs_invocations
= get_query_result64(pq
->u
.query
.compute_shader
, gl_info
);
923 pq
->statistics
.clipping_input_primitives
= get_query_result64(pq
->u
.query
.clipping_input
, gl_info
);
924 pq
->statistics
.clipping_output_primitives
= get_query_result64(pq
->u
.query
.clipping_output
, gl_info
);
927 checkGLcall("poll pipeline statistics query");
928 context_release(&context_gl
->c
);
932 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query
*query
,
933 struct wined3d_context_gl
*context_gl
)
935 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
937 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB
));
938 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB
));
939 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB
));
940 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB
));
941 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB
));
942 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS
));
943 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB
));
944 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB
));
945 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB
));
946 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB
));
947 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB
));
948 checkGLcall("end query");
951 static BOOL
wined3d_pipeline_query_ops_issue(struct wined3d_query
*query
, uint32_t flags
)
953 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
954 struct wined3d_device
*device
= query
->device
;
955 const struct wined3d_gl_info
*gl_info
;
956 struct wined3d_context_gl
*context_gl
;
959 TRACE("query %p, flags %#x.\n", query
, flags
);
961 if (flags
& WINED3DISSUE_BEGIN
)
965 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
967 wined3d_pipeline_statistics_query_end(pq
, context_gl
);
971 FIXME("Wrong thread, can't restart query.\n");
972 wined3d_context_gl_free_pipeline_statistics_query(pq
);
973 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
974 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl
, pq
);
980 wined3d_context_gl_free_pipeline_statistics_query(pq
);
981 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
982 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl
, pq
);
984 gl_info
= context_gl
->gl_info
;
986 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB
, pq
->u
.query
.vertices
));
987 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB
, pq
->u
.query
.primitives
));
988 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.vertex_shader
));
989 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB
, pq
->u
.query
.tess_control_shader
));
990 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.tess_eval_shader
));
991 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS
, pq
->u
.query
.geometry_shader
));
992 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB
, pq
->u
.query
.geometry_primitives
));
993 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.fragment_shader
));
994 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.compute_shader
));
995 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB
, pq
->u
.query
.clipping_input
));
996 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB
, pq
->u
.query
.clipping_output
));
997 checkGLcall("begin query");
999 context_release(&context_gl
->c
);
1002 if (flags
& WINED3DISSUE_END
)
1006 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
1008 wined3d_pipeline_statistics_query_end(pq
, context_gl
);
1009 context_release(&context_gl
->c
);
1014 FIXME("Wrong thread, can't end query.\n");
1017 pq
->started
= FALSE
;
1023 static void wined3d_event_query_ops_destroy(struct wined3d_query
*query
)
1025 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
1027 wined3d_fence_free(&event_query
->fence
);
1028 heap_free(event_query
);
1031 static const struct wined3d_query_ops event_query_ops
=
1033 wined3d_event_query_ops_poll
,
1034 wined3d_event_query_ops_issue
,
1035 wined3d_event_query_ops_destroy
,
1038 static HRESULT
wined3d_event_query_create(struct wined3d_device
*device
,
1039 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1040 struct wined3d_query
**query
)
1042 const struct wined3d_gl_info
*gl_info
= &wined3d_adapter_gl(device
->adapter
)->gl_info
;
1043 struct wined3d_event_query
*object
;
1046 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1047 device
, type
, parent
, parent_ops
, query
);
1049 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1050 return E_OUTOFMEMORY
;
1052 if (FAILED(hr
= wined3d_fence_init(&object
->fence
, gl_info
)))
1054 WARN("Event queries not supported.\n");
1059 wined3d_query_init(&object
->query
, device
, type
, &object
->signalled
,
1060 sizeof(object
->signalled
), &event_query_ops
, parent
, parent_ops
);
1062 TRACE("Created query %p.\n", object
);
1063 *query
= &object
->query
;
1068 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query
*query
)
1070 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
1073 wined3d_context_gl_free_occlusion_query(oq
);
1077 static const struct wined3d_query_ops occlusion_query_ops
=
1079 wined3d_occlusion_query_ops_poll
,
1080 wined3d_occlusion_query_ops_issue
,
1081 wined3d_occlusion_query_ops_destroy
,
1084 static HRESULT
wined3d_occlusion_query_create(struct wined3d_device
*device
,
1085 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1086 struct wined3d_query
**query
)
1088 const struct wined3d_gl_info
*gl_info
= &wined3d_adapter_gl(device
->adapter
)->gl_info
;
1089 struct wined3d_occlusion_query
*object
;
1091 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1092 device
, type
, parent
, parent_ops
, query
);
1094 if (!gl_info
->supported
[ARB_OCCLUSION_QUERY
])
1096 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1097 return WINED3DERR_NOTAVAILABLE
;
1100 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1101 return E_OUTOFMEMORY
;
1103 wined3d_query_init(&object
->query
, device
, type
, &object
->samples
,
1104 sizeof(object
->samples
), &occlusion_query_ops
, parent
, parent_ops
);
1106 TRACE("Created query %p.\n", object
);
1107 *query
= &object
->query
;
1112 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query
*query
)
1114 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
1117 wined3d_context_gl_free_timestamp_query(tq
);
1121 static const struct wined3d_query_ops timestamp_query_ops
=
1123 wined3d_timestamp_query_ops_poll
,
1124 wined3d_timestamp_query_ops_issue
,
1125 wined3d_timestamp_query_ops_destroy
,
1128 static HRESULT
wined3d_timestamp_query_create(struct wined3d_device
*device
,
1129 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1130 struct wined3d_query
**query
)
1132 const struct wined3d_gl_info
*gl_info
= &wined3d_adapter_gl(device
->adapter
)->gl_info
;
1133 struct wined3d_timestamp_query
*object
;
1135 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1136 device
, type
, parent
, parent_ops
, query
);
1138 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1140 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1141 return WINED3DERR_NOTAVAILABLE
;
1144 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1145 return E_OUTOFMEMORY
;
1147 wined3d_query_init(&object
->query
, device
, type
, &object
->timestamp
,
1148 sizeof(object
->timestamp
), ×tamp_query_ops
, parent
, parent_ops
);
1150 TRACE("Created query %p.\n", object
);
1151 *query
= &object
->query
;
1156 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query
*query
)
1161 static const struct wined3d_query_ops timestamp_disjoint_query_ops
=
1163 wined3d_timestamp_disjoint_query_ops_poll
,
1164 wined3d_timestamp_disjoint_query_ops_issue
,
1165 wined3d_timestamp_disjoint_query_ops_destroy
,
1168 static HRESULT
wined3d_timestamp_disjoint_query_create(struct wined3d_device
*device
,
1169 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1170 struct wined3d_query
**query
)
1172 const struct wined3d_gl_info
*gl_info
= &wined3d_adapter_gl(device
->adapter
)->gl_info
;
1173 struct wined3d_query
*object
;
1175 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1176 device
, type
, parent
, parent_ops
, query
);
1178 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1180 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1181 return WINED3DERR_NOTAVAILABLE
;
1184 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1185 return E_OUTOFMEMORY
;
1187 if (type
== WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
)
1189 static const struct wined3d_query_data_timestamp_disjoint disjoint_data
= {1000 * 1000 * 1000, FALSE
};
1191 wined3d_query_init(object
, device
, type
, &disjoint_data
,
1192 sizeof(disjoint_data
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1196 static const UINT64 freq
= 1000 * 1000 * 1000;
1198 wined3d_query_init(object
, device
, type
, &freq
,
1199 sizeof(freq
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1202 TRACE("Created query %p.\n", object
);
1208 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query
*query
)
1210 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
1213 wined3d_context_gl_free_so_statistics_query(pq
);
1217 static const struct wined3d_query_ops so_statistics_query_ops
=
1219 wined3d_so_statistics_query_ops_poll
,
1220 wined3d_so_statistics_query_ops_issue
,
1221 wined3d_so_statistics_query_ops_destroy
,
1224 static HRESULT
wined3d_so_statistics_query_create(struct wined3d_device
*device
,
1225 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1226 struct wined3d_query
**query
)
1228 const struct wined3d_gl_info
*gl_info
= &wined3d_adapter_gl(device
->adapter
)->gl_info
;
1229 struct wined3d_so_statistics_query
*object
;
1230 unsigned int stream_idx
;
1232 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
<= type
&& type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1233 stream_idx
= type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
;
1234 else if (type
== WINED3D_QUERY_TYPE_SO_STATISTICS
)
1237 return WINED3DERR_NOTAVAILABLE
;
1239 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1240 device
, type
, parent
, parent_ops
, query
);
1242 if (!gl_info
->supported
[WINED3D_GL_PRIMITIVE_QUERY
])
1244 WARN("OpenGL implementation does not support primitive queries.\n");
1245 return WINED3DERR_NOTAVAILABLE
;
1247 if (stream_idx
&& !gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
1249 WARN("OpenGL implementation does not support indexed queries.\n");
1250 return WINED3DERR_NOTAVAILABLE
;
1253 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1254 return E_OUTOFMEMORY
;
1256 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1257 sizeof(object
->statistics
), &so_statistics_query_ops
, parent
, parent_ops
);
1258 object
->stream_idx
= stream_idx
;
1260 TRACE("Created query %p.\n", object
);
1261 *query
= &object
->query
;
1266 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query
*query
)
1268 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
1270 wined3d_context_gl_free_pipeline_statistics_query(pq
);
1274 static const struct wined3d_query_ops pipeline_query_ops
=
1276 wined3d_pipeline_query_ops_poll
,
1277 wined3d_pipeline_query_ops_issue
,
1278 wined3d_pipeline_query_ops_destroy
,
1281 static HRESULT
wined3d_pipeline_query_create(struct wined3d_device
*device
,
1282 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1283 struct wined3d_query
**query
)
1285 const struct wined3d_gl_info
*gl_info
= &wined3d_adapter_gl(device
->adapter
)->gl_info
;
1286 struct wined3d_pipeline_statistics_query
*object
;
1288 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1289 device
, type
, parent
, parent_ops
, query
);
1291 if (!gl_info
->supported
[ARB_PIPELINE_STATISTICS_QUERY
])
1293 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1294 return WINED3DERR_NOTAVAILABLE
;
1297 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1298 return E_OUTOFMEMORY
;
1300 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1301 sizeof(object
->statistics
), &pipeline_query_ops
, parent
, parent_ops
);
1303 TRACE("Created query %p.\n", object
);
1304 *query
= &object
->query
;
1309 HRESULT
wined3d_query_gl_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1310 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1312 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1313 device
, type
, parent
, parent_ops
, query
);
1317 case WINED3D_QUERY_TYPE_EVENT
:
1318 return wined3d_event_query_create(device
, type
, parent
, parent_ops
, query
);
1320 case WINED3D_QUERY_TYPE_OCCLUSION
:
1321 return wined3d_occlusion_query_create(device
, type
, parent
, parent_ops
, query
);
1323 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1324 return wined3d_timestamp_query_create(device
, type
, parent
, parent_ops
, query
);
1326 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1327 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ
:
1328 return wined3d_timestamp_disjoint_query_create(device
, type
, parent
, parent_ops
, query
);
1330 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1331 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1332 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1333 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1334 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1335 return wined3d_so_statistics_query_create(device
, type
, parent
, parent_ops
, query
);
1337 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1338 return wined3d_pipeline_query_create(device
, type
, parent
, parent_ops
, query
);
1341 FIXME("Unhandled query type %#x.\n", type
);
1342 return WINED3DERR_NOTAVAILABLE
;
1346 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk
*pool_vk
, size_t idx
,
1347 struct wined3d_context_vk
*context_vk
)
1349 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1350 * outside of a render pass. Queue the query to be reset at the very end of the current
1351 * command buffer instead. */
1352 wined3d_bitmap_set(pool_vk
->completed
, idx
);
1353 if (list_empty(&pool_vk
->completed_entry
))
1354 list_add_tail(&context_vk
->completed_query_pools
, &pool_vk
->completed_entry
);
1357 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk
*pool_vk
, size_t *idx
)
1359 if ((*idx
= wined3d_bitmap_ffz(pool_vk
->allocated
, WINED3D_QUERY_POOL_SIZE
, 0)) > WINED3D_QUERY_POOL_SIZE
)
1361 wined3d_bitmap_set(pool_vk
->allocated
, *idx
);
1366 void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk
*context_vk
, struct wined3d_query_pool_vk
*pool_vk
,
1367 uint32_t start
, uint32_t count
)
1369 unsigned int idx
, end
= start
+ count
;
1371 for (idx
= start
; idx
< end
; ++idx
)
1372 wined3d_bitmap_clear(pool_vk
->allocated
, idx
);
1374 if (list_empty(&pool_vk
->entry
))
1375 list_add_tail(pool_vk
->free_list
, &pool_vk
->entry
);
1378 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk
*pool_vk
, struct wined3d_context_vk
*context_vk
)
1380 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(context_vk
->c
.device
);
1381 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1383 VK_CALL(vkDestroyQueryPool(device_vk
->vk_device
, pool_vk
->vk_query_pool
, NULL
));
1384 if (pool_vk
->vk_event
)
1385 VK_CALL(vkDestroyEvent(device_vk
->vk_device
, pool_vk
->vk_event
, NULL
));
1386 list_remove(&pool_vk
->entry
);
1387 list_remove(&pool_vk
->completed_entry
);
1390 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk
*pool_vk
,
1391 struct wined3d_context_vk
*context_vk
, enum wined3d_query_type type
, struct list
*free_pools
)
1393 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(context_vk
->c
.device
);
1394 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1395 VkQueryPoolCreateInfo pool_info
;
1398 list_init(&pool_vk
->entry
);
1399 list_init(&pool_vk
->completed_entry
);
1400 pool_vk
->free_list
= free_pools
;
1402 pool_info
.sType
= VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO
;
1403 pool_info
.pNext
= NULL
;
1404 pool_info
.flags
= 0;
1405 pool_info
.queryCount
= WINED3D_QUERY_POOL_SIZE
;
1409 case WINED3D_QUERY_TYPE_OCCLUSION
:
1410 pool_info
.queryType
= VK_QUERY_TYPE_OCCLUSION
;
1411 pool_info
.pipelineStatistics
= 0;
1414 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1415 pool_info
.queryType
= VK_QUERY_TYPE_TIMESTAMP
;
1416 pool_info
.pipelineStatistics
= 0;
1419 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1420 pool_info
.queryType
= VK_QUERY_TYPE_PIPELINE_STATISTICS
;
1421 pool_info
.pipelineStatistics
= VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1422 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1423 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1424 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1425 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1426 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1427 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1428 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1429 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1430 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1431 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT
;
1434 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1435 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1436 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1437 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1438 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1439 pool_info
.queryType
= VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
;
1440 pool_info
.pipelineStatistics
= 0;
1444 FIXME("Unhandled query type %#x.\n", type
);
1448 if ((vr
= VK_CALL(vkCreateQueryPool(device_vk
->vk_device
, &pool_info
, NULL
, &pool_vk
->vk_query_pool
))) < 0)
1450 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr
));
1454 list_add_head(free_pools
, &pool_vk
->entry
);
1459 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk
*query_vk
,
1460 struct wined3d_device_vk
*device_vk
, const struct wined3d_query_pool_idx_vk
*pool_idx
)
1462 const struct wined3d_query_data_pipeline_statistics
*ps_tmp
;
1463 const struct wined3d_vk_info
*vk_info
= &device_vk
->vk_info
;
1464 struct wined3d_query_data_pipeline_statistics
*ps_result
;
1470 struct wined3d_query_data_pipeline_statistics pipeline_statistics
;
1471 struct wined3d_query_data_so_statistics so_statistics
;
1474 if (pool_idx
->pool_vk
->vk_event
)
1476 /* Check if the pool's initial reset command executed. */
1477 vr
= VK_CALL(vkGetEventStatus(device_vk
->vk_device
,
1478 pool_idx
->pool_vk
->vk_event
));
1479 if (vr
== VK_EVENT_RESET
)
1481 else if (vr
!= VK_EVENT_SET
)
1483 ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr
));
1488 if ((vr
= VK_CALL(vkGetQueryPoolResults(device_vk
->vk_device
, pool_idx
->pool_vk
->vk_query_pool
,
1489 pool_idx
->idx
, 1, sizeof(tmp
), &tmp
, sizeof(tmp
), VK_QUERY_RESULT_64_BIT
))) < 0)
1491 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr
));
1495 if (vr
== VK_NOT_READY
)
1498 result
= (void *)query_vk
->q
.data
;
1499 switch (query_vk
->q
.type
)
1501 case WINED3D_QUERY_TYPE_OCCLUSION
:
1502 result
->occlusion
+= tmp
.occlusion
;
1505 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1506 result
->timestamp
= tmp
.timestamp
;
1509 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1510 ps_result
= &result
->pipeline_statistics
;
1511 ps_tmp
= &tmp
.pipeline_statistics
;
1512 ps_result
->vertices_submitted
+= ps_tmp
->vertices_submitted
;
1513 ps_result
->primitives_submitted
+= ps_tmp
->primitives_submitted
;
1514 ps_result
->vs_invocations
+= ps_tmp
->vs_invocations
;
1515 ps_result
->gs_invocations
+= ps_tmp
->gs_invocations
;
1516 ps_result
->gs_primitives
+= ps_tmp
->gs_primitives
;
1517 ps_result
->clipping_input_primitives
+= ps_tmp
->clipping_input_primitives
;
1518 ps_result
->clipping_output_primitives
+= ps_tmp
->clipping_output_primitives
;
1519 ps_result
->ps_invocations
+= ps_tmp
->ps_invocations
;
1520 ps_result
->hs_invocations
+= ps_tmp
->hs_invocations
;
1521 ps_result
->ds_invocations
+= ps_tmp
->ds_invocations
;
1522 ps_result
->cs_invocations
+= ps_tmp
->cs_invocations
;
1525 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1526 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1527 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1528 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1529 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1530 result
->so_statistics
.primitives_written
+= tmp
.so_statistics
.primitives_written
;
1531 result
->so_statistics
.primitives_generated
+= tmp
.so_statistics
.primitives_generated
;
1535 FIXME("Unhandled query type %#x.\n", query_vk
->q
.type
);
1542 static void wined3d_query_vk_begin(struct wined3d_query_vk
*query_vk
,
1543 struct wined3d_context_vk
*context_vk
, VkCommandBuffer vk_command_buffer
)
1545 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1546 struct wined3d_query_pool_vk
*pool_vk
;
1549 pool_vk
= query_vk
->pool_idx
.pool_vk
;
1550 idx
= query_vk
->pool_idx
.idx
;
1552 if (query_vk
->q
.type
>= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1553 && query_vk
->q
.type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1554 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
,
1555 query_vk
->control_flags
, query_vk
->q
.type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
));
1557 VK_CALL(vkCmdBeginQuery(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
, query_vk
->control_flags
));
1558 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1561 static void wined3d_query_vk_end(struct wined3d_query_vk
*query_vk
,
1562 struct wined3d_context_vk
*context_vk
, VkCommandBuffer vk_command_buffer
)
1564 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1565 struct wined3d_query_pool_vk
*pool_vk
;
1568 pool_vk
= query_vk
->pool_idx
.pool_vk
;
1569 idx
= query_vk
->pool_idx
.idx
;
1571 if (query_vk
->q
.type
>= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1572 && query_vk
->q
.type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1573 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer
, pool_vk
->vk_query_pool
,
1574 idx
, query_vk
->q
.type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
));
1576 VK_CALL(vkCmdEndQuery(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
));
1579 void wined3d_query_vk_resume(struct wined3d_query_vk
*query_vk
, struct wined3d_context_vk
*context_vk
)
1581 VkCommandBuffer vk_command_buffer
= context_vk
->current_command_buffer
.vk_command_buffer
;
1583 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1584 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
;
1587 void wined3d_query_vk_suspend(struct wined3d_query_vk
*query_vk
, struct wined3d_context_vk
*context_vk
)
1589 VkCommandBuffer vk_command_buffer
= context_vk
->current_command_buffer
.vk_command_buffer
;
1591 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1593 if (!wined3d_array_reserve((void **)&query_vk
->pending
, &query_vk
->pending_size
,
1594 query_vk
->pending_count
+ 1, sizeof(*query_vk
->pending
)))
1596 ERR("Failed to allocate entry.\n");
1600 query_vk
->pending
[query_vk
->pending_count
++] = query_vk
->pool_idx
;
1601 query_vk
->pool_idx
.pool_vk
= NULL
;
1602 query_vk
->flags
&= ~WINED3D_QUERY_VK_FLAG_ACTIVE
;
1605 static BOOL
wined3d_query_vk_poll(struct wined3d_query
*query
, uint32_t flags
)
1607 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1608 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1611 memset((void *)query
->data
, 0, query
->data_size
);
1613 if (query_vk
->pool_idx
.pool_vk
&& !wined3d_query_vk_accumulate_data(query_vk
, device_vk
, &query_vk
->pool_idx
))
1616 for (i
= 0; i
< query_vk
->pending_count
; ++i
)
1618 if (!wined3d_query_vk_accumulate_data(query_vk
, device_vk
, &query_vk
->pending
[i
]))
1625 if ((flags
& WINED3DGETDATA_FLUSH
) && !query
->device
->cs
->queries_flushed
)
1626 query
->device
->cs
->c
.ops
->flush(&query
->device
->cs
->c
);
1631 static void wined3d_query_vk_remove_pending_queries(struct wined3d_context_vk
*context_vk
,
1632 struct wined3d_query_vk
*query_vk
)
1636 for (i
= 0; i
< query_vk
->pending_count
; ++i
)
1637 wined3d_query_pool_vk_mark_complete(query_vk
->pending
[i
].pool_vk
, query_vk
->pending
[i
].idx
, context_vk
);
1639 query_vk
->pending_count
= 0;
1642 static BOOL
wined3d_query_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1644 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1645 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1646 struct wined3d_context_vk
*context_vk
;
1647 VkCommandBuffer vk_command_buffer
;
1650 TRACE("query %p, flags %#x.\n", query
, flags
);
1652 if (flags
& WINED3DISSUE_BEGIN
)
1654 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1656 if (query_vk
->pending_count
)
1657 wined3d_query_vk_remove_pending_queries(context_vk
, query_vk
);
1658 vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1659 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1661 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_ACTIVE
)
1662 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1663 list_remove(&query_vk
->entry
);
1665 if (query_vk
->pool_idx
.pool_vk
)
1666 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
,
1667 query_vk
->pool_idx
.idx
, context_vk
);
1669 if (!wined3d_context_vk_allocate_query(context_vk
, query_vk
->q
.type
, &query_vk
->pool_idx
))
1671 ERR("Failed to allocate new query.\n");
1675 /* A query needs to either begin and end inside a single render pass
1676 * or begin and end outside of a render pass. Occlusion queries, if
1677 * issued outside of a render pass, are queued up and only begun when
1678 * a render pass is started, to avoid interrupting the render pass
1679 * when the query ends. */
1680 if (context_vk
->vk_render_pass
)
1682 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1683 list_add_head(&context_vk
->render_pass_queries
, &query_vk
->entry
);
1684 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
| WINED3D_QUERY_VK_FLAG_RENDER_PASS
;
1686 else if (query
->type
== WINED3D_QUERY_TYPE_OCCLUSION
)
1688 list_add_head(&context_vk
->render_pass_queries
, &query_vk
->entry
);
1689 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_RENDER_PASS
;
1693 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1694 list_add_head(&context_vk
->active_queries
, &query_vk
->entry
);
1695 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
;
1698 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_STARTED
;
1699 context_release(&context_vk
->c
);
1701 if (flags
& WINED3DISSUE_END
&& query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1703 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1705 /* If the query was already ended because the command buffer was
1706 * flushed or the render pass ended, we don't need to end it here. */
1707 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_ACTIVE
)
1709 vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1710 if (!(query_vk
->flags
& WINED3D_QUERY_VK_FLAG_RENDER_PASS
))
1711 wined3d_context_vk_end_current_render_pass(context_vk
);
1712 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1714 else if (query_vk
->pool_idx
.pool_vk
)
1716 /* It was queued, but never activated. */
1717 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
,
1718 query_vk
->pool_idx
.idx
, context_vk
);
1719 query_vk
->pool_idx
.pool_vk
= NULL
;
1721 list_remove(&query_vk
->entry
);
1722 query_vk
->flags
= 0;
1725 context_release(&context_vk
->c
);
1731 static void wined3d_query_vk_destroy(struct wined3d_query
*query
)
1733 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1734 struct wined3d_context_vk
*context_vk
;
1736 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1737 list_remove(&query_vk
->entry
);
1738 context_vk
= wined3d_context_vk(context_acquire(query_vk
->q
.device
, NULL
, 0));
1739 wined3d_query_vk_remove_pending_queries(context_vk
, query_vk
);
1740 if (query_vk
->pool_idx
.pool_vk
)
1741 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
, query_vk
->pool_idx
.idx
, context_vk
);
1742 if (query_vk
->vk_event
)
1743 wined3d_context_vk_destroy_vk_event(context_vk
, query_vk
->vk_event
, query_vk
->command_buffer_id
);
1744 context_release(&context_vk
->c
);
1745 heap_free(query_vk
->pending
);
1746 heap_free(query_vk
);
1749 static const struct wined3d_query_ops wined3d_query_vk_ops
=
1751 .query_poll
= wined3d_query_vk_poll
,
1752 .query_issue
= wined3d_query_vk_issue
,
1753 .query_destroy
= wined3d_query_vk_destroy
,
1756 static BOOL
wined3d_query_event_vk_poll(struct wined3d_query
*query
, uint32_t flags
)
1758 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1759 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1760 const struct wined3d_vk_info
*vk_info
= &device_vk
->vk_info
;
1763 signalled
= VK_CALL(vkGetEventStatus(device_vk
->vk_device
, query_vk
->vk_event
))
1765 if (!signalled
&& (flags
& WINED3DGETDATA_FLUSH
) && !query
->device
->cs
->queries_flushed
)
1766 query
->device
->cs
->c
.ops
->flush(&query
->device
->cs
->c
);
1767 return *(BOOL
*)query
->data
= signalled
;
1770 static BOOL
wined3d_query_event_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1772 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1773 const struct wined3d_vk_info
*vk_info
= &device_vk
->vk_info
;
1774 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1775 struct wined3d_context_vk
*context_vk
;
1776 VkEventCreateInfo create_info
;
1779 TRACE("query %p, flags %#x.\n", query
, flags
);
1781 if (flags
& WINED3DISSUE_END
)
1783 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1784 wined3d_context_vk_end_current_render_pass(context_vk
);
1786 if (query_vk
->vk_event
)
1788 if (query_vk
->command_buffer_id
> context_vk
->completed_command_buffer_id
)
1790 /* Cannot reuse this event, as it may still get signalled by previous usage. */
1791 /* Throw it away and create a new one, but if that happens a lot we may want to pool instead. */
1792 wined3d_context_vk_destroy_vk_event(context_vk
, query_vk
->vk_event
, query_vk
->command_buffer_id
);
1793 query_vk
->vk_event
= VK_NULL_HANDLE
;
1797 VK_CALL(vkResetEvent(device_vk
->vk_device
, query_vk
->vk_event
));
1801 if (!query_vk
->vk_event
)
1803 create_info
.sType
= VK_STRUCTURE_TYPE_EVENT_CREATE_INFO
;
1804 create_info
.pNext
= NULL
;
1805 create_info
.flags
= 0;
1807 vr
= VK_CALL(vkCreateEvent(device_vk
->vk_device
, &create_info
, NULL
, &query_vk
->vk_event
));
1808 if (vr
!= VK_SUCCESS
)
1810 ERR("Failed to create Vulkan event, vr %s\n", wined3d_debug_vkresult(vr
));
1811 context_release(&context_vk
->c
);
1816 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1817 VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk
), query_vk
->vk_event
,
1818 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
));
1819 context_release(&context_vk
->c
);
1827 static const struct wined3d_query_ops wined3d_query_event_vk_ops
=
1829 .query_poll
= wined3d_query_event_vk_poll
,
1830 .query_issue
= wined3d_query_event_vk_issue
,
1831 .query_destroy
= wined3d_query_vk_destroy
,
1834 static BOOL
wined3d_query_timestamp_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1836 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1837 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1838 const struct wined3d_vk_info
*vk_info
;
1839 struct wined3d_context_vk
*context_vk
;
1840 VkCommandBuffer command_buffer
;
1842 TRACE("query %p, flags %#x.\n", query
, flags
);
1844 if (flags
& WINED3DISSUE_BEGIN
)
1845 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1847 if (flags
& WINED3DISSUE_END
)
1849 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1850 vk_info
= context_vk
->vk_info
;
1852 command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1853 if (query_vk
->pool_idx
.pool_vk
)
1854 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
, query_vk
->pool_idx
.idx
, context_vk
);
1855 if (!wined3d_context_vk_allocate_query(context_vk
, query_vk
->q
.type
, &query_vk
->pool_idx
))
1857 ERR("Failed to allocate new query.\n");
1860 VK_CALL(vkCmdWriteTimestamp(command_buffer
, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
,
1861 query_vk
->pool_idx
.pool_vk
->vk_query_pool
, query_vk
->pool_idx
.idx
));
1862 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1864 context_release(&context_vk
->c
);
1872 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops
=
1874 .query_poll
= wined3d_query_vk_poll
,
1875 .query_issue
= wined3d_query_timestamp_vk_issue
,
1876 .query_destroy
= wined3d_query_vk_destroy
,
1879 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops
=
1881 .query_poll
= wined3d_timestamp_disjoint_query_ops_poll
,
1882 .query_issue
= wined3d_timestamp_disjoint_query_ops_issue
,
1883 .query_destroy
= wined3d_query_vk_destroy
,
1886 HRESULT
wined3d_query_vk_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1887 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1889 struct wined3d_query_data_timestamp_disjoint
*disjoint_data
;
1890 const struct wined3d_query_ops
*ops
= &wined3d_query_vk_ops
;
1891 struct wined3d_query_vk
*query_vk
;
1892 unsigned int data_size
;
1895 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1896 device
, type
, parent
, parent_ops
, query
);
1900 case WINED3D_QUERY_TYPE_EVENT
:
1901 ops
= &wined3d_query_event_vk_ops
;
1902 data_size
= sizeof(BOOL
);
1905 case WINED3D_QUERY_TYPE_OCCLUSION
:
1906 data_size
= sizeof(uint64_t);
1909 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1910 if (!wined3d_device_vk(device
)->timestamp_bits
)
1912 WARN("Timestamp queries not supported.\n");
1913 return WINED3DERR_NOTAVAILABLE
;
1915 ops
= &wined3d_query_timestamp_vk_ops
;
1916 data_size
= sizeof(uint64_t);
1919 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1920 if (!wined3d_device_vk(device
)->timestamp_bits
)
1922 WARN("Timestamp queries not supported.\n");
1923 return WINED3DERR_NOTAVAILABLE
;
1925 ops
= &wined3d_query_timestamp_disjoint_vk_ops
;
1926 data_size
= sizeof(struct wined3d_query_data_timestamp_disjoint
);
1929 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1930 data_size
= sizeof(struct wined3d_query_data_pipeline_statistics
);
1933 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1934 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1935 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1936 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1937 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1938 if (!wined3d_adapter_vk(device
->adapter
)->vk_info
.supported
[WINED3D_VK_EXT_TRANSFORM_FEEDBACK
])
1940 WARN("Stream output queries not supported.\n");
1941 return WINED3DERR_NOTAVAILABLE
;
1943 data_size
= sizeof(struct wined3d_query_data_so_statistics
);
1947 FIXME("Unhandled query type %#x.\n", type
);
1948 return WINED3DERR_NOTAVAILABLE
;
1951 if (!(query_vk
= heap_alloc_zero(sizeof(*query_vk
) + data_size
)))
1952 return E_OUTOFMEMORY
;
1953 data
= query_vk
+ 1;
1955 wined3d_query_init(&query_vk
->q
, device
, type
, data
, data_size
, ops
, parent
, parent_ops
);
1956 query_vk
->q
.poll_in_cs
= false;
1960 case WINED3D_QUERY_TYPE_OCCLUSION
:
1961 query_vk
->control_flags
= VK_QUERY_CONTROL_PRECISE_BIT
;
1964 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1965 disjoint_data
= data
;
1966 disjoint_data
->frequency
= 1000000000 / wined3d_adapter_vk(device
->adapter
)->device_limits
.timestampPeriod
;
1967 disjoint_data
->disjoint
= FALSE
;
1974 TRACE("Created query %p.\n", query_vk
);
1975 *query
= &query_vk
->q
;
1980 HRESULT CDECL
wined3d_query_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1981 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1983 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1984 device
, type
, parent
, parent_ops
, query
);
1986 return device
->adapter
->adapter_ops
->adapter_create_query(device
, type
, parent
, parent_ops
, query
);