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