wined3d: Use a single allocation for timestamp queries.
[wine.git] / dlls / wined3d / query.c
blob976cdd992978764518fa082ab1a796d495804948
1 /*
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
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
28 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
29 enum wined3d_query_type type, DWORD data_size, const struct wined3d_query_ops *query_ops, void *parent)
31 query->ref = 1;
32 query->parent = parent;
33 query->device = device;
34 query->state = QUERY_CREATED;
35 query->type = type;
36 query->data_size = data_size;
37 query->query_ops = query_ops;
40 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
42 return CONTAINING_RECORD(query, struct wined3d_event_query, query);
45 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
47 return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
50 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
52 return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
55 BOOL wined3d_event_query_supported(const struct wined3d_gl_info *gl_info)
57 return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
60 void wined3d_event_query_destroy(struct wined3d_event_query *query)
62 if (query->context) context_free_event_query(query);
63 HeapFree(GetProcessHeap(), 0, query);
66 static enum wined3d_event_query_result wined3d_event_query_test(const struct wined3d_event_query *query,
67 const struct wined3d_device *device)
69 struct wined3d_context *context;
70 const struct wined3d_gl_info *gl_info;
71 enum wined3d_event_query_result ret;
72 BOOL fence_result;
74 TRACE("(%p) : device %p\n", query, device);
76 if (!query->context)
78 TRACE("Query not started\n");
79 return WINED3D_EVENT_QUERY_NOT_STARTED;
82 if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
84 WARN("Event query tested from wrong thread\n");
85 return WINED3D_EVENT_QUERY_WRONG_THREAD;
88 context = context_acquire(device, context_get_rt_surface(query->context));
89 gl_info = context->gl_info;
91 if (gl_info->supported[ARB_SYNC])
93 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, 0));
94 checkGLcall("glClientWaitSync");
96 switch (gl_ret)
98 case GL_ALREADY_SIGNALED:
99 case GL_CONDITION_SATISFIED:
100 ret = WINED3D_EVENT_QUERY_OK;
101 break;
103 case GL_TIMEOUT_EXPIRED:
104 ret = WINED3D_EVENT_QUERY_WAITING;
105 break;
107 case GL_WAIT_FAILED:
108 default:
109 ERR("glClientWaitSync returned %#x.\n", gl_ret);
110 ret = WINED3D_EVENT_QUERY_ERROR;
113 else if (gl_info->supported[APPLE_FENCE])
115 fence_result = GL_EXTCALL(glTestFenceAPPLE(query->object.id));
116 checkGLcall("glTestFenceAPPLE");
117 if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
118 else ret = WINED3D_EVENT_QUERY_WAITING;
120 else if (gl_info->supported[NV_FENCE])
122 fence_result = GL_EXTCALL(glTestFenceNV(query->object.id));
123 checkGLcall("glTestFenceNV");
124 if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
125 else ret = WINED3D_EVENT_QUERY_WAITING;
127 else
129 ERR("Event query created despite lack of GL support\n");
130 ret = WINED3D_EVENT_QUERY_ERROR;
133 context_release(context);
134 return ret;
137 enum wined3d_event_query_result wined3d_event_query_finish(const struct wined3d_event_query *query,
138 const struct wined3d_device *device)
140 struct wined3d_context *context;
141 const struct wined3d_gl_info *gl_info;
142 enum wined3d_event_query_result ret;
144 TRACE("query %p, device %p.\n", query, device);
146 if (!query->context)
148 TRACE("Query not started\n");
149 return WINED3D_EVENT_QUERY_NOT_STARTED;
151 gl_info = query->context->gl_info;
153 if (query->context->tid != GetCurrentThreadId() && !gl_info->supported[ARB_SYNC])
155 /* A glFinish does not reliably wait for draws in other contexts. The caller has
156 * to find its own way to cope with the thread switch
158 WARN("Event query finished from wrong thread\n");
159 return WINED3D_EVENT_QUERY_WRONG_THREAD;
162 context = context_acquire(device, context_get_rt_surface(query->context));
164 if (gl_info->supported[ARB_SYNC])
166 /* Apple seems to be into arbitrary limits, and timeouts larger than
167 * 0xfffffffffffffbff immediately return GL_TIMEOUT_EXPIRED. We don't
168 * really care and can live with waiting a few μs less. (OS X 10.7.4). */
169 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0xffff));
170 checkGLcall("glClientWaitSync");
172 switch (gl_ret)
174 case GL_ALREADY_SIGNALED:
175 case GL_CONDITION_SATISFIED:
176 ret = WINED3D_EVENT_QUERY_OK;
177 break;
179 /* We don't expect a timeout for a ~584 year wait */
180 default:
181 ERR("glClientWaitSync returned %#x.\n", gl_ret);
182 ret = WINED3D_EVENT_QUERY_ERROR;
185 else if (context->gl_info->supported[APPLE_FENCE])
187 GL_EXTCALL(glFinishFenceAPPLE(query->object.id));
188 checkGLcall("glFinishFenceAPPLE");
189 ret = WINED3D_EVENT_QUERY_OK;
191 else if (context->gl_info->supported[NV_FENCE])
193 GL_EXTCALL(glFinishFenceNV(query->object.id));
194 checkGLcall("glFinishFenceNV");
195 ret = WINED3D_EVENT_QUERY_OK;
197 else
199 ERR("Event query created without GL support\n");
200 ret = WINED3D_EVENT_QUERY_ERROR;
203 context_release(context);
204 return ret;
207 void wined3d_event_query_issue(struct wined3d_event_query *query, const struct wined3d_device *device)
209 const struct wined3d_gl_info *gl_info;
210 struct wined3d_context *context;
212 if (query->context)
214 if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
216 context_free_event_query(query);
217 context = context_acquire(device, NULL);
218 context_alloc_event_query(context, query);
220 else
222 context = context_acquire(device, context_get_rt_surface(query->context));
225 else
227 context = context_acquire(device, NULL);
228 context_alloc_event_query(context, query);
231 gl_info = context->gl_info;
233 if (gl_info->supported[ARB_SYNC])
235 if (query->object.sync) GL_EXTCALL(glDeleteSync(query->object.sync));
236 checkGLcall("glDeleteSync");
237 query->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
238 checkGLcall("glFenceSync");
240 else if (gl_info->supported[APPLE_FENCE])
242 GL_EXTCALL(glSetFenceAPPLE(query->object.id));
243 checkGLcall("glSetFenceAPPLE");
245 else if (gl_info->supported[NV_FENCE])
247 GL_EXTCALL(glSetFenceNV(query->object.id, GL_ALL_COMPLETED_NV));
248 checkGLcall("glSetFenceNV");
251 context_release(context);
254 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
256 ULONG refcount = InterlockedIncrement(&query->ref);
258 TRACE("%p increasing refcount to %u.\n", query, refcount);
260 return refcount;
263 static void wined3d_query_destroy_object(void *object)
265 struct wined3d_query *query = object;
267 /* Queries are specific to the GL context that created them. Not
268 * deleting the query will obviously leak it, but that's still better
269 * than potentially deleting a different query with the same id in this
270 * context, and (still) leaking the actual query. */
271 if (query->type == WINED3D_QUERY_TYPE_EVENT)
273 wined3d_event_query_destroy(wined3d_event_query_from_query(query));
274 return;
276 else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
278 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
280 if (oq->context)
281 context_free_occlusion_query(oq);
282 HeapFree(GetProcessHeap(), 0, oq);
283 return;
285 else if (query->type == WINED3D_QUERY_TYPE_TIMESTAMP)
287 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
289 if (tq->context)
290 context_free_timestamp_query(tq);
291 HeapFree(GetProcessHeap(), 0, tq);
292 return;
295 HeapFree(GetProcessHeap(), 0, query);
298 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
300 ULONG refcount = InterlockedDecrement(&query->ref);
302 TRACE("%p decreasing refcount to %u.\n", query, refcount);
304 if (!refcount)
305 wined3d_cs_emit_destroy_object(query->device->cs, wined3d_query_destroy_object, query);
307 return refcount;
310 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
311 void *data, UINT data_size, DWORD flags)
313 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
314 query, data, data_size, flags);
316 return query->query_ops->query_get_data(query, data, data_size, flags);
319 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
321 TRACE("query %p.\n", query);
323 return query->data_size;
326 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
328 TRACE("query %p, flags %#x.\n", query, flags);
330 return query->query_ops->query_issue(query, flags);
333 static void fill_query_data(void *out, unsigned int out_size, const void *result, unsigned int result_size)
335 memcpy(out, result, min(out_size, result_size));
338 static HRESULT wined3d_occlusion_query_ops_get_data(struct wined3d_query *query,
339 void *data, DWORD size, DWORD flags)
341 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
342 struct wined3d_device *device = query->device;
343 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
344 struct wined3d_context *context;
345 GLuint available;
346 GLuint samples;
347 HRESULT res;
349 TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
351 if (!oq->context)
352 query->state = QUERY_CREATED;
354 if (query->state == QUERY_CREATED)
356 /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
357 TRACE("Query wasn't yet started, returning S_OK\n");
358 samples = 0;
359 fill_query_data(data, size, &samples, sizeof(samples));
360 return S_OK;
363 if (query->state == QUERY_BUILDING)
365 /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
366 TRACE("Query is building, returning S_FALSE\n");
367 return S_FALSE;
370 if (oq->context->tid != GetCurrentThreadId())
372 FIXME("%p Wrong thread, returning 1.\n", query);
373 samples = 1;
374 fill_query_data(data, size, &samples, sizeof(samples));
375 return S_OK;
378 context = context_acquire(device, context_get_rt_surface(oq->context));
380 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
381 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
382 TRACE("available %#x.\n", available);
384 if (available)
386 if (size)
388 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT, &samples));
389 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT)");
390 TRACE("Returning %d samples.\n", samples);
391 fill_query_data(data, size, &samples, sizeof(samples));
393 res = S_OK;
395 else
397 res = S_FALSE;
400 context_release(context);
402 return res;
405 static HRESULT wined3d_event_query_ops_get_data(struct wined3d_query *query,
406 void *data, DWORD size, DWORD flags)
408 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
409 enum wined3d_event_query_result ret;
410 BOOL signaled;
412 TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
414 if (!data || !size)
415 return S_OK;
417 ret = wined3d_event_query_test(event_query, query->device);
418 switch(ret)
420 case WINED3D_EVENT_QUERY_OK:
421 case WINED3D_EVENT_QUERY_NOT_STARTED:
422 signaled = TRUE;
423 fill_query_data(data, size, &signaled, sizeof(signaled));
424 break;
426 case WINED3D_EVENT_QUERY_WAITING:
427 signaled = FALSE;
428 fill_query_data(data, size, &signaled, sizeof(signaled));
429 break;
431 case WINED3D_EVENT_QUERY_WRONG_THREAD:
432 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
433 signaled = TRUE;
434 fill_query_data(data, size, &signaled, sizeof(signaled));
435 break;
437 case WINED3D_EVENT_QUERY_ERROR:
438 ERR("The GL event query failed, returning D3DERR_INVALIDCALL\n");
439 return WINED3DERR_INVALIDCALL;
442 return S_OK;
445 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
447 TRACE("query %p.\n", query);
449 return query->parent;
452 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
454 TRACE("query %p.\n", query);
456 return query->type;
459 static HRESULT wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
461 TRACE("query %p, flags %#x.\n", query, flags);
463 if (flags & WINED3DISSUE_END)
465 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
467 wined3d_event_query_issue(event_query, query->device);
469 else if (flags & WINED3DISSUE_BEGIN)
471 /* Started implicitly at query creation. */
472 ERR("Event query issued with START flag - what to do?\n");
475 if (flags & WINED3DISSUE_BEGIN)
476 query->state = QUERY_BUILDING;
477 else
478 query->state = QUERY_SIGNALLED;
480 return WINED3D_OK;
483 static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
485 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
486 struct wined3d_device *device = query->device;
487 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
488 struct wined3d_context *context;
490 TRACE("query %p, flags %#x.\n", query, flags);
492 /* This is allowed according to MSDN and our tests. Reset the query and
493 * restart. */
494 if (flags & WINED3DISSUE_BEGIN)
496 if (query->state == QUERY_BUILDING)
498 if (oq->context->tid != GetCurrentThreadId())
500 FIXME("Wrong thread, can't restart query.\n");
502 context_free_occlusion_query(oq);
503 context = context_acquire(query->device, NULL);
504 context_alloc_occlusion_query(context, oq);
506 else
508 context = context_acquire(device, context_get_rt_surface(oq->context));
510 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
511 checkGLcall("glEndQuery()");
514 else
516 if (oq->context)
517 context_free_occlusion_query(oq);
518 context = context_acquire(query->device, NULL);
519 context_alloc_occlusion_query(context, oq);
522 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
523 checkGLcall("glBeginQuery()");
525 context_release(context);
527 if (flags & WINED3DISSUE_END)
529 /* MSDN says END on a non-building occlusion query returns an error,
530 * but our tests show that it returns OK. But OpenGL doesn't like it,
531 * so avoid generating an error. */
532 if (query->state == QUERY_BUILDING)
534 if (oq->context->tid != GetCurrentThreadId())
536 FIXME("Wrong thread, can't end query.\n");
538 else
540 context = context_acquire(device, context_get_rt_surface(oq->context));
542 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
543 checkGLcall("glEndQuery()");
545 context_release(context);
550 if (flags & WINED3DISSUE_BEGIN)
551 query->state = QUERY_BUILDING;
552 else
553 query->state = QUERY_SIGNALLED;
555 return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */
558 static HRESULT wined3d_timestamp_query_ops_get_data(struct wined3d_query *query,
559 void *data, DWORD size, DWORD flags)
561 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
562 struct wined3d_device *device = query->device;
563 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
564 struct wined3d_context *context;
565 GLuint available;
566 GLuint64 timestamp;
567 HRESULT res;
569 TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
571 if (!tq->context)
572 query->state = QUERY_CREATED;
574 if (query->state == QUERY_CREATED)
576 /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves. */
577 TRACE("Query wasn't yet started, returning S_OK.\n");
578 timestamp = 0;
579 fill_query_data(data, size, &timestamp, sizeof(timestamp));
580 return S_OK;
583 if (tq->context->tid != GetCurrentThreadId())
585 FIXME("%p Wrong thread, returning 1.\n", query);
586 timestamp = 1;
587 fill_query_data(data, size, &timestamp, sizeof(timestamp));
588 return S_OK;
591 context = context_acquire(device, context_get_rt_surface(tq->context));
593 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
594 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
595 TRACE("available %#x.\n", available);
597 if (available)
599 if (size)
601 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
602 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
603 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
604 fill_query_data(data, size, &timestamp, sizeof(timestamp));
606 res = S_OK;
608 else
610 res = S_FALSE;
613 context_release(context);
615 return res;
618 static HRESULT wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
620 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
621 struct wined3d_device *device = query->device;
622 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
623 struct wined3d_context *context;
625 TRACE("query %p, flags %#x.\n", query, flags);
627 if (flags & WINED3DISSUE_BEGIN)
629 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
631 if (flags & WINED3DISSUE_END)
633 if (tq->context)
634 context_free_timestamp_query(tq);
635 context = context_acquire(query->device, NULL);
636 context_alloc_timestamp_query(context, tq);
637 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
638 checkGLcall("glQueryCounter()");
639 context_release(context);
641 query->state = QUERY_SIGNALLED;
644 return WINED3D_OK;
647 static HRESULT wined3d_timestamp_disjoint_query_ops_get_data(struct wined3d_query *query,
648 void *data, DWORD size, DWORD flags)
650 TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
652 if (query->type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
654 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
656 if (query->state == QUERY_BUILDING)
658 TRACE("Query is building, returning S_FALSE.\n");
659 return S_FALSE;
662 fill_query_data(data, size, &disjoint_data, sizeof(disjoint_data));
664 else
666 static const UINT64 freq = 1000 * 1000 * 1000;
668 fill_query_data(data, size, &freq, sizeof(freq));
670 return S_OK;
673 static HRESULT wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
675 TRACE("query %p, flags %#x.\n", query, flags);
677 if (flags & WINED3DISSUE_BEGIN)
678 query->state = QUERY_BUILDING;
679 if (flags & WINED3DISSUE_END)
680 query->state = QUERY_SIGNALLED;
682 return WINED3D_OK;
685 static const struct wined3d_query_ops event_query_ops =
687 wined3d_event_query_ops_get_data,
688 wined3d_event_query_ops_issue,
691 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
692 enum wined3d_query_type type, void *parent, struct wined3d_query **query)
694 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
695 struct wined3d_event_query *object;
697 TRACE("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
699 if (!wined3d_event_query_supported(gl_info))
701 WARN("Event queries not supported.\n");
702 return WINED3DERR_NOTAVAILABLE;
705 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
706 return E_OUTOFMEMORY;
708 wined3d_query_init(&object->query, device, type, sizeof(BOOL), &event_query_ops, parent);
710 TRACE("Created query %p.\n", object);
711 *query = &object->query;
713 return WINED3D_OK;
716 static const struct wined3d_query_ops occlusion_query_ops =
718 wined3d_occlusion_query_ops_get_data,
719 wined3d_occlusion_query_ops_issue,
722 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
723 enum wined3d_query_type type, void *parent, struct wined3d_query **query)
725 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
726 struct wined3d_occlusion_query *object;
728 TRACE("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
730 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
732 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
733 return WINED3DERR_NOTAVAILABLE;
736 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
737 return E_OUTOFMEMORY;
739 wined3d_query_init(&object->query, device, type, sizeof(DWORD), &occlusion_query_ops, parent);
741 TRACE("Created query %p.\n", object);
742 *query = &object->query;
744 return WINED3D_OK;
747 static const struct wined3d_query_ops timestamp_query_ops =
749 wined3d_timestamp_query_ops_get_data,
750 wined3d_timestamp_query_ops_issue,
753 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
754 enum wined3d_query_type type, void *parent, struct wined3d_query **query)
756 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
757 struct wined3d_timestamp_query *object;
759 TRACE("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
761 if (!gl_info->supported[ARB_TIMER_QUERY])
763 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
764 return WINED3DERR_NOTAVAILABLE;
767 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
768 return E_OUTOFMEMORY;
770 wined3d_query_init(&object->query, device, type, sizeof(UINT64), &timestamp_query_ops, parent);
772 TRACE("Created query %p.\n", object);
773 *query = &object->query;
775 return WINED3D_OK;
778 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
780 wined3d_timestamp_disjoint_query_ops_get_data,
781 wined3d_timestamp_disjoint_query_ops_issue,
784 static HRESULT query_init(struct wined3d_query *query, struct wined3d_device *device,
785 enum wined3d_query_type type, void *parent)
787 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
789 query->parent = parent;
791 switch (type)
793 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
794 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
795 TRACE("TIMESTAMP_DISJOINT query.\n");
796 if (!gl_info->supported[ARB_TIMER_QUERY])
798 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
799 return WINED3DERR_NOTAVAILABLE;
801 query->query_ops = &timestamp_disjoint_query_ops;
802 query->data_size = type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT
803 ? sizeof(struct wined3d_query_data_timestamp_disjoint) : sizeof(UINT64);
804 break;
806 case WINED3D_QUERY_TYPE_VCACHE:
807 case WINED3D_QUERY_TYPE_RESOURCE_MANAGER:
808 case WINED3D_QUERY_TYPE_VERTEX_STATS:
809 case WINED3D_QUERY_TYPE_PIPELINE_TIMINGS:
810 case WINED3D_QUERY_TYPE_INTERFACE_TIMINGS:
811 case WINED3D_QUERY_TYPE_VERTEX_TIMINGS:
812 case WINED3D_QUERY_TYPE_PIXEL_TIMINGS:
813 case WINED3D_QUERY_TYPE_BANDWIDTH_TIMINGS:
814 case WINED3D_QUERY_TYPE_CACHE_UTILIZATION:
815 default:
816 FIXME("Unhandled query type %#x.\n", type);
817 return WINED3DERR_NOTAVAILABLE;
820 query->type = type;
821 query->state = QUERY_CREATED;
822 query->device = device;
823 query->ref = 1;
825 return WINED3D_OK;
828 HRESULT CDECL wined3d_query_create(struct wined3d_device *device,
829 enum wined3d_query_type type, void *parent, struct wined3d_query **query)
831 struct wined3d_query *object;
832 HRESULT hr;
834 TRACE("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
836 switch (type)
838 case WINED3D_QUERY_TYPE_EVENT:
839 return wined3d_event_query_create(device, type, parent, query);
841 case WINED3D_QUERY_TYPE_OCCLUSION:
842 return wined3d_occlusion_query_create(device, type, parent, query);
844 case WINED3D_QUERY_TYPE_TIMESTAMP:
845 return wined3d_timestamp_query_create(device, type, parent, query);
847 default:
848 break;
851 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
852 if (!object)
853 return E_OUTOFMEMORY;
855 if (FAILED(hr = query_init(object, device, type, parent)))
857 WARN("Failed to initialize query, hr %#x.\n", hr);
858 HeapFree(GetProcessHeap(), 0, object);
859 return hr;
862 TRACE("Created query %p.\n", object);
863 *query = object;
865 return WINED3D_OK;