1 /* 2 * Copyright 2005 Oliver Stieber 3 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers 4 * Copyright 2009-2010 Henri Verbeet for CodeWeavers. 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 22 #include "config.h" 23 #include "wine/port.h" 24 #include "wined3d_private.h" 25 26 WINE_DEFAULT_DEBUG_CHANNEL(d3d); 27 28 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info) 29 { 30 if (gl_info->supported[ARB_TIMER_QUERY]) 31 { 32 GLuint64 result; 33 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result)); 34 return result; 35 } 36 else 37 { 38 GLuint result; 39 GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result)); 40 return result; 41 } 42 } 43 44 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device, 45 enum wined3d_query_type type, const void *data, DWORD data_size, 46 const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops) 47 { 48 query->ref = 1; 49 query->parent = parent; 50 query->parent_ops = parent_ops; 51 query->device = device; 52 query->state = QUERY_CREATED; 53 query->type = type; 54 query->data = data; 55 query->data_size = data_size; 56 query->query_ops = query_ops; 57 list_init(&query->poll_list_entry); 58 } 59 60 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query) 61 { 62 return CONTAINING_RECORD(query, struct wined3d_event_query, query); 63 } 64 65 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query) 66 { 67 return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query); 68 } 69 70 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query) 71 { 72 return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query); 73 } 74 75 static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query) 76 { 77 return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query); 78 } 79 80 static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query( 81 struct wined3d_query *query) 82 { 83 return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query); 84 } 85 86 static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info) 87 { 88 return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE]; 89 } 90 91 static enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence, 92 const struct wined3d_device *device, DWORD flags) 93 { 94 const struct wined3d_gl_info *gl_info; 95 struct wined3d_context *context; 96 enum wined3d_fence_result ret; 97 BOOL fence_result; 98 99 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags); 100 101 if (!fence->context) 102 { 103 TRACE("Fence not issued.\n"); 104 return WINED3D_FENCE_NOT_STARTED; 105 } 106 107 if (!(context = context_reacquire(device, fence->context))) 108 { 109 if (!fence->context->gl_info->supported[ARB_SYNC]) 110 { 111 WARN("Fence tested from wrong thread.\n"); 112 return WINED3D_FENCE_WRONG_THREAD; 113 } 114 context = context_acquire(device, NULL, 0); 115 } 116 gl_info = context->gl_info; 117 118 if (gl_info->supported[ARB_SYNC]) 119 { 120 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync, 121 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0)); 122 checkGLcall("glClientWaitSync"); 123 124 switch (gl_ret) 125 { 126 case GL_ALREADY_SIGNALED: 127 case GL_CONDITION_SATISFIED: 128 ret = WINED3D_FENCE_OK; 129 break; 130 131 case GL_TIMEOUT_EXPIRED: 132 ret = WINED3D_FENCE_WAITING; 133 break; 134 135 case GL_WAIT_FAILED: 136 default: 137 ERR("glClientWaitSync returned %#x.\n", gl_ret); 138 ret = WINED3D_FENCE_ERROR; 139 } 140 } 141 else if (gl_info->supported[APPLE_FENCE]) 142 { 143 fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id)); 144 checkGLcall("glTestFenceAPPLE"); 145 if (fence_result) 146 ret = WINED3D_FENCE_OK; 147 else 148 ret = WINED3D_FENCE_WAITING; 149 } 150 else if (gl_info->supported[NV_FENCE]) 151 { 152 fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id)); 153 checkGLcall("glTestFenceNV"); 154 if (fence_result) 155 ret = WINED3D_FENCE_OK; 156 else 157 ret = WINED3D_FENCE_WAITING; 158 } 159 else 160 { 161 ERR("Fence created despite lack of GL support.\n"); 162 ret = WINED3D_FENCE_ERROR; 163 } 164 165 context_release(context); 166 return ret; 167 } 168 169 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence, 170 const struct wined3d_device *device) 171 { 172 const struct wined3d_gl_info *gl_info; 173 struct wined3d_context *context; 174 enum wined3d_fence_result ret; 175 176 TRACE("fence %p, device %p.\n", fence, device); 177 178 if (!fence->context) 179 { 180 TRACE("Fence not issued.\n"); 181 return WINED3D_FENCE_NOT_STARTED; 182 } 183 gl_info = fence->context->gl_info; 184 185 if (!(context = context_reacquire(device, fence->context))) 186 { 187 /* A glFinish does not reliably wait for draws in other contexts. The caller has 188 * to find its own way to cope with the thread switch 189 */ 190 if (!gl_info->supported[ARB_SYNC]) 191 { 192 WARN("Fence finished from wrong thread.\n"); 193 return WINED3D_FENCE_WRONG_THREAD; 194 } 195 context = context_acquire(device, NULL, 0); 196 } 197 gl_info = context->gl_info; 198 199 if (gl_info->supported[ARB_SYNC]) 200 { 201 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED, 202 * possibly because macOS internally adds some slop to the timer. To avoid this, 203 * we use a large number that isn't near the point of overflow (macOS 10.12.5). 204 */ 205 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync, 206 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1)); 207 checkGLcall("glClientWaitSync"); 208 209 switch (gl_ret) 210 { 211 case GL_ALREADY_SIGNALED: 212 case GL_CONDITION_SATISFIED: 213 ret = WINED3D_FENCE_OK; 214 break; 215 216 /* We don't expect a timeout for a ~292 year wait */ 217 default: 218 ERR("glClientWaitSync returned %#x.\n", gl_ret); 219 ret = WINED3D_FENCE_ERROR; 220 } 221 } 222 else if (context->gl_info->supported[APPLE_FENCE]) 223 { 224 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id)); 225 checkGLcall("glFinishFenceAPPLE"); 226 ret = WINED3D_FENCE_OK; 227 } 228 else if (context->gl_info->supported[NV_FENCE]) 229 { 230 GL_EXTCALL(glFinishFenceNV(fence->object.id)); 231 checkGLcall("glFinishFenceNV"); 232 ret = WINED3D_FENCE_OK; 233 } 234 else 235 { 236 ERR("Fence created without GL support.\n"); 237 ret = WINED3D_FENCE_ERROR; 238 } 239 240 context_release(context); 241 return ret; 242 } 243 244 void wined3d_fence_issue(struct wined3d_fence *fence, const struct wined3d_device *device) 245 { 246 struct wined3d_context *context = NULL; 247 const struct wined3d_gl_info *gl_info; 248 249 if (fence->context && !(context = context_reacquire(device, fence->context)) 250 && !fence->context->gl_info->supported[ARB_SYNC]) 251 context_free_fence(fence); 252 if (!context) 253 context = context_acquire(device, NULL, 0); 254 gl_info = context->gl_info; 255 if (!fence->context) 256 context_alloc_fence(context, fence); 257 258 if (gl_info->supported[ARB_SYNC]) 259 { 260 if (fence->object.sync) 261 GL_EXTCALL(glDeleteSync(fence->object.sync)); 262 checkGLcall("glDeleteSync"); 263 fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); 264 checkGLcall("glFenceSync"); 265 } 266 else if (gl_info->supported[APPLE_FENCE]) 267 { 268 GL_EXTCALL(glSetFenceAPPLE(fence->object.id)); 269 checkGLcall("glSetFenceAPPLE"); 270 } 271 else if (gl_info->supported[NV_FENCE]) 272 { 273 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV)); 274 checkGLcall("glSetFenceNV"); 275 } 276 277 context_release(context); 278 } 279 280 static void wined3d_fence_free(struct wined3d_fence *fence) 281 { 282 if (fence->context) 283 context_free_fence(fence); 284 } 285 286 void wined3d_fence_destroy(struct wined3d_fence *fence) 287 { 288 wined3d_fence_free(fence); 289 heap_free(fence); 290 } 291 292 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info) 293 { 294 if (!wined3d_fence_supported(gl_info)) 295 { 296 WARN("Fences not supported.\n"); 297 return WINED3DERR_NOTAVAILABLE; 298 } 299 300 return WINED3D_OK; 301 } 302 303 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence) 304 { 305 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 306 struct wined3d_fence *object; 307 HRESULT hr; 308 309 TRACE("device %p, fence %p.\n", device, fence); 310 311 if (!(object = heap_alloc_zero(sizeof(*object)))) 312 return E_OUTOFMEMORY; 313 314 if (FAILED(hr = wined3d_fence_init(object, gl_info))) 315 { 316 heap_free(object); 317 return hr; 318 } 319 320 TRACE("Created fence %p.\n", object); 321 *fence = object; 322 323 return WINED3D_OK; 324 } 325 326 ULONG CDECL wined3d_query_incref(struct wined3d_query *query) 327 { 328 ULONG refcount = InterlockedIncrement(&query->ref); 329 330 TRACE("%p increasing refcount to %u.\n", query, refcount); 331 332 return refcount; 333 } 334 335 static void wined3d_query_destroy_object(void *object) 336 { 337 struct wined3d_query *query = object; 338 339 if (!list_empty(&query->poll_list_entry)) 340 list_remove(&query->poll_list_entry); 341 342 /* Queries are specific to the GL context that created them. Not 343 * deleting the query will obviously leak it, but that's still better 344 * than potentially deleting a different query with the same id in this 345 * context, and (still) leaking the actual query. */ 346 query->query_ops->query_destroy(query); 347 } 348 349 ULONG CDECL wined3d_query_decref(struct wined3d_query *query) 350 { 351 ULONG refcount = InterlockedDecrement(&query->ref); 352 353 TRACE("%p decreasing refcount to %u.\n", query, refcount); 354 355 if (!refcount) 356 { 357 query->parent_ops->wined3d_object_destroyed(query->parent); 358 wined3d_cs_destroy_object(query->device->cs, wined3d_query_destroy_object, query); 359 } 360 361 return refcount; 362 } 363 364 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query, 365 void *data, UINT data_size, DWORD flags) 366 { 367 TRACE("query %p, data %p, data_size %u, flags %#x.\n", 368 query, data, data_size, flags); 369 370 if (flags) 371 WARN("Ignoring flags %#x.\n", flags); 372 373 if (query->state == QUERY_BUILDING) 374 { 375 WARN("Query is building, returning S_FALSE.\n"); 376 return S_FALSE; 377 } 378 379 if (query->state == QUERY_CREATED) 380 { 381 WARN("Query wasn't started yet.\n"); 382 return WINED3DERR_INVALIDCALL; 383 } 384 385 if (!query->device->cs->thread) 386 { 387 if (!query->query_ops->query_poll(query, flags)) 388 return S_FALSE; 389 } 390 else if (query->counter_main != query->counter_retrieved) 391 { 392 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed) 393 wined3d_cs_emit_flush(query->device->cs); 394 return S_FALSE; 395 } 396 397 if (data) 398 memcpy(data, query->data, min(data_size, query->data_size)); 399 400 return S_OK; 401 } 402 403 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query) 404 { 405 TRACE("query %p.\n", query); 406 407 return query->data_size; 408 } 409 410 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags) 411 { 412 TRACE("query %p, flags %#x.\n", query, flags); 413 414 if (flags & WINED3DISSUE_END) 415 ++query->counter_main; 416 417 wined3d_cs_emit_query_issue(query->device->cs, query, flags); 418 419 if (flags & WINED3DISSUE_BEGIN) 420 query->state = QUERY_BUILDING; 421 else 422 query->state = QUERY_SIGNALLED; 423 424 return WINED3D_OK; 425 } 426 427 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags) 428 { 429 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query); 430 struct wined3d_device *device = query->device; 431 const struct wined3d_gl_info *gl_info; 432 struct wined3d_context *context; 433 GLuint available; 434 435 TRACE("query %p, flags %#x.\n", query, flags); 436 437 if (!(context = context_reacquire(device, oq->context))) 438 { 439 FIXME("%p Wrong thread, returning 1.\n", query); 440 oq->samples = 1; 441 return TRUE; 442 } 443 gl_info = context->gl_info; 444 445 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available)); 446 TRACE("Available %#x.\n", available); 447 448 if (available) 449 { 450 oq->samples = get_query_result64(oq->id, gl_info); 451 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples)); 452 } 453 454 checkGLcall("poll occlusion query"); 455 context_release(context); 456 457 return available; 458 } 459 460 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags) 461 { 462 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query); 463 enum wined3d_fence_result ret; 464 465 TRACE("query %p, flags %#x.\n", query, flags); 466 467 ret = wined3d_fence_test(&event_query->fence, query->device, flags); 468 switch (ret) 469 { 470 case WINED3D_FENCE_OK: 471 case WINED3D_FENCE_NOT_STARTED: 472 return event_query->signalled = TRUE; 473 474 case WINED3D_FENCE_WAITING: 475 return event_query->signalled = FALSE; 476 477 case WINED3D_FENCE_WRONG_THREAD: 478 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query); 479 return event_query->signalled = TRUE; 480 481 case WINED3D_FENCE_ERROR: 482 ERR("The GL event query failed.\n"); 483 return event_query->signalled = TRUE; 484 485 default: 486 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret); 487 return event_query->signalled = TRUE; 488 } 489 } 490 491 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query) 492 { 493 TRACE("query %p.\n", query); 494 495 return query->parent; 496 } 497 498 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query) 499 { 500 TRACE("query %p.\n", query); 501 502 return query->type; 503 } 504 505 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags) 506 { 507 TRACE("query %p, flags %#x.\n", query, flags); 508 509 if (flags & WINED3DISSUE_END) 510 { 511 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query); 512 513 wined3d_fence_issue(&event_query->fence, query->device); 514 return TRUE; 515 } 516 else if (flags & WINED3DISSUE_BEGIN) 517 { 518 /* Started implicitly at query creation. */ 519 ERR("Event query issued with START flag - what to do?\n"); 520 } 521 522 return FALSE; 523 } 524 525 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags) 526 { 527 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query); 528 struct wined3d_device *device = query->device; 529 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 530 struct wined3d_context *context; 531 BOOL poll = FALSE; 532 533 TRACE("query %p, flags %#x.\n", query, flags); 534 535 /* This is allowed according to MSDN and our tests. Reset the query and 536 * restart. */ 537 if (flags & WINED3DISSUE_BEGIN) 538 { 539 if (oq->started) 540 { 541 if ((context = context_reacquire(device, oq->context))) 542 { 543 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED)); 544 checkGLcall("glEndQuery()"); 545 } 546 else 547 { 548 FIXME("Wrong thread, can't restart query.\n"); 549 context_free_occlusion_query(oq); 550 context = context_acquire(device, NULL, 0); 551 context_alloc_occlusion_query(context, oq); 552 } 553 } 554 else 555 { 556 if (oq->context) 557 context_free_occlusion_query(oq); 558 context = context_acquire(device, NULL, 0); 559 context_alloc_occlusion_query(context, oq); 560 } 561 562 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id)); 563 checkGLcall("glBeginQuery()"); 564 565 context_release(context); 566 oq->started = TRUE; 567 } 568 if (flags & WINED3DISSUE_END) 569 { 570 /* MSDN says END on a non-building occlusion query returns an error, 571 * but our tests show that it returns OK. But OpenGL doesn't like it, 572 * so avoid generating an error. */ 573 if (oq->started) 574 { 575 if ((context = context_reacquire(device, oq->context))) 576 { 577 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED)); 578 checkGLcall("glEndQuery()"); 579 580 context_release(context); 581 poll = TRUE; 582 } 583 else 584 { 585 FIXME("Wrong thread, can't end query.\n"); 586 } 587 } 588 oq->started = FALSE; 589 } 590 591 return poll; 592 } 593 594 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags) 595 { 596 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query); 597 struct wined3d_device *device = query->device; 598 const struct wined3d_gl_info *gl_info; 599 struct wined3d_context *context; 600 GLuint64 timestamp; 601 GLuint available; 602 603 TRACE("query %p, flags %#x.\n", query, flags); 604 605 if (!(context = context_reacquire(device, tq->context))) 606 { 607 FIXME("%p Wrong thread, returning 1.\n", query); 608 tq->timestamp = 1; 609 return TRUE; 610 } 611 gl_info = context->gl_info; 612 613 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available)); 614 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)"); 615 TRACE("available %#x.\n", available); 616 617 if (available) 618 { 619 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, ×tamp)); 620 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)"); 621 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp)); 622 tq->timestamp = timestamp; 623 } 624 625 context_release(context); 626 627 return available; 628 } 629 630 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags) 631 { 632 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query); 633 const struct wined3d_gl_info *gl_info; 634 struct wined3d_context *context; 635 636 TRACE("query %p, flags %#x.\n", query, flags); 637 638 if (flags & WINED3DISSUE_BEGIN) 639 { 640 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n"); 641 } 642 if (flags & WINED3DISSUE_END) 643 { 644 if (tq->context) 645 context_free_timestamp_query(tq); 646 context = context_acquire(query->device, NULL, 0); 647 gl_info = context->gl_info; 648 context_alloc_timestamp_query(context, tq); 649 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP)); 650 checkGLcall("glQueryCounter()"); 651 context_release(context); 652 653 return TRUE; 654 } 655 656 return FALSE; 657 } 658 659 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags) 660 { 661 TRACE("query %p, flags %#x.\n", query, flags); 662 663 return TRUE; 664 } 665 666 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags) 667 { 668 TRACE("query %p, flags %#x.\n", query, flags); 669 670 return FALSE; 671 } 672 673 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags) 674 { 675 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query); 676 struct wined3d_device *device = query->device; 677 GLuint written_available, generated_available; 678 const struct wined3d_gl_info *gl_info; 679 struct wined3d_context *context; 680 681 TRACE("query %p, flags %#x.\n", query, flags); 682 683 if (!(context = context_reacquire(device, pq->context))) 684 { 685 FIXME("%p Wrong thread, returning 0 primitives.\n", query); 686 memset(&pq->statistics, 0, sizeof(pq->statistics)); 687 return TRUE; 688 } 689 gl_info = context->gl_info; 690 691 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written, 692 GL_QUERY_RESULT_AVAILABLE, &written_available)); 693 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated, 694 GL_QUERY_RESULT_AVAILABLE, &generated_available)); 695 TRACE("Available %#x, %#x.\n", written_available, generated_available); 696 697 if (written_available && generated_available) 698 { 699 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info); 700 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info); 701 TRACE("Returning %s, %s primitives.\n", 702 wine_dbgstr_longlong(pq->statistics.primitives_written), 703 wine_dbgstr_longlong(pq->statistics.primitives_generated)); 704 } 705 706 checkGLcall("poll SO statistics query"); 707 context_release(context); 708 709 return written_available && generated_available; 710 } 711 712 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags) 713 { 714 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query); 715 struct wined3d_device *device = query->device; 716 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 717 struct wined3d_context *context; 718 BOOL poll = FALSE; 719 720 TRACE("query %p, flags %#x.\n", query, flags); 721 722 if (flags & WINED3DISSUE_BEGIN) 723 { 724 if (pq->started) 725 { 726 if ((context = context_reacquire(device, pq->context))) 727 { 728 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx)); 729 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx)); 730 } 731 else 732 { 733 FIXME("Wrong thread, can't restart query.\n"); 734 context_free_so_statistics_query(pq); 735 context = context_acquire(device, NULL, 0); 736 context_alloc_so_statistics_query(context, pq); 737 } 738 } 739 else 740 { 741 if (pq->context) 742 context_free_so_statistics_query(pq); 743 context = context_acquire(device, NULL, 0); 744 context_alloc_so_statistics_query(context, pq); 745 } 746 747 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 748 pq->stream_idx, pq->u.query.written)); 749 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED, 750 pq->stream_idx, pq->u.query.generated)); 751 checkGLcall("begin query"); 752 753 context_release(context); 754 pq->started = TRUE; 755 } 756 if (flags & WINED3DISSUE_END) 757 { 758 if (pq->started) 759 { 760 if ((context = context_reacquire(device, pq->context))) 761 { 762 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx)); 763 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx)); 764 checkGLcall("end query"); 765 766 context_release(context); 767 poll = TRUE; 768 } 769 else 770 { 771 FIXME("Wrong thread, can't end query.\n"); 772 } 773 } 774 pq->started = FALSE; 775 } 776 777 return poll; 778 } 779 780 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags) 781 { 782 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query); 783 struct wined3d_device *device = query->device; 784 const struct wined3d_gl_info *gl_info; 785 struct wined3d_context *context; 786 GLuint available; 787 int i; 788 789 TRACE("query %p, flags %#x.\n", query, flags); 790 791 if (!(context = context_reacquire(device, pq->context))) 792 { 793 FIXME("%p Wrong thread.\n", query); 794 memset(&pq->statistics, 0, sizeof(pq->statistics)); 795 return TRUE; 796 } 797 gl_info = context->gl_info; 798 799 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i) 800 { 801 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available)); 802 if (!available) 803 break; 804 } 805 806 if (available) 807 { 808 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info); 809 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info); 810 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info); 811 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info); 812 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info); 813 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info); 814 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info); 815 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info); 816 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info); 817 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info); 818 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info); 819 } 820 821 checkGLcall("poll pipeline statistics query"); 822 context_release(context); 823 return available; 824 } 825 826 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query, 827 struct wined3d_context *context) 828 { 829 const struct wined3d_gl_info *gl_info = context->gl_info; 830 831 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB)); 832 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB)); 833 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB)); 834 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB)); 835 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB)); 836 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS)); 837 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB)); 838 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB)); 839 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB)); 840 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB)); 841 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB)); 842 checkGLcall("end query"); 843 } 844 845 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags) 846 { 847 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query); 848 struct wined3d_device *device = query->device; 849 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 850 struct wined3d_context *context; 851 BOOL poll = FALSE; 852 853 TRACE("query %p, flags %#x.\n", query, flags); 854 855 if (flags & WINED3DISSUE_BEGIN) 856 { 857 if (pq->started) 858 { 859 if ((context = context_reacquire(device, pq->context))) 860 { 861 wined3d_pipeline_statistics_query_end(pq, context); 862 } 863 else 864 { 865 FIXME("Wrong thread, can't restart query.\n"); 866 context_free_pipeline_statistics_query(pq); 867 context = context_acquire(device, NULL, 0); 868 context_alloc_pipeline_statistics_query(context, pq); 869 } 870 } 871 else 872 { 873 if (pq->context) 874 context_free_pipeline_statistics_query(pq); 875 context = context_acquire(device, NULL, 0); 876 context_alloc_pipeline_statistics_query(context, pq); 877 } 878 879 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices)); 880 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives)); 881 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader)); 882 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader)); 883 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader)); 884 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader)); 885 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives)); 886 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader)); 887 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader)); 888 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input)); 889 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output)); 890 checkGLcall("begin query"); 891 892 context_release(context); 893 pq->started = TRUE; 894 } 895 if (flags & WINED3DISSUE_END) 896 { 897 if (pq->started) 898 { 899 if ((context = context_reacquire(device, pq->context))) 900 { 901 wined3d_pipeline_statistics_query_end(pq, context); 902 context_release(context); 903 poll = TRUE; 904 } 905 else 906 { 907 FIXME("Wrong thread, can't end query.\n"); 908 } 909 } 910 pq->started = FALSE; 911 } 912 913 return poll; 914 } 915 916 static BOOL wined3d_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags) 917 { 918 TRACE("query %p, flags %#x.\n", query, flags); 919 920 return TRUE; 921 } 922 923 static BOOL wined3d_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags) 924 { 925 FIXME("query %p, flags %#x.\n", query, flags); 926 927 return FALSE; 928 } 929 930 static BOOL wined3d_overflow_query_ops_poll(struct wined3d_query *query, DWORD flags) 931 { 932 TRACE("query %p, flags %#x.\n", query, flags); 933 934 return TRUE; 935 } 936 937 static BOOL wined3d_overflow_query_ops_issue(struct wined3d_query *query, DWORD flags) 938 { 939 FIXME("query %p, flags %#x.\n", query, flags); 940 941 return FALSE; 942 } 943 944 static void wined3d_event_query_ops_destroy(struct wined3d_query *query) 945 { 946 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query); 947 948 wined3d_fence_free(&event_query->fence); 949 heap_free(event_query); 950 } 951 952 static const struct wined3d_query_ops event_query_ops = 953 { 954 wined3d_event_query_ops_poll, 955 wined3d_event_query_ops_issue, 956 wined3d_event_query_ops_destroy, 957 }; 958 959 static HRESULT wined3d_event_query_create(struct wined3d_device *device, 960 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, 961 struct wined3d_query **query) 962 { 963 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 964 struct wined3d_event_query *object; 965 HRESULT hr; 966 967 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n", 968 device, type, parent, parent_ops, query); 969 970 if (!(object = heap_alloc_zero(sizeof(*object)))) 971 return E_OUTOFMEMORY; 972 973 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info))) 974 { 975 WARN("Event queries not supported.\n"); 976 heap_free(object); 977 return hr; 978 } 979 980 wined3d_query_init(&object->query, device, type, &object->signalled, 981 sizeof(object->signalled), &event_query_ops, parent, parent_ops); 982 983 TRACE("Created query %p.\n", object); 984 *query = &object->query; 985 986 return WINED3D_OK; 987 } 988 989 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query) 990 { 991 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query); 992 993 if (oq->context) 994 context_free_occlusion_query(oq); 995 heap_free(oq); 996 } 997 998 static const struct wined3d_query_ops occlusion_query_ops = 999 { 1000 wined3d_occlusion_query_ops_poll, 1001 wined3d_occlusion_query_ops_issue, 1002 wined3d_occlusion_query_ops_destroy, 1003 }; 1004 1005 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device, 1006 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, 1007 struct wined3d_query **query) 1008 { 1009 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 1010 struct wined3d_occlusion_query *object; 1011 1012 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n", 1013 device, type, parent, parent_ops, query); 1014 1015 if (!gl_info->supported[ARB_OCCLUSION_QUERY]) 1016 { 1017 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n"); 1018 return WINED3DERR_NOTAVAILABLE; 1019 } 1020 1021 if (!(object = heap_alloc_zero(sizeof(*object)))) 1022 return E_OUTOFMEMORY; 1023 1024 wined3d_query_init(&object->query, device, type, &object->samples, 1025 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops); 1026 1027 TRACE("Created query %p.\n", object); 1028 *query = &object->query; 1029 1030 return WINED3D_OK; 1031 } 1032 1033 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query) 1034 { 1035 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query); 1036 1037 if (tq->context) 1038 context_free_timestamp_query(tq); 1039 heap_free(tq); 1040 } 1041 1042 static const struct wined3d_query_ops timestamp_query_ops = 1043 { 1044 wined3d_timestamp_query_ops_poll, 1045 wined3d_timestamp_query_ops_issue, 1046 wined3d_timestamp_query_ops_destroy, 1047 }; 1048 1049 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device, 1050 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, 1051 struct wined3d_query **query) 1052 { 1053 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 1054 struct wined3d_timestamp_query *object; 1055 1056 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n", 1057 device, type, parent, parent_ops, query); 1058 1059 if (!gl_info->supported[ARB_TIMER_QUERY]) 1060 { 1061 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n"); 1062 return WINED3DERR_NOTAVAILABLE; 1063 } 1064 1065 if (!(object = heap_alloc_zero(sizeof(*object)))) 1066 return E_OUTOFMEMORY; 1067 1068 wined3d_query_init(&object->query, device, type, &object->timestamp, 1069 sizeof(object->timestamp), ×tamp_query_ops, parent, parent_ops); 1070 1071 TRACE("Created query %p.\n", object); 1072 *query = &object->query; 1073 1074 return WINED3D_OK; 1075 } 1076 1077 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query) 1078 { 1079 heap_free(query); 1080 } 1081 1082 static const struct wined3d_query_ops timestamp_disjoint_query_ops = 1083 { 1084 wined3d_timestamp_disjoint_query_ops_poll, 1085 wined3d_timestamp_disjoint_query_ops_issue, 1086 wined3d_timestamp_disjoint_query_ops_destroy, 1087 }; 1088 1089 static HRESULT wined3d_timestamp_disjoint_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) 1092 { 1093 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 1094 struct wined3d_query *object; 1095 1096 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n", 1097 device, type, parent, parent_ops, query); 1098 1099 if (!gl_info->supported[ARB_TIMER_QUERY]) 1100 { 1101 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n"); 1102 return WINED3DERR_NOTAVAILABLE; 1103 } 1104 1105 if (!(object = heap_alloc_zero(sizeof(*object)))) 1106 return E_OUTOFMEMORY; 1107 1108 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT) 1109 { 1110 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE}; 1111 1112 wined3d_query_init(object, device, type, &disjoint_data, 1113 sizeof(disjoint_data), ×tamp_disjoint_query_ops, parent, parent_ops); 1114 } 1115 else 1116 { 1117 static const UINT64 freq = 1000 * 1000 * 1000; 1118 1119 wined3d_query_init(object, device, type, &freq, 1120 sizeof(freq), ×tamp_disjoint_query_ops, parent, parent_ops); 1121 } 1122 1123 TRACE("Created query %p.\n", object); 1124 *query = object; 1125 1126 return WINED3D_OK; 1127 } 1128 1129 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query) 1130 { 1131 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query); 1132 1133 if (pq->context) 1134 context_free_so_statistics_query(pq); 1135 heap_free(pq); 1136 } 1137 1138 static const struct wined3d_query_ops so_statistics_query_ops = 1139 { 1140 wined3d_so_statistics_query_ops_poll, 1141 wined3d_so_statistics_query_ops_issue, 1142 wined3d_so_statistics_query_ops_destroy, 1143 }; 1144 1145 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device, 1146 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, 1147 struct wined3d_query **query) 1148 { 1149 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 1150 struct wined3d_so_statistics_query *object; 1151 unsigned int stream_idx; 1152 1153 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3) 1154 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0; 1155 else 1156 return WINED3DERR_NOTAVAILABLE; 1157 1158 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n", 1159 device, type, parent, parent_ops, query); 1160 1161 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY]) 1162 { 1163 WARN("OpenGL implementation does not support primitive queries.\n"); 1164 return WINED3DERR_NOTAVAILABLE; 1165 } 1166 if (!gl_info->supported[ARB_TRANSFORM_FEEDBACK3]) 1167 { 1168 WARN("OpenGL implementation does not support indexed queries.\n"); 1169 return WINED3DERR_NOTAVAILABLE; 1170 } 1171 1172 if (!(object = heap_alloc_zero(sizeof(*object)))) 1173 return E_OUTOFMEMORY; 1174 1175 wined3d_query_init(&object->query, device, type, &object->statistics, 1176 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops); 1177 object->stream_idx = stream_idx; 1178 1179 TRACE("Created query %p.\n", object); 1180 *query = &object->query; 1181 1182 return WINED3D_OK; 1183 } 1184 1185 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query) 1186 { 1187 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query); 1188 if (pq->context) 1189 context_free_pipeline_statistics_query(pq); 1190 heap_free(pq); 1191 } 1192 1193 static const struct wined3d_query_ops pipeline_query_ops = 1194 { 1195 wined3d_pipeline_query_ops_poll, 1196 wined3d_pipeline_query_ops_issue, 1197 wined3d_pipeline_query_ops_destroy, 1198 }; 1199 1200 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device, 1201 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, 1202 struct wined3d_query **query) 1203 { 1204 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 1205 struct wined3d_pipeline_statistics_query *object; 1206 1207 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n", 1208 device, type, parent, parent_ops, query); 1209 1210 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY]) 1211 { 1212 WARN("OpenGL implementation does not support pipeline statistics queries.\n"); 1213 return WINED3DERR_NOTAVAILABLE; 1214 } 1215 1216 if (!(object = heap_alloc_zero(sizeof(*object)))) 1217 return E_OUTOFMEMORY; 1218 1219 wined3d_query_init(&object->query, device, type, &object->statistics, 1220 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops); 1221 1222 TRACE("Created query %p.\n", object); 1223 *query = &object->query; 1224 1225 return WINED3D_OK; 1226 } 1227 1228 static void wined3d_statistics_query_ops_destroy(struct wined3d_query *query) 1229 { 1230 HeapFree(GetProcessHeap(), 0, query); 1231 } 1232 1233 static const struct wined3d_query_ops statistics_query_ops = 1234 { 1235 wined3d_statistics_query_ops_poll, 1236 wined3d_statistics_query_ops_issue, 1237 wined3d_statistics_query_ops_destroy, 1238 }; 1239 1240 static HRESULT wined3d_statistics_query_create(struct wined3d_device *device, 1241 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, 1242 struct wined3d_query **query) 1243 { 1244 static const struct wined3d_query_data_so_statistics statistics = { 1, 1 }; 1245 struct wined3d_query *object; 1246 1247 FIXME("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query); 1248 1249 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) 1250 return E_OUTOFMEMORY; 1251 1252 wined3d_query_init(object, device, type, &statistics, 1253 sizeof(statistics), &statistics_query_ops, parent, parent_ops); 1254 1255 TRACE("Created query %p.\n", object); 1256 *query = object; 1257 1258 return WINED3D_OK; 1259 } 1260 1261 static void wined3d_overflow_query_ops_destroy(struct wined3d_query *query) 1262 { 1263 HeapFree(GetProcessHeap(), 0, query); 1264 } 1265 1266 static const struct wined3d_query_ops overflow_query_ops = 1267 { 1268 wined3d_overflow_query_ops_poll, 1269 wined3d_overflow_query_ops_issue, 1270 wined3d_overflow_query_ops_destroy, 1271 }; 1272 1273 static HRESULT wined3d_overflow_query_create(struct wined3d_device *device, 1274 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, 1275 struct wined3d_query **query) 1276 { 1277 static const BOOL overflow = FALSE; 1278 struct wined3d_query *object; 1279 1280 FIXME("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query); 1281 1282 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) 1283 return E_OUTOFMEMORY; 1284 1285 wined3d_query_init(object, device, type, &overflow, 1286 sizeof(overflow), &overflow_query_ops, parent, parent_ops); 1287 1288 TRACE("Created query %p.\n", object); 1289 *query = object; 1290 1291 return WINED3D_OK; 1292 } 1293 1294 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type, 1295 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query) 1296 { 1297 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n", 1298 device, type, parent, parent_ops, query); 1299 1300 switch (type) 1301 { 1302 case WINED3D_QUERY_TYPE_EVENT: 1303 return wined3d_event_query_create(device, type, parent, parent_ops, query); 1304 1305 case WINED3D_QUERY_TYPE_OCCLUSION: 1306 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query); 1307 1308 case WINED3D_QUERY_TYPE_TIMESTAMP: 1309 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query); 1310 1311 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT: 1312 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ: 1313 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query); 1314 1315 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0: 1316 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1: 1317 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2: 1318 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3: 1319 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query); 1320 1321 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS: 1322 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query); 1323 1324 case WINED3D_QUERY_TYPE_SO_STATISTICS: 1325 return wined3d_statistics_query_create(device, type, parent, parent_ops, query); 1326 1327 case WINED3D_QUERY_TYPE_SO_OVERFLOW: 1328 return wined3d_overflow_query_create(device, type, parent, parent_ops, query); 1329 1330 default: 1331 FIXME("Unhandled query type %#x.\n", type); 1332 return WINED3DERR_NOTAVAILABLE; 1333 } 1334 } 1335