2 * Copyright 2005 Oliver Stieber
3 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
4 * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
28 static void wined3d_query_buffer_invalidate(struct wined3d_query
*query
)
30 /* map[0] != map[1]: exact values do not have any significance. */
31 query
->map_ptr
[0] = 0;
32 query
->map_ptr
[1] = ~(UINT64
)0;
35 static BOOL
wined3d_query_buffer_is_valid(struct wined3d_query
*query
)
37 return query
->map_ptr
[0] == query
->map_ptr
[1];
40 static void wined3d_query_create_buffer_object(struct wined3d_context_gl
*context_gl
, struct wined3d_query
*query
)
42 const GLuint map_flags
= GL_MAP_READ_BIT
| GL_MAP_WRITE_BIT
| GL_MAP_PERSISTENT_BIT
| GL_MAP_COHERENT_BIT
;
43 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
46 GL_EXTCALL(glGenBuffers(1, &buffer_object
));
47 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, buffer_object
));
48 GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER
, sizeof(query
->map_ptr
[0]) * 2, NULL
, map_flags
));
49 query
->map_ptr
= GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER
, 0, sizeof(query
->map_ptr
[0]) * 2, map_flags
));
50 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, 0));
51 checkGLcall("query buffer object creation");
53 wined3d_query_buffer_invalidate(query
);
54 query
->buffer_object
= buffer_object
;
57 void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl
*context_gl
, struct wined3d_query
*query
)
59 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
61 GL_EXTCALL(glDeleteBuffers(1, &query
->buffer_object
));
62 checkGLcall("query buffer object destruction");
64 query
->buffer_object
= 0;
65 query
->map_ptr
= NULL
;
68 /* From ARB_occlusion_query: "Querying the state for a given occlusion query
69 * forces that occlusion query to complete within a finite amount of time."
70 * In practice, that means drivers flush when retrieving
71 * GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
72 * significant number of queries. Using a persistently mapped query buffer
73 * object allows us to avoid these implicit flushes. An additional benefit is
74 * that it allows us to poll the query status from the application-thread
75 * instead of from the csmt-thread. */
76 static BOOL
wined3d_query_buffer_queue_result(struct wined3d_context_gl
*context_gl
,
77 struct wined3d_query
*query
, GLuint id
)
79 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
82 if (!gl_info
->supported
[ARB_QUERY_BUFFER_OBJECT
] || !gl_info
->supported
[ARB_BUFFER_STORAGE
])
84 /* Don't use query buffers without CSMT, mainly for simplicity. */
85 if (!context_gl
->c
.device
->cs
->thread
)
88 if (query
->buffer_object
)
90 /* If there's still a query result in-flight for the existing buffer
91 * object (i.e., the query was restarted before we received its
92 * result), we can't reuse the existing buffer object. */
93 if (wined3d_query_buffer_is_valid(query
))
94 wined3d_query_buffer_invalidate(query
);
96 wined3d_query_gl_destroy_buffer_object(context_gl
, query
);
99 if (!query
->buffer_object
)
100 wined3d_query_create_buffer_object(context_gl
, query
);
102 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, query
->buffer_object
));
103 /* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
104 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, (void *)0));
105 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, (void *)sizeof(query
->map_ptr
[0])));
106 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER
, 0));
107 checkGLcall("queue query result");
109 /* ARB_buffer_storage requires the client to call FenceSync with
110 * SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
111 * is not enforced by Mesa.
113 tmp_sync
= GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE
, 0));
114 GL_EXTCALL(glDeleteSync(tmp_sync
));
115 checkGLcall("query buffer sync");
120 static UINT64
get_query_result64(GLuint id
, const struct wined3d_gl_info
*gl_info
)
122 if (gl_info
->supported
[ARB_TIMER_QUERY
])
125 GL_EXTCALL(glGetQueryObjectui64v(id
, GL_QUERY_RESULT
, &result
));
131 GL_EXTCALL(glGetQueryObjectuiv(id
, GL_QUERY_RESULT
, &result
));
136 static void wined3d_query_init(struct wined3d_query
*query
, struct wined3d_device
*device
,
137 enum wined3d_query_type type
, const void *data
, DWORD data_size
,
138 const struct wined3d_query_ops
*query_ops
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
141 query
->parent
= parent
;
142 query
->parent_ops
= parent_ops
;
143 query
->device
= device
;
144 query
->state
= QUERY_CREATED
;
147 query
->data_size
= data_size
;
148 query
->query_ops
= query_ops
;
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 static BOOL
wined3d_fence_supported(const struct wined3d_gl_info
*gl_info
)
180 return gl_info
->supported
[ARB_SYNC
] || gl_info
->supported
[NV_FENCE
] || gl_info
->supported
[APPLE_FENCE
];
183 enum wined3d_fence_result
wined3d_fence_test(const struct wined3d_fence
*fence
,
184 struct wined3d_device
*device
, DWORD flags
)
186 const struct wined3d_gl_info
*gl_info
;
187 struct wined3d_context_gl
*context_gl
;
188 enum wined3d_fence_result ret
;
191 TRACE("fence %p, device %p, flags %#x.\n", fence
, device
, flags
);
193 if (!fence
->context_gl
)
195 TRACE("Fence not issued.\n");
196 return WINED3D_FENCE_NOT_STARTED
;
199 if (!(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
)))
201 if (!fence
->context_gl
->gl_info
->supported
[ARB_SYNC
])
203 WARN("Fence tested from wrong thread.\n");
204 return WINED3D_FENCE_WRONG_THREAD
;
206 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
208 gl_info
= context_gl
->gl_info
;
210 if (gl_info
->supported
[ARB_SYNC
])
212 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
213 (flags
& WINED3DGETDATA_FLUSH
) ? GL_SYNC_FLUSH_COMMANDS_BIT
: 0, 0));
214 checkGLcall("glClientWaitSync");
218 case GL_ALREADY_SIGNALED
:
219 case GL_CONDITION_SATISFIED
:
220 ret
= WINED3D_FENCE_OK
;
223 case GL_TIMEOUT_EXPIRED
:
224 ret
= WINED3D_FENCE_WAITING
;
229 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
230 ret
= WINED3D_FENCE_ERROR
;
233 else if (gl_info
->supported
[APPLE_FENCE
])
235 fence_result
= GL_EXTCALL(glTestFenceAPPLE(fence
->object
.id
));
236 checkGLcall("glTestFenceAPPLE");
238 ret
= WINED3D_FENCE_OK
;
240 ret
= WINED3D_FENCE_WAITING
;
242 else if (gl_info
->supported
[NV_FENCE
])
244 fence_result
= GL_EXTCALL(glTestFenceNV(fence
->object
.id
));
245 checkGLcall("glTestFenceNV");
247 ret
= WINED3D_FENCE_OK
;
249 ret
= WINED3D_FENCE_WAITING
;
253 ERR("Fence created despite lack of GL support.\n");
254 ret
= WINED3D_FENCE_ERROR
;
257 context_release(&context_gl
->c
);
261 enum wined3d_fence_result
wined3d_fence_wait(const struct wined3d_fence
*fence
,
262 struct wined3d_device
*device
)
264 const struct wined3d_gl_info
*gl_info
;
265 struct wined3d_context_gl
*context_gl
;
266 enum wined3d_fence_result ret
;
268 TRACE("fence %p, device %p.\n", fence
, device
);
270 if (!fence
->context_gl
)
272 TRACE("Fence not issued.\n");
273 return WINED3D_FENCE_NOT_STARTED
;
275 gl_info
= fence
->context_gl
->gl_info
;
277 if (!(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
)))
279 /* A glFinish does not reliably wait for draws in other contexts. The caller has
280 * to find its own way to cope with the thread switch
282 if (!gl_info
->supported
[ARB_SYNC
])
284 WARN("Fence finished from wrong thread.\n");
285 return WINED3D_FENCE_WRONG_THREAD
;
287 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
289 gl_info
= context_gl
->gl_info
;
291 if (gl_info
->supported
[ARB_SYNC
])
293 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
294 * possibly because macOS internally adds some slop to the timer. To avoid this,
295 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
297 GLenum gl_ret
= GL_EXTCALL(glClientWaitSync(fence
->object
.sync
,
298 GL_SYNC_FLUSH_COMMANDS_BIT
, ~(GLuint64
)0 >> 1));
299 checkGLcall("glClientWaitSync");
303 case GL_ALREADY_SIGNALED
:
304 case GL_CONDITION_SATISFIED
:
305 ret
= WINED3D_FENCE_OK
;
308 /* We don't expect a timeout for a ~292 year wait */
310 ERR("glClientWaitSync returned %#x.\n", gl_ret
);
311 ret
= WINED3D_FENCE_ERROR
;
314 else if (gl_info
->supported
[APPLE_FENCE
])
316 GL_EXTCALL(glFinishFenceAPPLE(fence
->object
.id
));
317 checkGLcall("glFinishFenceAPPLE");
318 ret
= WINED3D_FENCE_OK
;
320 else if (gl_info
->supported
[NV_FENCE
])
322 GL_EXTCALL(glFinishFenceNV(fence
->object
.id
));
323 checkGLcall("glFinishFenceNV");
324 ret
= WINED3D_FENCE_OK
;
328 ERR("Fence created without GL support.\n");
329 ret
= WINED3D_FENCE_ERROR
;
332 context_release(&context_gl
->c
);
336 void wined3d_fence_issue(struct wined3d_fence
*fence
, struct wined3d_device
*device
)
338 struct wined3d_context_gl
*context_gl
= NULL
;
339 const struct wined3d_gl_info
*gl_info
;
341 if (fence
->context_gl
&& !(context_gl
= wined3d_context_gl_reacquire(fence
->context_gl
))
342 && !fence
->context_gl
->gl_info
->supported
[ARB_SYNC
])
343 wined3d_context_gl_free_fence(fence
);
345 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
346 gl_info
= context_gl
->gl_info
;
347 if (!fence
->context_gl
)
348 wined3d_context_gl_alloc_fence(context_gl
, fence
);
350 if (gl_info
->supported
[ARB_SYNC
])
352 if (fence
->object
.sync
)
353 GL_EXTCALL(glDeleteSync(fence
->object
.sync
));
354 checkGLcall("glDeleteSync");
355 fence
->object
.sync
= GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE
, 0));
356 checkGLcall("glFenceSync");
358 else if (gl_info
->supported
[APPLE_FENCE
])
360 GL_EXTCALL(glSetFenceAPPLE(fence
->object
.id
));
361 checkGLcall("glSetFenceAPPLE");
363 else if (gl_info
->supported
[NV_FENCE
])
365 GL_EXTCALL(glSetFenceNV(fence
->object
.id
, GL_ALL_COMPLETED_NV
));
366 checkGLcall("glSetFenceNV");
369 context_release(&context_gl
->c
);
372 static void wined3d_fence_free(struct wined3d_fence
*fence
)
374 if (fence
->context_gl
)
375 wined3d_context_gl_free_fence(fence
);
378 void wined3d_fence_destroy(struct wined3d_fence
*fence
)
380 wined3d_fence_free(fence
);
384 static HRESULT
wined3d_fence_init(struct wined3d_fence
*fence
, const struct wined3d_gl_info
*gl_info
)
386 if (!wined3d_fence_supported(gl_info
))
388 WARN("Fences not supported.\n");
389 return WINED3DERR_NOTAVAILABLE
;
395 HRESULT
wined3d_fence_create(struct wined3d_device
*device
, struct wined3d_fence
**fence
)
397 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
398 struct wined3d_fence
*object
;
401 TRACE("device %p, fence %p.\n", device
, fence
);
403 if (!(object
= heap_alloc_zero(sizeof(*object
))))
404 return E_OUTOFMEMORY
;
406 if (FAILED(hr
= wined3d_fence_init(object
, gl_info
)))
412 TRACE("Created fence %p.\n", object
);
418 ULONG CDECL
wined3d_query_incref(struct wined3d_query
*query
)
420 ULONG refcount
= InterlockedIncrement(&query
->ref
);
422 TRACE("%p increasing refcount to %u.\n", query
, refcount
);
427 static void wined3d_query_destroy_object(void *object
)
429 struct wined3d_query
*query
= object
;
431 TRACE("query %p.\n", query
);
433 if (!list_empty(&query
->poll_list_entry
))
434 list_remove(&query
->poll_list_entry
);
437 ULONG CDECL
wined3d_query_decref(struct wined3d_query
*query
)
439 ULONG refcount
= InterlockedDecrement(&query
->ref
);
441 TRACE("%p decreasing refcount to %u.\n", query
, refcount
);
445 struct wined3d_device
*device
= query
->device
;
447 query
->parent_ops
->wined3d_object_destroyed(query
->parent
);
448 wined3d_cs_destroy_object(device
->cs
, wined3d_query_destroy_object
, query
);
449 device
->adapter
->adapter_ops
->adapter_destroy_query(query
);
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
->device
->cs
->thread
)
475 if (query
->counter_main
!= query
->counter_retrieved
476 || (query
->buffer_object
&& !wined3d_query_buffer_is_valid(query
)))
478 if (flags
& WINED3DGETDATA_FLUSH
&& !query
->device
->cs
->queries_flushed
)
479 query
->device
->cs
->c
.ops
->flush(&query
->device
->cs
->c
);
482 if (query
->buffer_object
)
483 query
->data
= query
->map_ptr
;
485 else if (!query
->query_ops
->query_poll(query
, flags
))
491 memcpy(data
, query
->data
, min(data_size
, query
->data_size
));
496 UINT CDECL
wined3d_query_get_data_size(const struct wined3d_query
*query
)
498 TRACE("query %p.\n", query
);
500 return query
->data_size
;
503 HRESULT CDECL
wined3d_query_issue(struct wined3d_query
*query
, DWORD flags
)
505 TRACE("query %p, flags %#x.\n", query
, flags
);
507 wined3d_device_context_issue_query(&query
->device
->cs
->c
, query
, flags
);
512 static BOOL
wined3d_occlusion_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
514 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
515 const struct wined3d_gl_info
*gl_info
;
516 struct wined3d_context_gl
*context_gl
;
519 TRACE("query %p, flags %#x.\n", query
, flags
);
521 if (!(context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
523 FIXME("%p Wrong thread, returning 1.\n", query
);
527 gl_info
= context_gl
->gl_info
;
529 GL_EXTCALL(glGetQueryObjectuiv(oq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
530 TRACE("Available %#x.\n", available
);
534 oq
->samples
= get_query_result64(oq
->id
, gl_info
);
535 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq
->samples
));
538 checkGLcall("poll occlusion query");
539 context_release(&context_gl
->c
);
544 static BOOL
wined3d_event_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
546 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
547 enum wined3d_fence_result ret
;
549 TRACE("query %p, flags %#x.\n", query
, flags
);
551 ret
= wined3d_fence_test(&event_query
->fence
, query
->device
, flags
);
554 case WINED3D_FENCE_OK
:
555 case WINED3D_FENCE_NOT_STARTED
:
556 return event_query
->signalled
= TRUE
;
558 case WINED3D_FENCE_WAITING
:
559 return event_query
->signalled
= FALSE
;
561 case WINED3D_FENCE_WRONG_THREAD
:
562 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query
);
563 return event_query
->signalled
= TRUE
;
565 case WINED3D_FENCE_ERROR
:
566 ERR("The GL event query failed.\n");
567 return event_query
->signalled
= TRUE
;
570 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret
);
571 return event_query
->signalled
= TRUE
;
575 void * CDECL
wined3d_query_get_parent(const struct wined3d_query
*query
)
577 TRACE("query %p.\n", query
);
579 return query
->parent
;
582 enum wined3d_query_type CDECL
wined3d_query_get_type(const struct wined3d_query
*query
)
584 TRACE("query %p.\n", query
);
589 static BOOL
wined3d_event_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
591 TRACE("query %p, flags %#x.\n", query
, flags
);
593 if (flags
& WINED3DISSUE_END
)
595 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
597 wined3d_fence_issue(&event_query
->fence
, query
->device
);
600 else if (flags
& WINED3DISSUE_BEGIN
)
602 /* Started implicitly at query creation. */
603 ERR("Event query issued with START flag - what to do?\n");
609 static BOOL
wined3d_occlusion_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
611 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
612 struct wined3d_device
*device
= query
->device
;
613 const struct wined3d_gl_info
*gl_info
;
614 struct wined3d_context_gl
*context_gl
;
617 TRACE("query %p, flags %#x.\n", query
, flags
);
619 /* This is allowed according to MSDN and our tests. Reset the query and
621 if (flags
& WINED3DISSUE_BEGIN
)
625 if ((context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
627 gl_info
= context_gl
->gl_info
;
628 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
629 checkGLcall("glEndQuery()");
633 FIXME("Wrong thread, can't restart query.\n");
634 wined3d_context_gl_free_occlusion_query(oq
);
635 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
636 wined3d_context_gl_alloc_occlusion_query(context_gl
, oq
);
642 wined3d_context_gl_free_occlusion_query(oq
);
643 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
644 wined3d_context_gl_alloc_occlusion_query(context_gl
, oq
);
646 gl_info
= context_gl
->gl_info
;
648 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED
, oq
->id
));
649 checkGLcall("glBeginQuery()");
651 context_release(&context_gl
->c
);
654 if (flags
& WINED3DISSUE_END
)
656 /* MSDN says END on a non-building occlusion query returns an error,
657 * but our tests show that it returns OK. But OpenGL doesn't like it,
658 * so avoid generating an error. */
661 if ((context_gl
= wined3d_context_gl_reacquire(oq
->context_gl
)))
663 gl_info
= context_gl
->gl_info
;
664 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED
));
665 checkGLcall("glEndQuery()");
666 wined3d_query_buffer_queue_result(context_gl
, query
, oq
->id
);
668 context_release(&context_gl
->c
);
673 FIXME("Wrong thread, can't end query.\n");
682 static BOOL
wined3d_timestamp_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
684 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
685 const struct wined3d_gl_info
*gl_info
;
686 struct wined3d_context_gl
*context_gl
;
690 TRACE("query %p, flags %#x.\n", query
, flags
);
692 if (!(context_gl
= wined3d_context_gl_reacquire(tq
->context_gl
)))
694 FIXME("%p Wrong thread, returning 1.\n", query
);
698 gl_info
= context_gl
->gl_info
;
700 GL_EXTCALL(glGetQueryObjectuiv(tq
->id
, GL_QUERY_RESULT_AVAILABLE
, &available
));
701 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
702 TRACE("available %#x.\n", available
);
706 GL_EXTCALL(glGetQueryObjectui64v(tq
->id
, GL_QUERY_RESULT
, ×tamp
));
707 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
708 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp
));
709 tq
->timestamp
= timestamp
;
712 context_release(&context_gl
->c
);
717 static BOOL
wined3d_timestamp_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
719 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
720 const struct wined3d_gl_info
*gl_info
;
721 struct wined3d_context_gl
*context_gl
;
723 TRACE("query %p, flags %#x.\n", query
, flags
);
725 if (flags
& WINED3DISSUE_BEGIN
)
727 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
729 if (flags
& WINED3DISSUE_END
)
732 wined3d_context_gl_free_timestamp_query(tq
);
733 context_gl
= wined3d_context_gl(context_acquire(query
->device
, NULL
, 0));
734 gl_info
= context_gl
->gl_info
;
735 wined3d_context_gl_alloc_timestamp_query(context_gl
, tq
);
736 GL_EXTCALL(glQueryCounter(tq
->id
, GL_TIMESTAMP
));
737 checkGLcall("glQueryCounter()");
738 context_release(&context_gl
->c
);
746 static BOOL
wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
748 TRACE("query %p, flags %#x.\n", query
, flags
);
753 static BOOL
wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
755 TRACE("query %p, flags %#x.\n", query
, flags
);
760 static BOOL
wined3d_so_statistics_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
762 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
763 GLuint written_available
, generated_available
;
764 const struct wined3d_gl_info
*gl_info
;
765 struct wined3d_context_gl
*context_gl
;
767 TRACE("query %p, flags %#x.\n", query
, flags
);
769 if (!(context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
771 FIXME("%p Wrong thread, returning 0 primitives.\n", query
);
772 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
775 gl_info
= context_gl
->gl_info
;
777 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.query
.written
,
778 GL_QUERY_RESULT_AVAILABLE
, &written_available
));
779 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.query
.generated
,
780 GL_QUERY_RESULT_AVAILABLE
, &generated_available
));
781 TRACE("Available %#x, %#x.\n", written_available
, generated_available
);
783 if (written_available
&& generated_available
)
785 pq
->statistics
.primitives_written
= get_query_result64(pq
->u
.query
.written
, gl_info
);
786 pq
->statistics
.primitives_generated
= get_query_result64(pq
->u
.query
.generated
, gl_info
);
787 TRACE("Returning %s, %s primitives.\n",
788 wine_dbgstr_longlong(pq
->statistics
.primitives_written
),
789 wine_dbgstr_longlong(pq
->statistics
.primitives_generated
));
792 checkGLcall("poll SO statistics query");
793 context_release(&context_gl
->c
);
795 return written_available
&& generated_available
;
798 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query
*query
,
799 struct wined3d_context_gl
*context_gl
)
801 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
803 if (gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
805 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
, query
->stream_idx
));
806 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED
, query
->stream_idx
));
810 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
));
811 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED
));
813 checkGLcall("end query");
816 static BOOL
wined3d_so_statistics_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
818 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
819 struct wined3d_device
*device
= query
->device
;
820 const struct wined3d_gl_info
*gl_info
;
821 struct wined3d_context_gl
*context_gl
;
824 TRACE("query %p, flags %#x.\n", query
, flags
);
826 if (flags
& WINED3DISSUE_BEGIN
)
830 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
832 wined3d_so_statistics_query_end(pq
, context_gl
);
836 FIXME("Wrong thread, can't restart query.\n");
837 wined3d_context_gl_free_so_statistics_query(pq
);
838 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
839 wined3d_context_gl_alloc_so_statistics_query(context_gl
, pq
);
845 wined3d_context_gl_free_so_statistics_query(pq
);
846 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
847 wined3d_context_gl_alloc_so_statistics_query(context_gl
, pq
);
849 gl_info
= context_gl
->gl_info
;
851 if (gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
853 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
,
854 pq
->stream_idx
, pq
->u
.query
.written
));
855 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED
,
856 pq
->stream_idx
, pq
->u
.query
.generated
));
860 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
,
861 pq
->u
.query
.written
));
862 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED
,
863 pq
->u
.query
.generated
));
865 checkGLcall("begin query");
867 context_release(&context_gl
->c
);
870 if (flags
& WINED3DISSUE_END
)
874 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
876 wined3d_so_statistics_query_end(pq
, context_gl
);
878 context_release(&context_gl
->c
);
883 FIXME("Wrong thread, can't end query.\n");
892 static BOOL
wined3d_pipeline_query_ops_poll(struct wined3d_query
*query
, DWORD flags
)
894 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
895 const struct wined3d_gl_info
*gl_info
;
896 struct wined3d_context_gl
*context_gl
;
900 TRACE("query %p, flags %#x.\n", query
, flags
);
902 if (!(context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
904 FIXME("%p Wrong thread.\n", query
);
905 memset(&pq
->statistics
, 0, sizeof(pq
->statistics
));
908 gl_info
= context_gl
->gl_info
;
910 for (i
= 0; i
< ARRAY_SIZE(pq
->u
.id
); ++i
)
912 GL_EXTCALL(glGetQueryObjectuiv(pq
->u
.id
[i
], GL_QUERY_RESULT_AVAILABLE
, &available
));
919 pq
->statistics
.vertices_submitted
= get_query_result64(pq
->u
.query
.vertices
, gl_info
);
920 pq
->statistics
.primitives_submitted
= get_query_result64(pq
->u
.query
.primitives
, gl_info
);
921 pq
->statistics
.vs_invocations
= get_query_result64(pq
->u
.query
.vertex_shader
, gl_info
);
922 pq
->statistics
.hs_invocations
= get_query_result64(pq
->u
.query
.tess_control_shader
, gl_info
);
923 pq
->statistics
.ds_invocations
= get_query_result64(pq
->u
.query
.tess_eval_shader
, gl_info
);
924 pq
->statistics
.gs_invocations
= get_query_result64(pq
->u
.query
.geometry_shader
, gl_info
);
925 pq
->statistics
.gs_primitives
= get_query_result64(pq
->u
.query
.geometry_primitives
, gl_info
);
926 pq
->statistics
.ps_invocations
= get_query_result64(pq
->u
.query
.fragment_shader
, gl_info
);
927 pq
->statistics
.cs_invocations
= get_query_result64(pq
->u
.query
.compute_shader
, gl_info
);
928 pq
->statistics
.clipping_input_primitives
= get_query_result64(pq
->u
.query
.clipping_input
, gl_info
);
929 pq
->statistics
.clipping_output_primitives
= get_query_result64(pq
->u
.query
.clipping_output
, gl_info
);
932 checkGLcall("poll pipeline statistics query");
933 context_release(&context_gl
->c
);
937 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query
*query
,
938 struct wined3d_context_gl
*context_gl
)
940 const struct wined3d_gl_info
*gl_info
= context_gl
->gl_info
;
942 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB
));
943 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB
));
944 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB
));
945 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB
));
946 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB
));
947 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS
));
948 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB
));
949 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB
));
950 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB
));
951 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB
));
952 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB
));
953 checkGLcall("end query");
956 static BOOL
wined3d_pipeline_query_ops_issue(struct wined3d_query
*query
, DWORD flags
)
958 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
959 struct wined3d_device
*device
= query
->device
;
960 const struct wined3d_gl_info
*gl_info
;
961 struct wined3d_context_gl
*context_gl
;
964 TRACE("query %p, flags %#x.\n", query
, flags
);
966 if (flags
& WINED3DISSUE_BEGIN
)
970 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
972 wined3d_pipeline_statistics_query_end(pq
, context_gl
);
976 FIXME("Wrong thread, can't restart query.\n");
977 wined3d_context_gl_free_pipeline_statistics_query(pq
);
978 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
979 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl
, pq
);
985 wined3d_context_gl_free_pipeline_statistics_query(pq
);
986 context_gl
= wined3d_context_gl(context_acquire(device
, NULL
, 0));
987 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl
, pq
);
989 gl_info
= context_gl
->gl_info
;
991 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB
, pq
->u
.query
.vertices
));
992 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB
, pq
->u
.query
.primitives
));
993 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.vertex_shader
));
994 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB
, pq
->u
.query
.tess_control_shader
));
995 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.tess_eval_shader
));
996 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS
, pq
->u
.query
.geometry_shader
));
997 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB
, pq
->u
.query
.geometry_primitives
));
998 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.fragment_shader
));
999 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB
, pq
->u
.query
.compute_shader
));
1000 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB
, pq
->u
.query
.clipping_input
));
1001 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB
, pq
->u
.query
.clipping_output
));
1002 checkGLcall("begin query");
1004 context_release(&context_gl
->c
);
1007 if (flags
& WINED3DISSUE_END
)
1011 if ((context_gl
= wined3d_context_gl_reacquire(pq
->context_gl
)))
1013 wined3d_pipeline_statistics_query_end(pq
, context_gl
);
1014 context_release(&context_gl
->c
);
1019 FIXME("Wrong thread, can't end query.\n");
1022 pq
->started
= FALSE
;
1028 static void wined3d_event_query_ops_destroy(struct wined3d_query
*query
)
1030 struct wined3d_event_query
*event_query
= wined3d_event_query_from_query(query
);
1032 wined3d_fence_free(&event_query
->fence
);
1033 heap_free(event_query
);
1036 static const struct wined3d_query_ops event_query_ops
=
1038 wined3d_event_query_ops_poll
,
1039 wined3d_event_query_ops_issue
,
1040 wined3d_event_query_ops_destroy
,
1043 static HRESULT
wined3d_event_query_create(struct wined3d_device
*device
,
1044 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1045 struct wined3d_query
**query
)
1047 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1048 struct wined3d_event_query
*object
;
1051 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1052 device
, type
, parent
, parent_ops
, query
);
1054 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1055 return E_OUTOFMEMORY
;
1057 if (FAILED(hr
= wined3d_fence_init(&object
->fence
, gl_info
)))
1059 WARN("Event queries not supported.\n");
1064 wined3d_query_init(&object
->query
, device
, type
, &object
->signalled
,
1065 sizeof(object
->signalled
), &event_query_ops
, parent
, parent_ops
);
1067 TRACE("Created query %p.\n", object
);
1068 *query
= &object
->query
;
1073 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query
*query
)
1075 struct wined3d_occlusion_query
*oq
= wined3d_occlusion_query_from_query(query
);
1078 wined3d_context_gl_free_occlusion_query(oq
);
1082 static const struct wined3d_query_ops occlusion_query_ops
=
1084 wined3d_occlusion_query_ops_poll
,
1085 wined3d_occlusion_query_ops_issue
,
1086 wined3d_occlusion_query_ops_destroy
,
1089 static HRESULT
wined3d_occlusion_query_create(struct wined3d_device
*device
,
1090 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1091 struct wined3d_query
**query
)
1093 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1094 struct wined3d_occlusion_query
*object
;
1096 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1097 device
, type
, parent
, parent_ops
, query
);
1099 if (!gl_info
->supported
[ARB_OCCLUSION_QUERY
])
1101 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1102 return WINED3DERR_NOTAVAILABLE
;
1105 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1106 return E_OUTOFMEMORY
;
1108 wined3d_query_init(&object
->query
, device
, type
, &object
->samples
,
1109 sizeof(object
->samples
), &occlusion_query_ops
, parent
, parent_ops
);
1111 TRACE("Created query %p.\n", object
);
1112 *query
= &object
->query
;
1117 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query
*query
)
1119 struct wined3d_timestamp_query
*tq
= wined3d_timestamp_query_from_query(query
);
1122 wined3d_context_gl_free_timestamp_query(tq
);
1126 static const struct wined3d_query_ops timestamp_query_ops
=
1128 wined3d_timestamp_query_ops_poll
,
1129 wined3d_timestamp_query_ops_issue
,
1130 wined3d_timestamp_query_ops_destroy
,
1133 static HRESULT
wined3d_timestamp_query_create(struct wined3d_device
*device
,
1134 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1135 struct wined3d_query
**query
)
1137 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1138 struct wined3d_timestamp_query
*object
;
1140 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1141 device
, type
, parent
, parent_ops
, query
);
1143 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1145 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1146 return WINED3DERR_NOTAVAILABLE
;
1149 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1150 return E_OUTOFMEMORY
;
1152 wined3d_query_init(&object
->query
, device
, type
, &object
->timestamp
,
1153 sizeof(object
->timestamp
), ×tamp_query_ops
, parent
, parent_ops
);
1155 TRACE("Created query %p.\n", object
);
1156 *query
= &object
->query
;
1161 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query
*query
)
1166 static const struct wined3d_query_ops timestamp_disjoint_query_ops
=
1168 wined3d_timestamp_disjoint_query_ops_poll
,
1169 wined3d_timestamp_disjoint_query_ops_issue
,
1170 wined3d_timestamp_disjoint_query_ops_destroy
,
1173 static HRESULT
wined3d_timestamp_disjoint_query_create(struct wined3d_device
*device
,
1174 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1175 struct wined3d_query
**query
)
1177 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1178 struct wined3d_query
*object
;
1180 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1181 device
, type
, parent
, parent_ops
, query
);
1183 if (!gl_info
->supported
[ARB_TIMER_QUERY
])
1185 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1186 return WINED3DERR_NOTAVAILABLE
;
1189 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1190 return E_OUTOFMEMORY
;
1192 if (type
== WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
)
1194 static const struct wined3d_query_data_timestamp_disjoint disjoint_data
= {1000 * 1000 * 1000, FALSE
};
1196 wined3d_query_init(object
, device
, type
, &disjoint_data
,
1197 sizeof(disjoint_data
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1201 static const UINT64 freq
= 1000 * 1000 * 1000;
1203 wined3d_query_init(object
, device
, type
, &freq
,
1204 sizeof(freq
), ×tamp_disjoint_query_ops
, parent
, parent_ops
);
1207 TRACE("Created query %p.\n", object
);
1213 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query
*query
)
1215 struct wined3d_so_statistics_query
*pq
= wined3d_so_statistics_query_from_query(query
);
1218 wined3d_context_gl_free_so_statistics_query(pq
);
1222 static const struct wined3d_query_ops so_statistics_query_ops
=
1224 wined3d_so_statistics_query_ops_poll
,
1225 wined3d_so_statistics_query_ops_issue
,
1226 wined3d_so_statistics_query_ops_destroy
,
1229 static HRESULT
wined3d_so_statistics_query_create(struct wined3d_device
*device
,
1230 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1231 struct wined3d_query
**query
)
1233 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1234 struct wined3d_so_statistics_query
*object
;
1235 unsigned int stream_idx
;
1237 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
<= type
&& type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1238 stream_idx
= type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
;
1239 else if (type
== WINED3D_QUERY_TYPE_SO_STATISTICS
)
1242 return WINED3DERR_NOTAVAILABLE
;
1244 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1245 device
, type
, parent
, parent_ops
, query
);
1247 if (!gl_info
->supported
[WINED3D_GL_PRIMITIVE_QUERY
])
1249 WARN("OpenGL implementation does not support primitive queries.\n");
1250 return WINED3DERR_NOTAVAILABLE
;
1252 if (stream_idx
&& !gl_info
->supported
[ARB_TRANSFORM_FEEDBACK3
])
1254 WARN("OpenGL implementation does not support indexed queries.\n");
1255 return WINED3DERR_NOTAVAILABLE
;
1258 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1259 return E_OUTOFMEMORY
;
1261 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1262 sizeof(object
->statistics
), &so_statistics_query_ops
, parent
, parent_ops
);
1263 object
->stream_idx
= stream_idx
;
1265 TRACE("Created query %p.\n", object
);
1266 *query
= &object
->query
;
1271 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query
*query
)
1273 struct wined3d_pipeline_statistics_query
*pq
= wined3d_pipeline_statistics_query_from_query(query
);
1275 wined3d_context_gl_free_pipeline_statistics_query(pq
);
1279 static const struct wined3d_query_ops pipeline_query_ops
=
1281 wined3d_pipeline_query_ops_poll
,
1282 wined3d_pipeline_query_ops_issue
,
1283 wined3d_pipeline_query_ops_destroy
,
1286 static HRESULT
wined3d_pipeline_query_create(struct wined3d_device
*device
,
1287 enum wined3d_query_type type
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1288 struct wined3d_query
**query
)
1290 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1291 struct wined3d_pipeline_statistics_query
*object
;
1293 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1294 device
, type
, parent
, parent_ops
, query
);
1296 if (!gl_info
->supported
[ARB_PIPELINE_STATISTICS_QUERY
])
1298 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1299 return WINED3DERR_NOTAVAILABLE
;
1302 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1303 return E_OUTOFMEMORY
;
1305 wined3d_query_init(&object
->query
, device
, type
, &object
->statistics
,
1306 sizeof(object
->statistics
), &pipeline_query_ops
, parent
, parent_ops
);
1308 TRACE("Created query %p.\n", object
);
1309 *query
= &object
->query
;
1314 HRESULT
wined3d_query_gl_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1315 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1317 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1318 device
, type
, parent
, parent_ops
, query
);
1322 case WINED3D_QUERY_TYPE_EVENT
:
1323 return wined3d_event_query_create(device
, type
, parent
, parent_ops
, query
);
1325 case WINED3D_QUERY_TYPE_OCCLUSION
:
1326 return wined3d_occlusion_query_create(device
, type
, parent
, parent_ops
, query
);
1328 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1329 return wined3d_timestamp_query_create(device
, type
, parent
, parent_ops
, query
);
1331 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1332 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ
:
1333 return wined3d_timestamp_disjoint_query_create(device
, type
, parent
, parent_ops
, query
);
1335 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1336 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1337 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1338 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1339 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1340 return wined3d_so_statistics_query_create(device
, type
, parent
, parent_ops
, query
);
1342 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1343 return wined3d_pipeline_query_create(device
, type
, parent
, parent_ops
, query
);
1346 FIXME("Unhandled query type %#x.\n", type
);
1347 return WINED3DERR_NOTAVAILABLE
;
1351 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk
*pool_vk
, size_t idx
,
1352 struct wined3d_context_vk
*context_vk
)
1354 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1356 if (vk_info
->supported
[WINED3D_VK_EXT_HOST_QUERY_RESET
])
1358 VK_CALL(vkResetQueryPoolEXT(wined3d_device_vk(context_vk
->c
.device
)->vk_device
,
1359 pool_vk
->vk_query_pool
, idx
, 1));
1361 wined3d_bitmap_clear(pool_vk
->allocated
, idx
);
1362 if (list_empty(&pool_vk
->entry
))
1363 list_add_tail(pool_vk
->free_list
, &pool_vk
->entry
);
1367 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1368 * outside of a render pass. Queue the query to be reset in wined3d_query_pool_vk_reset()
1369 * instead, which is called when the render pass ends. */
1370 wined3d_bitmap_set(pool_vk
->completed
, idx
);
1371 if (list_empty(&pool_vk
->completed_entry
))
1372 list_add_tail(&context_vk
->completed_query_pools
, &pool_vk
->completed_entry
);
1376 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk
*pool_vk
, size_t *idx
)
1378 if ((*idx
= wined3d_bitmap_ffz(pool_vk
->allocated
, WINED3D_QUERY_POOL_SIZE
, 0)) > WINED3D_QUERY_POOL_SIZE
)
1380 wined3d_bitmap_set(pool_vk
->allocated
, *idx
);
1385 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk
*pool_vk
, struct wined3d_context_vk
*context_vk
)
1387 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(context_vk
->c
.device
);
1388 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1390 VK_CALL(vkDestroyQueryPool(device_vk
->vk_device
, pool_vk
->vk_query_pool
, NULL
));
1391 list_remove(&pool_vk
->entry
);
1392 list_remove(&pool_vk
->completed_entry
);
1395 void wined3d_query_pool_vk_reset(struct wined3d_query_pool_vk
*pool_vk
, struct wined3d_context_vk
*context_vk
,
1396 VkCommandBuffer vk_command_buffer
)
1398 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1399 unsigned int start
= 0, idx
;
1400 struct wined3d_range range
;
1404 if (!wined3d_bitmap_get_range(pool_vk
->completed
, WINED3D_QUERY_POOL_SIZE
, start
, &range
))
1407 VK_CALL(vkCmdResetQueryPool(vk_command_buffer
, pool_vk
->vk_query_pool
, range
.offset
, range
.size
));
1408 start
= range
.offset
+ range
.size
;
1409 for (idx
= range
.offset
; idx
< start
; ++idx
)
1410 wined3d_bitmap_clear(pool_vk
->allocated
, idx
);
1412 memset(pool_vk
->completed
, 0, sizeof(pool_vk
->completed
));
1413 if (list_empty(&pool_vk
->entry
))
1414 list_add_tail(pool_vk
->free_list
, &pool_vk
->entry
);
1417 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk
*pool_vk
,
1418 struct wined3d_context_vk
*context_vk
, enum wined3d_query_type type
, struct list
*free_pools
)
1420 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(context_vk
->c
.device
);
1421 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1422 VkQueryPoolCreateInfo pool_info
;
1425 list_init(&pool_vk
->entry
);
1426 list_init(&pool_vk
->completed_entry
);
1427 pool_vk
->free_list
= free_pools
;
1429 pool_info
.sType
= VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO
;
1430 pool_info
.pNext
= NULL
;
1431 pool_info
.flags
= 0;
1432 pool_info
.queryCount
= WINED3D_QUERY_POOL_SIZE
;
1436 case WINED3D_QUERY_TYPE_OCCLUSION
:
1437 pool_info
.queryType
= VK_QUERY_TYPE_OCCLUSION
;
1438 pool_info
.pipelineStatistics
= 0;
1441 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1442 pool_info
.queryType
= VK_QUERY_TYPE_TIMESTAMP
;
1443 pool_info
.pipelineStatistics
= 0;
1446 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1447 pool_info
.queryType
= VK_QUERY_TYPE_PIPELINE_STATISTICS
;
1448 pool_info
.pipelineStatistics
= VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1449 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1450 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1451 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1452 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1453 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1454 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1455 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1456 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1457 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1458 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT
;
1461 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1462 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1463 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1464 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1465 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1466 pool_info
.queryType
= VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
;
1467 pool_info
.pipelineStatistics
= 0;
1471 FIXME("Unhandled query type %#x.\n", type
);
1475 if ((vr
= VK_CALL(vkCreateQueryPool(device_vk
->vk_device
, &pool_info
, NULL
, &pool_vk
->vk_query_pool
))) < 0)
1477 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr
));
1481 list_add_head(free_pools
, &pool_vk
->entry
);
1486 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk
*query_vk
,
1487 struct wined3d_context_vk
*context_vk
, const struct wined3d_query_pool_idx_vk
*pool_idx
)
1489 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(context_vk
->c
.device
);
1490 const struct wined3d_query_data_pipeline_statistics
*ps_tmp
;
1491 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1492 struct wined3d_query_data_pipeline_statistics
*ps_result
;
1498 struct wined3d_query_data_pipeline_statistics pipeline_statistics
;
1499 struct wined3d_query_data_so_statistics so_statistics
;
1502 if ((vr
= VK_CALL(vkGetQueryPoolResults(device_vk
->vk_device
, pool_idx
->pool_vk
->vk_query_pool
,
1503 pool_idx
->idx
, 1, sizeof(tmp
), &tmp
, sizeof(tmp
), VK_QUERY_RESULT_64_BIT
))) < 0)
1505 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr
));
1509 if (vr
== VK_NOT_READY
)
1512 wined3d_query_pool_vk_mark_complete(pool_idx
->pool_vk
, pool_idx
->idx
, context_vk
);
1514 result
= (void *)query_vk
->q
.data
;
1515 switch (query_vk
->q
.type
)
1517 case WINED3D_QUERY_TYPE_OCCLUSION
:
1518 result
->occlusion
+= tmp
.occlusion
;
1521 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1522 result
->timestamp
= tmp
.timestamp
;
1525 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1526 ps_result
= &result
->pipeline_statistics
;
1527 ps_tmp
= &tmp
.pipeline_statistics
;
1528 ps_result
->vertices_submitted
+= ps_tmp
->vertices_submitted
;
1529 ps_result
->primitives_submitted
+= ps_tmp
->primitives_submitted
;
1530 ps_result
->vs_invocations
+= ps_tmp
->vs_invocations
;
1531 ps_result
->gs_invocations
+= ps_tmp
->gs_invocations
;
1532 ps_result
->gs_primitives
+= ps_tmp
->gs_primitives
;
1533 ps_result
->clipping_input_primitives
+= ps_tmp
->clipping_input_primitives
;
1534 ps_result
->clipping_output_primitives
+= ps_tmp
->clipping_output_primitives
;
1535 ps_result
->ps_invocations
+= ps_tmp
->ps_invocations
;
1536 ps_result
->hs_invocations
+= ps_tmp
->hs_invocations
;
1537 ps_result
->ds_invocations
+= ps_tmp
->ds_invocations
;
1538 ps_result
->cs_invocations
+= ps_tmp
->cs_invocations
;
1541 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1542 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1543 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1544 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1545 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1546 result
->so_statistics
.primitives_written
+= tmp
.so_statistics
.primitives_written
;
1547 result
->so_statistics
.primitives_generated
+= tmp
.so_statistics
.primitives_generated
;
1551 FIXME("Unhandled query type %#x.\n", query_vk
->q
.type
);
1558 static void wined3d_query_vk_begin(struct wined3d_query_vk
*query_vk
,
1559 struct wined3d_context_vk
*context_vk
, VkCommandBuffer vk_command_buffer
)
1561 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1562 struct wined3d_query_pool_vk
*pool_vk
;
1565 pool_vk
= query_vk
->pool_idx
.pool_vk
;
1566 idx
= query_vk
->pool_idx
.idx
;
1568 if (query_vk
->q
.type
>= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1569 && query_vk
->q
.type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1570 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
,
1571 query_vk
->control_flags
, query_vk
->q
.type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
));
1573 VK_CALL(vkCmdBeginQuery(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
, query_vk
->control_flags
));
1574 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1577 static void wined3d_query_vk_end(struct wined3d_query_vk
*query_vk
,
1578 struct wined3d_context_vk
*context_vk
, VkCommandBuffer vk_command_buffer
)
1580 const struct wined3d_vk_info
*vk_info
= context_vk
->vk_info
;
1581 struct wined3d_query_pool_vk
*pool_vk
;
1584 pool_vk
= query_vk
->pool_idx
.pool_vk
;
1585 idx
= query_vk
->pool_idx
.idx
;
1587 if (query_vk
->q
.type
>= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1588 && query_vk
->q
.type
<= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
)
1589 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer
, pool_vk
->vk_query_pool
,
1590 idx
, query_vk
->q
.type
- WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
));
1592 VK_CALL(vkCmdEndQuery(vk_command_buffer
, pool_vk
->vk_query_pool
, idx
));
1595 void wined3d_query_vk_resume(struct wined3d_query_vk
*query_vk
, struct wined3d_context_vk
*context_vk
)
1597 VkCommandBuffer vk_command_buffer
= context_vk
->current_command_buffer
.vk_command_buffer
;
1599 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1600 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
;
1603 void wined3d_query_vk_suspend(struct wined3d_query_vk
*query_vk
, struct wined3d_context_vk
*context_vk
)
1605 VkCommandBuffer vk_command_buffer
= context_vk
->current_command_buffer
.vk_command_buffer
;
1607 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1608 wined3d_context_vk_add_pending_query(context_vk
, query_vk
);
1609 query_vk
->pool_idx
.pool_vk
= NULL
;
1610 query_vk
->flags
&= ~WINED3D_QUERY_VK_FLAG_ACTIVE
;
1613 static BOOL
wined3d_query_vk_poll(struct wined3d_query
*query
, uint32_t flags
)
1615 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1616 struct wined3d_context_vk
*context_vk
;
1618 context_vk
= wined3d_context_vk(context_acquire(query
->device
, NULL
, 0));
1620 if (flags
& WINED3DGETDATA_FLUSH
)
1621 wined3d_context_vk_submit_command_buffer(context_vk
, 0, NULL
, NULL
, 0, NULL
);
1622 if (query_vk
->command_buffer_id
== context_vk
->current_command_buffer
.id
)
1625 if (query_vk
->command_buffer_id
> context_vk
->completed_command_buffer_id
)
1626 wined3d_context_vk_poll_command_buffers(context_vk
);
1627 if (query_vk
->command_buffer_id
> context_vk
->completed_command_buffer_id
)
1630 if (query_vk
->pending_count
)
1631 wined3d_context_vk_accumulate_pending_queries(context_vk
);
1632 if (query_vk
->pending_count
)
1635 /* If the query was suspended, and then ended before it was resumed,
1636 * there's no data to accumulate here. */
1637 if (query_vk
->pool_idx
.pool_vk
&& !wined3d_query_vk_accumulate_data(query_vk
, context_vk
, &query_vk
->pool_idx
))
1640 query_vk
->pool_idx
.pool_vk
= NULL
;
1641 context_release(&context_vk
->c
);
1646 context_release(&context_vk
->c
);
1650 static BOOL
wined3d_query_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1652 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1653 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1654 struct wined3d_context_vk
*context_vk
;
1655 VkCommandBuffer vk_command_buffer
;
1658 TRACE("query %p, flags %#x.\n", query
, flags
);
1660 if (flags
& WINED3DISSUE_BEGIN
)
1662 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1664 list_remove(&query_vk
->entry
);
1665 if (query_vk
->pending_count
)
1666 wined3d_context_vk_remove_pending_queries(context_vk
, query_vk
);
1667 memset((void *)query
->data
, 0, query
->data_size
);
1668 vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1669 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1671 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_ACTIVE
)
1672 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1673 list_remove(&query_vk
->entry
);
1675 if (query_vk
->pool_idx
.pool_vk
)
1676 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
,
1677 query_vk
->pool_idx
.idx
, context_vk
);
1679 if (!wined3d_context_vk_allocate_query(context_vk
, query_vk
->q
.type
, &query_vk
->pool_idx
))
1681 ERR("Failed to allocate new query.\n");
1685 /* A query need to either begin and end inside a single render pass,
1686 * or begin and end ouside of a render pass. Occlusion queries, if issued
1687 * ouside of a render pass, are queued up and only begun when a render
1688 * pass is started, to avoid interrupting it when the query ends. */
1689 if (context_vk
->vk_render_pass
)
1691 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1692 list_add_head(&context_vk
->render_pass_queries
, &query_vk
->entry
);
1693 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
| WINED3D_QUERY_VK_FLAG_RENDER_PASS
;
1695 else if (query
->type
== WINED3D_QUERY_TYPE_OCCLUSION
)
1697 list_add_head(&context_vk
->render_pass_queries
, &query_vk
->entry
);
1698 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_RENDER_PASS
;
1702 wined3d_query_vk_begin(query_vk
, context_vk
, vk_command_buffer
);
1703 list_add_head(&context_vk
->active_queries
, &query_vk
->entry
);
1704 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_ACTIVE
;
1707 query_vk
->flags
|= WINED3D_QUERY_VK_FLAG_STARTED
;
1708 context_release(&context_vk
->c
);
1710 if (flags
& WINED3DISSUE_END
&& query_vk
->flags
& WINED3D_QUERY_VK_FLAG_STARTED
)
1712 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1714 /* If the query was already ended because the command buffer was
1715 * flushed or the render pass ended, we don't need to end it here. */
1716 if (query_vk
->flags
& WINED3D_QUERY_VK_FLAG_ACTIVE
)
1718 vk_command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1719 if (!(query_vk
->flags
& WINED3D_QUERY_VK_FLAG_RENDER_PASS
))
1720 wined3d_context_vk_end_current_render_pass(context_vk
);
1721 wined3d_query_vk_end(query_vk
, context_vk
, vk_command_buffer
);
1723 else if (query_vk
->pool_idx
.pool_vk
)
1725 /* It was queued, but never activated. */
1726 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
,
1727 query_vk
->pool_idx
.idx
, context_vk
);
1728 query_vk
->pool_idx
.pool_vk
= NULL
;
1730 list_remove(&query_vk
->entry
);
1731 query_vk
->flags
= 0;
1734 context_release(&context_vk
->c
);
1740 static void wined3d_query_vk_destroy(struct wined3d_query
*query
)
1742 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1743 struct wined3d_context_vk
*context_vk
;
1745 list_remove(&query_vk
->entry
);
1746 if (query_vk
->pending_count
)
1748 context_vk
= wined3d_context_vk(context_acquire(query_vk
->q
.device
, NULL
, 0));
1749 wined3d_context_vk_remove_pending_queries(context_vk
, query_vk
);
1750 context_release(&context_vk
->c
);
1752 heap_free(query_vk
);
1755 static const struct wined3d_query_ops wined3d_query_vk_ops
=
1757 .query_poll
= wined3d_query_vk_poll
,
1758 .query_issue
= wined3d_query_vk_issue
,
1759 .query_destroy
= wined3d_query_vk_destroy
,
1762 static BOOL
wined3d_query_event_vk_poll(struct wined3d_query
*query
, uint32_t flags
)
1764 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1765 struct wined3d_context_vk
*context_vk
;
1768 context_vk
= wined3d_context_vk(context_acquire(query
->device
, NULL
, 0));
1770 signalled
= (BOOL
*)query
->data
;
1771 if (flags
& WINED3DGETDATA_FLUSH
)
1772 wined3d_context_vk_submit_command_buffer(context_vk
, 0, NULL
, NULL
, 0, NULL
);
1773 if (query_vk
->command_buffer_id
== context_vk
->current_command_buffer
.id
)
1775 context_release(&context_vk
->c
);
1776 return *signalled
= FALSE
;
1779 if (query_vk
->command_buffer_id
> context_vk
->completed_command_buffer_id
)
1780 wined3d_context_vk_poll_command_buffers(context_vk
);
1781 *signalled
= context_vk
->completed_command_buffer_id
>= query_vk
->command_buffer_id
;
1783 context_release(&context_vk
->c
);
1788 static BOOL
wined3d_query_event_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1790 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1791 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1792 struct wined3d_context_vk
*context_vk
;
1794 TRACE("query %p, flags %#x.\n", query
, flags
);
1796 if (flags
& WINED3DISSUE_END
)
1798 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1799 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1800 /* Because we don't actually submit any commands to the command buffer
1801 * for event queries, the context's current command buffer may still
1802 * be empty, and we should wait on the preceding command buffer
1803 * instead. That's not merely an optimisation; if the command buffer
1804 * referenced by the query is still empty by the time the application
1805 * waits for it, that wait will never complete. */
1806 if (!context_vk
->current_command_buffer
.vk_command_buffer
)
1807 --query_vk
->command_buffer_id
;
1808 context_release(&context_vk
->c
);
1816 static const struct wined3d_query_ops wined3d_query_event_vk_ops
=
1818 .query_poll
= wined3d_query_event_vk_poll
,
1819 .query_issue
= wined3d_query_event_vk_issue
,
1820 .query_destroy
= wined3d_query_vk_destroy
,
1823 static BOOL
wined3d_query_timestamp_vk_issue(struct wined3d_query
*query
, uint32_t flags
)
1825 struct wined3d_device_vk
*device_vk
= wined3d_device_vk(query
->device
);
1826 struct wined3d_query_vk
*query_vk
= wined3d_query_vk(query
);
1827 const struct wined3d_vk_info
*vk_info
;
1828 struct wined3d_context_vk
*context_vk
;
1829 VkCommandBuffer command_buffer
;
1831 TRACE("query %p, flags %#x.\n", query
, flags
);
1833 if (flags
& WINED3DISSUE_BEGIN
)
1834 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1836 if (flags
& WINED3DISSUE_END
)
1838 context_vk
= wined3d_context_vk(context_acquire(&device_vk
->d
, NULL
, 0));
1839 vk_info
= context_vk
->vk_info
;
1841 command_buffer
= wined3d_context_vk_get_command_buffer(context_vk
);
1842 if (query_vk
->pool_idx
.pool_vk
)
1843 wined3d_query_pool_vk_mark_complete(query_vk
->pool_idx
.pool_vk
, query_vk
->pool_idx
.idx
, context_vk
);
1844 if (!wined3d_context_vk_allocate_query(context_vk
, query_vk
->q
.type
, &query_vk
->pool_idx
))
1846 ERR("Failed to allocate new query.\n");
1849 VK_CALL(vkCmdWriteTimestamp(command_buffer
, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
,
1850 query_vk
->pool_idx
.pool_vk
->vk_query_pool
, query_vk
->pool_idx
.idx
));
1851 wined3d_context_vk_reference_query(context_vk
, query_vk
);
1853 context_release(&context_vk
->c
);
1861 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops
=
1863 .query_poll
= wined3d_query_vk_poll
,
1864 .query_issue
= wined3d_query_timestamp_vk_issue
,
1865 .query_destroy
= wined3d_query_vk_destroy
,
1868 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops
=
1870 .query_poll
= wined3d_timestamp_disjoint_query_ops_poll
,
1871 .query_issue
= wined3d_timestamp_disjoint_query_ops_issue
,
1872 .query_destroy
= wined3d_query_vk_destroy
,
1875 HRESULT
wined3d_query_vk_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1876 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1878 struct wined3d_query_data_timestamp_disjoint
*disjoint_data
;
1879 const struct wined3d_query_ops
*ops
= &wined3d_query_vk_ops
;
1880 struct wined3d_query_vk
*query_vk
;
1881 unsigned int data_size
;
1884 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1885 device
, type
, parent
, parent_ops
, query
);
1889 case WINED3D_QUERY_TYPE_EVENT
:
1890 ops
= &wined3d_query_event_vk_ops
;
1891 data_size
= sizeof(BOOL
);
1894 case WINED3D_QUERY_TYPE_OCCLUSION
:
1895 data_size
= sizeof(uint64_t);
1898 case WINED3D_QUERY_TYPE_TIMESTAMP
:
1899 if (!wined3d_device_vk(device
)->timestamp_bits
)
1901 WARN("Timestamp queries not supported.\n");
1902 return WINED3DERR_NOTAVAILABLE
;
1904 ops
= &wined3d_query_timestamp_vk_ops
;
1905 data_size
= sizeof(uint64_t);
1908 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1909 if (!wined3d_device_vk(device
)->timestamp_bits
)
1911 WARN("Timestamp queries not supported.\n");
1912 return WINED3DERR_NOTAVAILABLE
;
1914 ops
= &wined3d_query_timestamp_disjoint_vk_ops
;
1915 data_size
= sizeof(struct wined3d_query_data_timestamp_disjoint
);
1918 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS
:
1919 data_size
= sizeof(struct wined3d_query_data_pipeline_statistics
);
1922 case WINED3D_QUERY_TYPE_SO_STATISTICS
:
1923 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0
:
1924 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
:
1925 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2
:
1926 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3
:
1927 if (!wined3d_adapter_vk(device
->adapter
)->vk_info
.supported
[WINED3D_VK_EXT_TRANSFORM_FEEDBACK
])
1929 WARN("Stream output queries not supported.\n");
1930 return WINED3DERR_NOTAVAILABLE
;
1932 data_size
= sizeof(struct wined3d_query_data_so_statistics
);
1936 FIXME("Unhandled query type %#x.\n", type
);
1937 return WINED3DERR_NOTAVAILABLE
;
1940 if (!(query_vk
= heap_alloc_zero(sizeof(*query_vk
) + data_size
)))
1941 return E_OUTOFMEMORY
;
1942 data
= query_vk
+ 1;
1944 wined3d_query_init(&query_vk
->q
, device
, type
, data
, data_size
, ops
, parent
, parent_ops
);
1945 list_init(&query_vk
->entry
);
1949 case WINED3D_QUERY_TYPE_OCCLUSION
:
1950 query_vk
->control_flags
= VK_QUERY_CONTROL_PRECISE_BIT
;
1953 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
:
1954 disjoint_data
= data
;
1955 disjoint_data
->frequency
= 1000000000 / wined3d_adapter_vk(device
->adapter
)->device_limits
.timestampPeriod
;
1956 disjoint_data
->disjoint
= FALSE
;
1963 TRACE("Created query %p.\n", query_vk
);
1964 *query
= &query_vk
->q
;
1969 HRESULT CDECL
wined3d_query_create(struct wined3d_device
*device
, enum wined3d_query_type type
,
1970 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_query
**query
)
1972 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1973 device
, type
, parent
, parent_ops
, query
);
1975 return device
->adapter
->adapter_ops
->adapter_create_query(device
, type
, parent
, parent_ops
, query
);