2005-03-03 14:57:15 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2005 Oliver Stieber
|
2008-10-18 19:21:20 +02:00
|
|
|
* Copyright 2007-2008 Stefan Dösinger for CodeWeavers
|
2010-11-18 20:50:40 +01:00
|
|
|
* Copyright 2009-2010 Henri Verbeet for CodeWeavers.
|
2005-03-03 14:57:15 +01:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2006-05-18 14:49:52 +02:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-03-03 14:57:15 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "wined3d_private.h"
|
|
|
|
|
2010-03-03 22:45:34 +01:00
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
|
|
|
|
2018-09-28 20:18:29 +02:00
|
|
|
static void wined3d_query_buffer_invalidate(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
/* map[0] != map[1]: exact values do not have any significance. */
|
|
|
|
query->map_ptr[0] = 0;
|
|
|
|
query->map_ptr[1] = ~(UINT64)0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL wined3d_query_buffer_is_valid(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
return query->map_ptr[0] == query->map_ptr[1];
|
|
|
|
}
|
|
|
|
|
2019-07-04 13:58:02 +02:00
|
|
|
static void wined3d_query_create_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
|
2018-09-28 20:18:29 +02:00
|
|
|
{
|
|
|
|
const GLuint map_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
|
2019-08-07 13:41:58 +02:00
|
|
|
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
|
2018-09-28 20:18:29 +02:00
|
|
|
GLuint buffer_object;
|
|
|
|
|
|
|
|
GL_EXTCALL(glGenBuffers(1, &buffer_object));
|
|
|
|
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, buffer_object));
|
|
|
|
GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER, sizeof(query->map_ptr[0]) * 2, NULL, map_flags));
|
|
|
|
query->map_ptr = GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER, 0, sizeof(query->map_ptr[0]) * 2, map_flags));
|
|
|
|
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
|
|
|
|
checkGLcall("query buffer object creation");
|
|
|
|
|
|
|
|
wined3d_query_buffer_invalidate(query);
|
|
|
|
query->buffer_object = buffer_object;
|
|
|
|
}
|
|
|
|
|
2019-08-15 11:50:00 +02:00
|
|
|
void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
|
2018-09-28 20:18:29 +02:00
|
|
|
{
|
2019-08-07 13:41:58 +02:00
|
|
|
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
|
2018-09-28 20:18:29 +02:00
|
|
|
|
|
|
|
GL_EXTCALL(glDeleteBuffers(1, &query->buffer_object));
|
|
|
|
checkGLcall("query buffer object destruction");
|
|
|
|
|
|
|
|
query->buffer_object = 0;
|
|
|
|
query->map_ptr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* From ARB_occlusion_query: "Querying the state for a given occlusion query
|
|
|
|
* forces that occlusion query to complete within a finite amount of time."
|
|
|
|
* In practice, that means drivers flush when retrieving
|
|
|
|
* GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
|
|
|
|
* significant number of queries. Using a persistently mapped query buffer
|
|
|
|
* object allows us to avoid these implicit flushes. An additional benefit is
|
|
|
|
* that it allows us to poll the query status from the application-thread
|
|
|
|
* instead of from the csmt-thread. */
|
2019-07-05 13:38:19 +02:00
|
|
|
static BOOL wined3d_query_buffer_queue_result(struct wined3d_context_gl *context_gl,
|
|
|
|
struct wined3d_query *query, GLuint id)
|
2018-09-28 20:18:29 +02:00
|
|
|
{
|
2019-08-07 13:41:58 +02:00
|
|
|
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
|
2018-10-14 20:18:09 +02:00
|
|
|
GLsync tmp_sync;
|
2018-09-28 20:18:29 +02:00
|
|
|
|
|
|
|
if (!gl_info->supported[ARB_QUERY_BUFFER_OBJECT] || !gl_info->supported[ARB_BUFFER_STORAGE])
|
|
|
|
return FALSE;
|
|
|
|
/* Don't use query buffers without CSMT, mainly for simplicity. */
|
2019-07-05 13:38:19 +02:00
|
|
|
if (!context_gl->c.device->cs->thread)
|
2018-09-28 20:18:29 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (query->buffer_object)
|
|
|
|
{
|
|
|
|
/* If there's still a query result in-flight for the existing buffer
|
|
|
|
* object (i.e., the query was restarted before we received its
|
|
|
|
* result), we can't reuse the existing buffer object. */
|
|
|
|
if (wined3d_query_buffer_is_valid(query))
|
|
|
|
wined3d_query_buffer_invalidate(query);
|
|
|
|
else
|
2019-08-15 11:50:00 +02:00
|
|
|
wined3d_query_gl_destroy_buffer_object(context_gl, query);
|
2018-09-28 20:18:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!query->buffer_object)
|
2019-07-04 13:58:02 +02:00
|
|
|
wined3d_query_create_buffer_object(context_gl, query);
|
2018-09-28 20:18:29 +02:00
|
|
|
|
|
|
|
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, query->buffer_object));
|
|
|
|
/* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
|
|
|
|
GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)0));
|
|
|
|
GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)sizeof(query->map_ptr[0])));
|
|
|
|
GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
|
|
|
|
checkGLcall("queue query result");
|
|
|
|
|
2018-10-14 20:18:09 +02:00
|
|
|
/* ARB_buffer_storage requires the client to call FenceSync with
|
|
|
|
* SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
|
|
|
|
* is not enforced by Mesa.
|
|
|
|
*/
|
|
|
|
tmp_sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
|
|
|
|
GL_EXTCALL(glDeleteSync(tmp_sync));
|
|
|
|
checkGLcall("query buffer sync");
|
|
|
|
|
2018-09-28 20:18:29 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-06-05 00:47:37 +02:00
|
|
|
static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
|
|
|
|
{
|
|
|
|
if (gl_info->supported[ARB_TIMER_QUERY])
|
|
|
|
{
|
|
|
|
GLuint64 result;
|
|
|
|
GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GLuint result;
|
|
|
|
GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-22 00:43:48 +02:00
|
|
|
static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
|
2016-07-28 13:29:41 +02:00
|
|
|
enum wined3d_query_type type, const void *data, DWORD data_size,
|
2017-05-10 15:54:07 +02:00
|
|
|
const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops)
|
2016-07-22 00:43:48 +02:00
|
|
|
{
|
|
|
|
query->ref = 1;
|
|
|
|
query->parent = parent;
|
2017-05-10 15:54:07 +02:00
|
|
|
query->parent_ops = parent_ops;
|
2016-07-22 00:43:48 +02:00
|
|
|
query->device = device;
|
|
|
|
query->state = QUERY_CREATED;
|
|
|
|
query->type = type;
|
2016-07-28 13:29:41 +02:00
|
|
|
query->data = data;
|
2016-07-22 00:43:48 +02:00
|
|
|
query->data_size = data_size;
|
|
|
|
query->query_ops = query_ops;
|
2017-04-13 00:11:01 +02:00
|
|
|
list_init(&query->poll_list_entry);
|
2016-07-22 00:43:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(query, struct wined3d_event_query, query);
|
|
|
|
}
|
|
|
|
|
2016-07-22 00:43:49 +02:00
|
|
|
static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
|
|
|
|
}
|
|
|
|
|
2016-07-22 00:43:50 +02:00
|
|
|
static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
|
|
|
|
}
|
|
|
|
|
2017-05-24 17:09:59 +02:00
|
|
|
static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
|
|
|
|
}
|
|
|
|
|
2017-06-05 00:47:34 +02:00
|
|
|
static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query(
|
|
|
|
struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query);
|
|
|
|
}
|
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info)
|
2010-03-03 23:48:50 +01:00
|
|
|
{
|
2010-03-30 11:24:43 +02:00
|
|
|
return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
|
2010-03-03 23:48:50 +01:00
|
|
|
}
|
|
|
|
|
2020-11-30 15:41:25 +01:00
|
|
|
enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
|
2019-06-05 14:24:07 +02:00
|
|
|
struct wined3d_device *device, DWORD flags)
|
2010-03-03 22:45:34 +01:00
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2017-07-09 13:25:49 +02:00
|
|
|
enum wined3d_fence_result ret;
|
2010-03-03 22:45:34 +01:00
|
|
|
BOOL fence_result;
|
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
|
2010-03-03 22:45:34 +01:00
|
|
|
|
2019-05-14 12:56:19 +02:00
|
|
|
if (!fence->context_gl)
|
2010-03-03 22:45:34 +01:00
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
TRACE("Fence not issued.\n");
|
|
|
|
return WINED3D_FENCE_NOT_STARTED;
|
2010-03-03 22:45:34 +01:00
|
|
|
}
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
|
2010-03-03 22:45:34 +01:00
|
|
|
{
|
2019-08-07 13:41:58 +02:00
|
|
|
if (!fence->context_gl->gl_info->supported[ARB_SYNC])
|
2017-04-05 15:38:05 +02:00
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
WARN("Fence tested from wrong thread.\n");
|
|
|
|
return WINED3D_FENCE_WRONG_THREAD;
|
2017-04-05 15:38:05 +02:00
|
|
|
}
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
2010-03-03 22:45:34 +01:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2010-03-03 22:45:34 +01:00
|
|
|
|
|
|
|
if (gl_info->supported[ARB_SYNC])
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
|
2017-01-04 00:04:49 +01:00
|
|
|
(flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
|
2010-03-03 22:45:34 +01:00
|
|
|
checkGLcall("glClientWaitSync");
|
|
|
|
|
|
|
|
switch (gl_ret)
|
|
|
|
{
|
|
|
|
case GL_ALREADY_SIGNALED:
|
|
|
|
case GL_CONDITION_SATISFIED:
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = WINED3D_FENCE_OK;
|
2010-03-03 22:45:34 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_TIMEOUT_EXPIRED:
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = WINED3D_FENCE_WAITING;
|
2010-03-03 22:45:34 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_WAIT_FAILED:
|
|
|
|
default:
|
|
|
|
ERR("glClientWaitSync returned %#x.\n", gl_ret);
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = WINED3D_FENCE_ERROR;
|
2010-03-03 22:45:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (gl_info->supported[APPLE_FENCE])
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
|
2010-03-03 22:45:34 +01:00
|
|
|
checkGLcall("glTestFenceAPPLE");
|
2017-07-09 13:25:49 +02:00
|
|
|
if (fence_result)
|
|
|
|
ret = WINED3D_FENCE_OK;
|
|
|
|
else
|
|
|
|
ret = WINED3D_FENCE_WAITING;
|
2010-03-03 22:45:34 +01:00
|
|
|
}
|
|
|
|
else if (gl_info->supported[NV_FENCE])
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
|
2010-03-03 22:45:34 +01:00
|
|
|
checkGLcall("glTestFenceNV");
|
2017-07-09 13:25:49 +02:00
|
|
|
if (fence_result)
|
|
|
|
ret = WINED3D_FENCE_OK;
|
|
|
|
else
|
|
|
|
ret = WINED3D_FENCE_WAITING;
|
2010-03-03 22:45:34 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
ERR("Fence created despite lack of GL support.\n");
|
|
|
|
ret = WINED3D_FENCE_ERROR;
|
2010-03-03 22:45:34 +01:00
|
|
|
}
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2010-03-03 22:45:34 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
|
2019-06-05 14:24:07 +02:00
|
|
|
struct wined3d_device *device)
|
2010-03-21 13:26:36 +01:00
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2017-07-09 13:25:49 +02:00
|
|
|
enum wined3d_fence_result ret;
|
2010-03-21 13:26:36 +01:00
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
TRACE("fence %p, device %p.\n", fence, device);
|
2010-03-21 13:26:36 +01:00
|
|
|
|
2019-05-14 12:56:19 +02:00
|
|
|
if (!fence->context_gl)
|
2010-03-21 13:26:36 +01:00
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
TRACE("Fence not issued.\n");
|
|
|
|
return WINED3D_FENCE_NOT_STARTED;
|
2010-03-21 13:26:36 +01:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = fence->context_gl->gl_info;
|
2010-03-21 13:26:36 +01:00
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
|
2010-03-21 13:26:36 +01:00
|
|
|
{
|
|
|
|
/* A glFinish does not reliably wait for draws in other contexts. The caller has
|
|
|
|
* to find its own way to cope with the thread switch
|
|
|
|
*/
|
2017-04-05 15:38:05 +02:00
|
|
|
if (!gl_info->supported[ARB_SYNC])
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
WARN("Fence finished from wrong thread.\n");
|
|
|
|
return WINED3D_FENCE_WRONG_THREAD;
|
2017-04-05 15:38:05 +02:00
|
|
|
}
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
2010-03-21 13:26:36 +01:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2010-03-21 13:26:36 +01:00
|
|
|
|
|
|
|
if (gl_info->supported[ARB_SYNC])
|
|
|
|
{
|
2017-08-12 18:09:06 +02:00
|
|
|
/* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
|
|
|
|
* possibly because macOS internally adds some slop to the timer. To avoid this,
|
|
|
|
* we use a large number that isn't near the point of overflow (macOS 10.12.5).
|
|
|
|
*/
|
2017-07-09 13:25:49 +02:00
|
|
|
GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
|
2017-08-12 18:09:06 +02:00
|
|
|
GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
|
2010-03-21 13:26:36 +01:00
|
|
|
checkGLcall("glClientWaitSync");
|
|
|
|
|
|
|
|
switch (gl_ret)
|
|
|
|
{
|
|
|
|
case GL_ALREADY_SIGNALED:
|
|
|
|
case GL_CONDITION_SATISFIED:
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = WINED3D_FENCE_OK;
|
2010-03-21 13:26:36 +01:00
|
|
|
break;
|
|
|
|
|
2017-08-12 18:09:06 +02:00
|
|
|
/* We don't expect a timeout for a ~292 year wait */
|
2010-03-21 13:26:36 +01:00
|
|
|
default:
|
|
|
|
ERR("glClientWaitSync returned %#x.\n", gl_ret);
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = WINED3D_FENCE_ERROR;
|
2010-03-21 13:26:36 +01:00
|
|
|
}
|
|
|
|
}
|
2019-06-06 14:51:07 +02:00
|
|
|
else if (gl_info->supported[APPLE_FENCE])
|
2010-03-21 13:26:36 +01:00
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
|
2010-03-21 13:26:36 +01:00
|
|
|
checkGLcall("glFinishFenceAPPLE");
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = WINED3D_FENCE_OK;
|
2010-03-21 13:26:36 +01:00
|
|
|
}
|
2019-06-06 14:51:07 +02:00
|
|
|
else if (gl_info->supported[NV_FENCE])
|
2010-03-21 13:26:36 +01:00
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
GL_EXTCALL(glFinishFenceNV(fence->object.id));
|
2010-03-21 13:26:36 +01:00
|
|
|
checkGLcall("glFinishFenceNV");
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = WINED3D_FENCE_OK;
|
2010-03-21 13:26:36 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
ERR("Fence created without GL support.\n");
|
|
|
|
ret = WINED3D_FENCE_ERROR;
|
2010-03-21 13:26:36 +01:00
|
|
|
}
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2010-03-21 13:26:36 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-06-05 14:24:07 +02:00
|
|
|
void wined3d_fence_issue(struct wined3d_fence *fence, struct wined3d_device *device)
|
2010-03-03 23:18:37 +01:00
|
|
|
{
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl = NULL;
|
2010-03-03 23:18:37 +01:00
|
|
|
const struct wined3d_gl_info *gl_info;
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
if (fence->context_gl && !(context_gl = wined3d_context_gl_reacquire(fence->context_gl))
|
2019-08-07 13:41:58 +02:00
|
|
|
&& !fence->context_gl->gl_info->supported[ARB_SYNC])
|
2019-05-14 12:56:19 +02:00
|
|
|
wined3d_context_gl_free_fence(fence);
|
2019-06-06 14:51:07 +02:00
|
|
|
if (!context_gl)
|
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2019-05-14 12:56:19 +02:00
|
|
|
if (!fence->context_gl)
|
2019-06-06 14:51:07 +02:00
|
|
|
wined3d_context_gl_alloc_fence(context_gl, fence);
|
2010-03-03 23:18:37 +01:00
|
|
|
|
|
|
|
if (gl_info->supported[ARB_SYNC])
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
if (fence->object.sync)
|
|
|
|
GL_EXTCALL(glDeleteSync(fence->object.sync));
|
2010-03-03 23:18:37 +01:00
|
|
|
checkGLcall("glDeleteSync");
|
2017-07-09 13:25:49 +02:00
|
|
|
fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
|
2010-03-03 23:18:37 +01:00
|
|
|
checkGLcall("glFenceSync");
|
|
|
|
}
|
|
|
|
else if (gl_info->supported[APPLE_FENCE])
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
|
2010-03-03 23:18:37 +01:00
|
|
|
checkGLcall("glSetFenceAPPLE");
|
|
|
|
}
|
|
|
|
else if (gl_info->supported[NV_FENCE])
|
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
|
2010-03-03 23:18:37 +01:00
|
|
|
checkGLcall("glSetFenceNV");
|
|
|
|
}
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2010-03-03 23:18:37 +01:00
|
|
|
}
|
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
static void wined3d_fence_free(struct wined3d_fence *fence)
|
|
|
|
{
|
2019-05-14 12:56:19 +02:00
|
|
|
if (fence->context_gl)
|
|
|
|
wined3d_context_gl_free_fence(fence);
|
2017-07-09 13:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void wined3d_fence_destroy(struct wined3d_fence *fence)
|
|
|
|
{
|
|
|
|
wined3d_fence_free(fence);
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(fence);
|
2017-07-09 13:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
|
|
|
|
{
|
|
|
|
if (!wined3d_fence_supported(gl_info))
|
|
|
|
{
|
|
|
|
WARN("Fences not supported.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
|
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
|
|
|
struct wined3d_fence *object;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
TRACE("device %p, fence %p.\n", device, fence);
|
|
|
|
|
2018-02-14 07:39:59 +01:00
|
|
|
if (!(object = heap_alloc_zero(sizeof(*object))))
|
2017-07-09 13:25:49 +02:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
if (FAILED(hr = wined3d_fence_init(object, gl_info)))
|
|
|
|
{
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(object);
|
2017-07-09 13:25:49 +02:00
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Created fence %p.\n", object);
|
|
|
|
*fence = object;
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
2011-02-03 20:14:06 +01:00
|
|
|
ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
|
2005-03-03 14:57:15 +01:00
|
|
|
{
|
2011-02-03 20:14:06 +01:00
|
|
|
ULONG refcount = InterlockedIncrement(&query->ref);
|
2010-08-31 18:41:38 +02:00
|
|
|
|
2011-02-03 20:14:06 +01:00
|
|
|
TRACE("%p increasing refcount to %u.\n", query, refcount);
|
2010-08-31 18:41:38 +02:00
|
|
|
|
2011-02-03 20:14:06 +01:00
|
|
|
return refcount;
|
2005-03-03 14:57:15 +01:00
|
|
|
}
|
|
|
|
|
2016-06-22 10:39:03 +02:00
|
|
|
static void wined3d_query_destroy_object(void *object)
|
2011-02-03 20:14:06 +01:00
|
|
|
{
|
2016-06-22 10:39:03 +02:00
|
|
|
struct wined3d_query *query = object;
|
2005-03-03 14:57:15 +01:00
|
|
|
|
2021-02-11 11:52:16 +01:00
|
|
|
TRACE("query %p.\n", query);
|
|
|
|
|
2017-04-13 00:11:01 +02:00
|
|
|
if (!list_empty(&query->poll_list_entry))
|
|
|
|
list_remove(&query->poll_list_entry);
|
2016-06-22 10:39:03 +02:00
|
|
|
}
|
2007-03-01 00:34:33 +01:00
|
|
|
|
2016-06-22 10:39:03 +02:00
|
|
|
ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
ULONG refcount = InterlockedDecrement(&query->ref);
|
|
|
|
|
|
|
|
TRACE("%p decreasing refcount to %u.\n", query, refcount);
|
|
|
|
|
|
|
|
if (!refcount)
|
2017-05-10 15:54:07 +02:00
|
|
|
{
|
2019-08-15 11:50:00 +02:00
|
|
|
struct wined3d_device *device = query->device;
|
|
|
|
|
2021-10-15 14:25:57 +02:00
|
|
|
wined3d_mutex_lock();
|
2017-05-10 15:54:07 +02:00
|
|
|
query->parent_ops->wined3d_object_destroyed(query->parent);
|
2019-08-15 11:50:00 +02:00
|
|
|
wined3d_cs_destroy_object(device->cs, wined3d_query_destroy_object, query);
|
|
|
|
device->adapter->adapter_ops->adapter_destroy_query(query);
|
2021-10-15 14:25:57 +02:00
|
|
|
wined3d_mutex_unlock();
|
2017-05-10 15:54:07 +02:00
|
|
|
}
|
2011-02-03 20:14:06 +01:00
|
|
|
|
|
|
|
return refcount;
|
2005-03-03 14:57:15 +01:00
|
|
|
}
|
|
|
|
|
2011-02-03 20:14:06 +01:00
|
|
|
HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
|
|
|
|
void *data, UINT data_size, DWORD flags)
|
2011-02-03 20:14:05 +01:00
|
|
|
{
|
2011-02-03 20:14:06 +01:00
|
|
|
TRACE("query %p, data %p, data_size %u, flags %#x.\n",
|
|
|
|
query, data, data_size, flags);
|
2011-02-03 20:14:05 +01:00
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
if (query->state == QUERY_BUILDING)
|
|
|
|
{
|
|
|
|
WARN("Query is building, returning S_FALSE.\n");
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query->state == QUERY_CREATED)
|
2017-02-03 14:08:46 +01:00
|
|
|
{
|
2016-07-28 13:29:41 +02:00
|
|
|
WARN("Query wasn't started yet.\n");
|
2017-02-03 14:08:46 +01:00
|
|
|
return WINED3DERR_INVALIDCALL;
|
|
|
|
}
|
|
|
|
|
2018-09-28 20:18:29 +02:00
|
|
|
if (query->device->cs->thread)
|
2017-04-13 00:11:01 +02:00
|
|
|
{
|
2018-09-28 20:18:29 +02:00
|
|
|
if (query->counter_main != query->counter_retrieved
|
|
|
|
|| (query->buffer_object && !wined3d_query_buffer_is_valid(query)))
|
|
|
|
{
|
|
|
|
if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
|
2021-04-14 04:05:26 +02:00
|
|
|
query->device->cs->c.ops->flush(&query->device->cs->c);
|
2017-04-13 00:11:01 +02:00
|
|
|
return S_FALSE;
|
2018-09-28 20:18:29 +02:00
|
|
|
}
|
|
|
|
if (query->buffer_object)
|
|
|
|
query->data = query->map_ptr;
|
2017-04-13 00:11:01 +02:00
|
|
|
}
|
2018-09-28 20:18:29 +02:00
|
|
|
else if (!query->query_ops->query_poll(query, flags))
|
2017-04-13 00:11:01 +02:00
|
|
|
{
|
2016-07-28 13:29:41 +02:00
|
|
|
return S_FALSE;
|
2017-04-13 00:11:01 +02:00
|
|
|
}
|
2016-07-28 13:29:41 +02:00
|
|
|
|
|
|
|
if (data)
|
|
|
|
memcpy(data, query->data, min(data_size, query->data_size));
|
|
|
|
|
|
|
|
return S_OK;
|
2011-02-03 20:14:05 +01:00
|
|
|
}
|
|
|
|
|
2011-02-03 20:14:06 +01:00
|
|
|
UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
|
2011-02-03 20:14:05 +01:00
|
|
|
{
|
2011-02-03 20:14:06 +01:00
|
|
|
TRACE("query %p.\n", query);
|
2011-02-03 20:14:05 +01:00
|
|
|
|
|
|
|
return query->data_size;
|
|
|
|
}
|
|
|
|
|
2011-02-03 20:14:06 +01:00
|
|
|
HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
|
2011-02-03 20:14:05 +01:00
|
|
|
{
|
2011-02-03 20:14:06 +01:00
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
2011-02-03 20:14:05 +01:00
|
|
|
|
2021-04-14 04:05:24 +02:00
|
|
|
wined3d_device_context_issue_query(&query->device->cs->c, query, flags);
|
2016-07-28 13:29:42 +02:00
|
|
|
|
|
|
|
return WINED3D_OK;
|
2011-02-03 20:14:05 +01:00
|
|
|
}
|
|
|
|
|
2017-01-04 00:04:49 +01:00
|
|
|
static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags)
|
2010-11-18 20:50:40 +01:00
|
|
|
{
|
2016-07-22 00:43:49 +02:00
|
|
|
struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
|
2016-07-28 13:29:41 +02:00
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2009-01-07 09:00:55 +01:00
|
|
|
GLuint available;
|
2009-07-24 10:44:13 +02:00
|
|
|
|
2017-01-04 00:04:49 +01:00
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
2009-01-07 09:00:55 +01:00
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
if (!(context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
|
2009-01-07 09:00:55 +01:00
|
|
|
{
|
2011-02-03 20:14:05 +01:00
|
|
|
FIXME("%p Wrong thread, returning 1.\n", query);
|
2016-07-28 13:29:41 +02:00
|
|
|
oq->samples = 1;
|
|
|
|
return TRUE;
|
2009-01-07 09:00:55 +01:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2009-07-01 09:46:17 +02:00
|
|
|
|
2015-01-29 18:45:04 +01:00
|
|
|
GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
|
2017-06-05 00:47:37 +02:00
|
|
|
TRACE("Available %#x.\n", available);
|
2009-01-07 09:00:55 +01:00
|
|
|
|
|
|
|
if (available)
|
|
|
|
{
|
2017-06-05 00:47:37 +02:00
|
|
|
oq->samples = get_query_result64(oq->id, gl_info);
|
2016-11-21 15:15:53 +01:00
|
|
|
TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
|
2009-01-07 09:00:55 +01:00
|
|
|
}
|
|
|
|
|
2017-06-05 00:47:37 +02:00
|
|
|
checkGLcall("poll occlusion query");
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2009-10-28 11:00:11 +01:00
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
return available;
|
2008-02-28 21:03:41 +01:00
|
|
|
}
|
|
|
|
|
2017-01-04 00:04:49 +01:00
|
|
|
static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags)
|
2010-11-18 20:50:40 +01:00
|
|
|
{
|
2016-07-22 00:43:48 +02:00
|
|
|
struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
|
2017-07-09 13:25:49 +02:00
|
|
|
enum wined3d_fence_result ret;
|
2009-07-01 09:46:17 +02:00
|
|
|
|
2017-01-04 00:04:49 +01:00
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
2009-06-26 10:07:08 +02:00
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
ret = wined3d_fence_test(&event_query->fence, query->device, flags);
|
2016-07-28 13:29:41 +02:00
|
|
|
switch (ret)
|
2009-08-11 09:42:12 +02:00
|
|
|
{
|
2017-07-09 13:25:49 +02:00
|
|
|
case WINED3D_FENCE_OK:
|
|
|
|
case WINED3D_FENCE_NOT_STARTED:
|
2016-07-28 13:29:41 +02:00
|
|
|
return event_query->signalled = TRUE;
|
2010-03-03 22:45:34 +01:00
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
case WINED3D_FENCE_WAITING:
|
2016-07-28 13:29:41 +02:00
|
|
|
return event_query->signalled = FALSE;
|
2010-03-03 22:45:34 +01:00
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
case WINED3D_FENCE_WRONG_THREAD:
|
2011-02-03 20:14:05 +01:00
|
|
|
FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
|
2016-07-28 13:29:41 +02:00
|
|
|
return event_query->signalled = TRUE;
|
2010-03-03 22:45:34 +01:00
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
case WINED3D_FENCE_ERROR:
|
2016-07-28 13:29:41 +02:00
|
|
|
ERR("The GL event query failed.\n");
|
|
|
|
return event_query->signalled = TRUE;
|
2009-07-01 09:46:17 +02:00
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
default:
|
|
|
|
ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
|
|
|
|
return event_query->signalled = TRUE;
|
|
|
|
}
|
2008-02-28 21:02:58 +01:00
|
|
|
}
|
2005-03-03 14:57:15 +01:00
|
|
|
|
2014-09-19 10:41:47 +02:00
|
|
|
void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
TRACE("query %p.\n", query);
|
|
|
|
|
|
|
|
return query->parent;
|
|
|
|
}
|
|
|
|
|
2012-01-17 21:13:38 +01:00
|
|
|
enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
|
2011-02-03 20:14:06 +01:00
|
|
|
{
|
|
|
|
TRACE("query %p.\n", query);
|
|
|
|
|
|
|
|
return query->type;
|
2005-03-03 14:57:15 +01:00
|
|
|
}
|
|
|
|
|
2017-04-13 00:11:01 +02:00
|
|
|
static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
|
2010-11-18 20:50:40 +01:00
|
|
|
{
|
2011-02-03 20:14:05 +01:00
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
2008-02-28 21:02:58 +01:00
|
|
|
|
2010-11-18 20:50:40 +01:00
|
|
|
if (flags & WINED3DISSUE_END)
|
2009-07-01 09:46:17 +02:00
|
|
|
{
|
2016-07-22 00:43:48 +02:00
|
|
|
struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
|
2010-03-03 23:48:50 +01:00
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
wined3d_fence_issue(&event_query->fence, query->device);
|
2017-04-13 00:11:01 +02:00
|
|
|
return TRUE;
|
2009-07-24 10:44:14 +02:00
|
|
|
}
|
2010-11-18 20:50:40 +01:00
|
|
|
else if (flags & WINED3DISSUE_BEGIN)
|
2009-07-24 10:44:14 +02:00
|
|
|
{
|
2016-07-22 00:43:48 +02:00
|
|
|
/* Started implicitly at query creation. */
|
2008-02-28 21:02:58 +01:00
|
|
|
ERR("Event query issued with START flag - what to do?\n");
|
|
|
|
}
|
2017-04-13 00:11:01 +02:00
|
|
|
|
|
|
|
return FALSE;
|
2008-02-28 21:02:58 +01:00
|
|
|
}
|
|
|
|
|
2017-04-13 00:11:01 +02:00
|
|
|
static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
|
2010-11-18 20:50:40 +01:00
|
|
|
{
|
2016-07-22 00:43:49 +02:00
|
|
|
struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
|
2011-05-16 23:01:23 +02:00
|
|
|
struct wined3d_device *device = query->device;
|
2018-08-21 10:24:29 +02:00
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2017-04-13 00:11:01 +02:00
|
|
|
BOOL poll = FALSE;
|
2006-07-25 00:51:33 +02:00
|
|
|
|
2011-02-03 20:14:05 +01:00
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
2016-07-21 15:58:00 +02:00
|
|
|
/* This is allowed according to MSDN and our tests. Reset the query and
|
|
|
|
* restart. */
|
|
|
|
if (flags & WINED3DISSUE_BEGIN)
|
2009-07-01 09:46:17 +02:00
|
|
|
{
|
2017-04-13 00:11:01 +02:00
|
|
|
if (oq->started)
|
2009-07-01 09:46:17 +02:00
|
|
|
{
|
2019-06-06 14:51:07 +02:00
|
|
|
if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
|
2009-07-24 10:44:13 +02:00
|
|
|
{
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2017-04-05 15:38:05 +02:00
|
|
|
GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
|
|
|
|
checkGLcall("glEndQuery()");
|
2008-02-28 21:03:41 +01:00
|
|
|
}
|
2009-07-24 10:44:13 +02:00
|
|
|
else
|
|
|
|
{
|
2017-04-05 15:38:05 +02:00
|
|
|
FIXME("Wrong thread, can't restart query.\n");
|
2019-05-10 18:31:07 +02:00
|
|
|
wined3d_context_gl_free_occlusion_query(oq);
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
|
|
|
wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
|
2009-07-24 10:44:13 +02:00
|
|
|
}
|
2016-07-21 15:58:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-10 18:31:07 +02:00
|
|
|
if (oq->context_gl)
|
|
|
|
wined3d_context_gl_free_occlusion_query(oq);
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
|
|
|
wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
|
2016-07-21 15:58:00 +02:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2009-07-24 10:44:13 +02:00
|
|
|
|
2016-07-21 15:58:00 +02:00
|
|
|
GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
|
|
|
|
checkGLcall("glBeginQuery()");
|
2009-10-28 11:00:11 +01:00
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-04-13 00:11:01 +02:00
|
|
|
oq->started = TRUE;
|
2016-07-21 15:58:00 +02:00
|
|
|
}
|
|
|
|
if (flags & WINED3DISSUE_END)
|
|
|
|
{
|
|
|
|
/* MSDN says END on a non-building occlusion query returns an error,
|
|
|
|
* but our tests show that it returns OK. But OpenGL doesn't like it,
|
|
|
|
* so avoid generating an error. */
|
2017-04-13 00:11:01 +02:00
|
|
|
if (oq->started)
|
2010-11-18 20:50:40 +01:00
|
|
|
{
|
2019-06-06 14:51:07 +02:00
|
|
|
if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
|
2009-07-24 10:44:13 +02:00
|
|
|
{
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2016-07-21 15:58:00 +02:00
|
|
|
GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
|
|
|
|
checkGLcall("glEndQuery()");
|
2019-07-05 13:38:19 +02:00
|
|
|
wined3d_query_buffer_queue_result(context_gl, query, oq->id);
|
2016-07-21 15:58:00 +02:00
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-04-13 00:11:01 +02:00
|
|
|
poll = TRUE;
|
2006-07-25 00:51:33 +02:00
|
|
|
}
|
2017-04-05 15:38:05 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("Wrong thread, can't end query.\n");
|
|
|
|
}
|
2008-02-28 21:03:41 +01:00
|
|
|
}
|
2017-04-13 00:11:01 +02:00
|
|
|
oq->started = FALSE;
|
2011-02-03 20:14:05 +01:00
|
|
|
}
|
2017-04-13 00:11:01 +02:00
|
|
|
|
|
|
|
return poll;
|
2008-02-28 21:03:41 +01:00
|
|
|
}
|
|
|
|
|
2017-01-04 00:04:49 +01:00
|
|
|
static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
|
2014-04-16 18:14:48 +02:00
|
|
|
{
|
2016-07-22 00:43:50 +02:00
|
|
|
struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
|
2016-07-28 13:29:41 +02:00
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2014-04-16 18:14:48 +02:00
|
|
|
GLuint64 timestamp;
|
2016-07-28 13:29:41 +02:00
|
|
|
GLuint available;
|
2014-04-16 18:14:48 +02:00
|
|
|
|
2017-01-04 00:04:49 +01:00
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
2014-04-16 18:14:48 +02:00
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
if (!(context_gl = wined3d_context_gl_reacquire(tq->context_gl)))
|
2014-04-16 18:14:48 +02:00
|
|
|
{
|
|
|
|
FIXME("%p Wrong thread, returning 1.\n", query);
|
2016-07-28 13:29:41 +02:00
|
|
|
tq->timestamp = 1;
|
|
|
|
return TRUE;
|
2014-04-16 18:14:48 +02:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2014-04-16 18:14:48 +02:00
|
|
|
|
2015-01-29 18:45:04 +01:00
|
|
|
GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
|
|
|
|
checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
|
2014-04-16 18:14:48 +02:00
|
|
|
TRACE("available %#x.\n", available);
|
|
|
|
|
|
|
|
if (available)
|
|
|
|
{
|
2016-07-28 13:29:41 +02:00
|
|
|
GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, ×tamp));
|
|
|
|
checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
|
|
|
|
TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
|
|
|
|
tq->timestamp = timestamp;
|
2014-04-16 18:14:48 +02:00
|
|
|
}
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2014-04-16 18:14:48 +02:00
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
return available;
|
2014-04-16 18:14:48 +02:00
|
|
|
}
|
|
|
|
|
2017-04-13 00:11:01 +02:00
|
|
|
static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
|
2014-04-16 18:14:48 +02:00
|
|
|
{
|
2016-07-22 00:43:50 +02:00
|
|
|
struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
|
2016-07-29 12:34:33 +02:00
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-08-07 13:41:58 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2014-04-16 18:14:48 +02:00
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
2016-07-22 00:43:47 +02:00
|
|
|
if (flags & WINED3DISSUE_BEGIN)
|
2014-04-16 18:14:48 +02:00
|
|
|
{
|
2016-07-22 00:43:47 +02:00
|
|
|
WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
|
2014-04-16 18:14:48 +02:00
|
|
|
}
|
2016-07-22 00:43:47 +02:00
|
|
|
if (flags & WINED3DISSUE_END)
|
2014-04-16 18:14:48 +02:00
|
|
|
{
|
2019-05-14 12:56:20 +02:00
|
|
|
if (tq->context_gl)
|
|
|
|
wined3d_context_gl_free_timestamp_query(tq);
|
2019-08-07 13:41:58 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(query->device, NULL, 0));
|
|
|
|
gl_info = context_gl->gl_info;
|
|
|
|
wined3d_context_gl_alloc_timestamp_query(context_gl, tq);
|
2016-07-22 00:43:47 +02:00
|
|
|
GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
|
|
|
|
checkGLcall("glQueryCounter()");
|
2019-08-07 13:41:58 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-04-13 00:11:01 +02:00
|
|
|
|
|
|
|
return TRUE;
|
2016-07-22 00:43:47 +02:00
|
|
|
}
|
2017-04-13 00:11:01 +02:00
|
|
|
|
|
|
|
return FALSE;
|
2014-04-16 18:14:48 +02:00
|
|
|
}
|
|
|
|
|
2017-01-04 00:04:49 +01:00
|
|
|
static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
|
2014-04-16 18:14:48 +02:00
|
|
|
{
|
2017-01-04 00:04:49 +01:00
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
2014-04-16 18:14:48 +02:00
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
return TRUE;
|
2014-04-16 18:14:48 +02:00
|
|
|
}
|
|
|
|
|
2017-04-13 00:11:01 +02:00
|
|
|
static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
|
2014-04-16 18:14:48 +02:00
|
|
|
{
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
2017-04-13 00:11:01 +02:00
|
|
|
|
|
|
|
return FALSE;
|
2014-04-16 18:14:48 +02:00
|
|
|
}
|
|
|
|
|
2017-05-24 17:09:59 +02:00
|
|
|
static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
|
|
|
|
{
|
|
|
|
struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
|
|
|
|
GLuint written_available, generated_available;
|
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2017-05-24 17:09:59 +02:00
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
|
2017-05-24 17:09:59 +02:00
|
|
|
{
|
|
|
|
FIXME("%p Wrong thread, returning 0 primitives.\n", query);
|
|
|
|
memset(&pq->statistics, 0, sizeof(pq->statistics));
|
|
|
|
return TRUE;
|
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2017-05-24 17:09:59 +02:00
|
|
|
|
|
|
|
GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
|
|
|
|
GL_QUERY_RESULT_AVAILABLE, &written_available));
|
|
|
|
GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
|
|
|
|
GL_QUERY_RESULT_AVAILABLE, &generated_available));
|
|
|
|
TRACE("Available %#x, %#x.\n", written_available, generated_available);
|
|
|
|
|
|
|
|
if (written_available && generated_available)
|
|
|
|
{
|
2017-06-05 00:47:37 +02:00
|
|
|
pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
|
|
|
|
pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
|
2017-05-24 17:09:59 +02:00
|
|
|
TRACE("Returning %s, %s primitives.\n",
|
|
|
|
wine_dbgstr_longlong(pq->statistics.primitives_written),
|
|
|
|
wine_dbgstr_longlong(pq->statistics.primitives_generated));
|
|
|
|
}
|
|
|
|
|
|
|
|
checkGLcall("poll SO statistics query");
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-05-24 17:09:59 +02:00
|
|
|
|
|
|
|
return written_available && generated_available;
|
|
|
|
}
|
|
|
|
|
2018-11-21 15:14:01 +01:00
|
|
|
static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query *query,
|
2019-07-05 13:38:20 +02:00
|
|
|
struct wined3d_context_gl *context_gl)
|
2018-11-21 15:14:01 +01:00
|
|
|
{
|
2019-08-07 13:41:58 +02:00
|
|
|
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
|
2018-11-21 15:14:01 +01:00
|
|
|
|
|
|
|
if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
|
|
|
|
{
|
|
|
|
GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->stream_idx));
|
|
|
|
GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, query->stream_idx));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED));
|
|
|
|
}
|
|
|
|
checkGLcall("end query");
|
|
|
|
}
|
|
|
|
|
2017-05-24 17:09:59 +02:00
|
|
|
static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
|
|
|
|
{
|
|
|
|
struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
|
|
|
|
struct wined3d_device *device = query->device;
|
2018-08-21 10:24:29 +02:00
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2017-05-24 17:09:59 +02:00
|
|
|
BOOL poll = FALSE;
|
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
|
|
|
if (flags & WINED3DISSUE_BEGIN)
|
|
|
|
{
|
|
|
|
if (pq->started)
|
|
|
|
{
|
2019-06-06 14:51:07 +02:00
|
|
|
if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
|
2017-05-24 17:09:59 +02:00
|
|
|
{
|
2019-07-05 13:38:20 +02:00
|
|
|
wined3d_so_statistics_query_end(pq, context_gl);
|
2017-05-24 17:09:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("Wrong thread, can't restart query.\n");
|
2019-05-14 12:56:21 +02:00
|
|
|
wined3d_context_gl_free_so_statistics_query(pq);
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
|
|
|
wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
|
2017-05-24 17:09:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-14 12:56:21 +02:00
|
|
|
if (pq->context_gl)
|
|
|
|
wined3d_context_gl_free_so_statistics_query(pq);
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
|
|
|
wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
|
2017-05-24 17:09:59 +02:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2017-05-24 17:09:59 +02:00
|
|
|
|
2018-11-21 15:14:01 +01:00
|
|
|
if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
|
|
|
|
{
|
|
|
|
GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
|
|
|
|
pq->stream_idx, pq->u.query.written));
|
|
|
|
GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
|
|
|
|
pq->stream_idx, pq->u.query.generated));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
|
|
|
|
pq->u.query.written));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED,
|
|
|
|
pq->u.query.generated));
|
|
|
|
}
|
2017-05-24 17:09:59 +02:00
|
|
|
checkGLcall("begin query");
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-05-24 17:09:59 +02:00
|
|
|
pq->started = TRUE;
|
|
|
|
}
|
|
|
|
if (flags & WINED3DISSUE_END)
|
|
|
|
{
|
|
|
|
if (pq->started)
|
|
|
|
{
|
2019-06-06 14:51:07 +02:00
|
|
|
if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
|
2017-05-24 17:09:59 +02:00
|
|
|
{
|
2019-07-05 13:38:20 +02:00
|
|
|
wined3d_so_statistics_query_end(pq, context_gl);
|
2017-05-24 17:09:59 +02:00
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-05-24 17:09:59 +02:00
|
|
|
poll = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("Wrong thread, can't end query.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pq->started = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return poll;
|
|
|
|
}
|
|
|
|
|
2017-06-05 00:47:34 +02:00
|
|
|
static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
|
|
|
|
{
|
|
|
|
struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
|
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2017-06-05 00:47:34 +02:00
|
|
|
GLuint available;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
|
2017-06-05 00:47:34 +02:00
|
|
|
{
|
|
|
|
FIXME("%p Wrong thread.\n", query);
|
|
|
|
memset(&pq->statistics, 0, sizeof(pq->statistics));
|
|
|
|
return TRUE;
|
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2017-06-05 00:47:34 +02:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
|
|
|
|
{
|
|
|
|
GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
|
|
|
|
if (!available)
|
2017-06-05 00:47:37 +02:00
|
|
|
break;
|
2017-06-05 00:47:34 +02:00
|
|
|
}
|
|
|
|
|
2017-06-05 00:47:37 +02:00
|
|
|
if (available)
|
2017-06-05 00:47:34 +02:00
|
|
|
{
|
2017-06-05 00:47:37 +02:00
|
|
|
pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
|
|
|
|
pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
|
|
|
|
pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
|
|
|
|
pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
|
|
|
|
pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
|
|
|
|
pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
|
|
|
|
pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
|
|
|
|
pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
|
|
|
|
pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
|
|
|
|
pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
|
|
|
|
pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
|
2017-06-05 00:47:34 +02:00
|
|
|
}
|
2017-06-05 00:47:37 +02:00
|
|
|
|
2017-06-05 00:47:34 +02:00
|
|
|
checkGLcall("poll pipeline statistics query");
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-06-05 00:47:34 +02:00
|
|
|
return available;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
|
2019-07-05 13:38:21 +02:00
|
|
|
struct wined3d_context_gl *context_gl)
|
2017-06-05 00:47:34 +02:00
|
|
|
{
|
2019-08-07 13:41:58 +02:00
|
|
|
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
|
2017-06-05 00:47:34 +02:00
|
|
|
|
|
|
|
GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
|
|
|
|
GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
|
|
|
|
checkGLcall("end query");
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
|
|
|
|
{
|
|
|
|
struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
|
|
|
|
struct wined3d_device *device = query->device;
|
2018-08-21 10:24:29 +02:00
|
|
|
const struct wined3d_gl_info *gl_info;
|
2019-06-06 14:51:07 +02:00
|
|
|
struct wined3d_context_gl *context_gl;
|
2017-06-05 00:47:34 +02:00
|
|
|
BOOL poll = FALSE;
|
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
|
|
|
if (flags & WINED3DISSUE_BEGIN)
|
|
|
|
{
|
|
|
|
if (pq->started)
|
|
|
|
{
|
2019-06-06 14:51:07 +02:00
|
|
|
if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
|
2017-06-05 00:47:34 +02:00
|
|
|
{
|
2019-07-05 13:38:21 +02:00
|
|
|
wined3d_pipeline_statistics_query_end(pq, context_gl);
|
2017-06-05 00:47:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("Wrong thread, can't restart query.\n");
|
2019-05-14 12:56:22 +02:00
|
|
|
wined3d_context_gl_free_pipeline_statistics_query(pq);
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
|
|
|
wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
|
2017-06-05 00:47:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-14 12:56:22 +02:00
|
|
|
if (pq->context_gl)
|
|
|
|
wined3d_context_gl_free_pipeline_statistics_query(pq);
|
2019-06-06 14:51:07 +02:00
|
|
|
context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
|
|
|
|
wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
|
2017-06-05 00:47:34 +02:00
|
|
|
}
|
2019-08-07 13:41:58 +02:00
|
|
|
gl_info = context_gl->gl_info;
|
2017-06-05 00:47:34 +02:00
|
|
|
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
|
|
|
|
GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
|
|
|
|
checkGLcall("begin query");
|
|
|
|
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-06-05 00:47:34 +02:00
|
|
|
pq->started = TRUE;
|
|
|
|
}
|
|
|
|
if (flags & WINED3DISSUE_END)
|
|
|
|
{
|
|
|
|
if (pq->started)
|
|
|
|
{
|
2019-06-06 14:51:07 +02:00
|
|
|
if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
|
2017-06-05 00:47:34 +02:00
|
|
|
{
|
2019-07-05 13:38:21 +02:00
|
|
|
wined3d_pipeline_statistics_query_end(pq, context_gl);
|
2019-06-06 14:51:07 +02:00
|
|
|
context_release(&context_gl->c);
|
2017-06-05 00:47:34 +02:00
|
|
|
poll = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("Wrong thread, can't end query.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pq->started = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return poll;
|
|
|
|
}
|
|
|
|
|
2017-05-26 10:48:03 +02:00
|
|
|
static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
|
|
|
|
|
2017-07-09 13:25:49 +02:00
|
|
|
wined3d_fence_free(&event_query->fence);
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(event_query);
|
2017-05-26 10:48:03 +02:00
|
|
|
}
|
|
|
|
|
2011-02-03 20:14:05 +01:00
|
|
|
static const struct wined3d_query_ops event_query_ops =
|
2008-02-28 21:02:58 +01:00
|
|
|
{
|
2016-07-28 13:29:41 +02:00
|
|
|
wined3d_event_query_ops_poll,
|
2011-02-03 20:14:05 +01:00
|
|
|
wined3d_event_query_ops_issue,
|
2017-05-26 10:48:03 +02:00
|
|
|
wined3d_event_query_ops_destroy,
|
2011-02-03 20:14:05 +01:00
|
|
|
};
|
|
|
|
|
2016-07-22 00:43:48 +02:00
|
|
|
static HRESULT wined3d_event_query_create(struct wined3d_device *device,
|
2017-05-10 15:54:07 +02:00
|
|
|
enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
|
|
struct wined3d_query **query)
|
2016-07-22 00:43:48 +02:00
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
|
|
|
struct wined3d_event_query *object;
|
2017-07-09 13:25:49 +02:00
|
|
|
HRESULT hr;
|
2016-07-22 00:43:48 +02:00
|
|
|
|
2017-05-10 15:54:07 +02:00
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
2016-07-22 00:43:48 +02:00
|
|
|
|
2018-02-14 07:39:59 +01:00
|
|
|
if (!(object = heap_alloc_zero(sizeof(*object))))
|
2017-07-09 13:25:49 +02:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
|
2016-07-22 00:43:48 +02:00
|
|
|
{
|
|
|
|
WARN("Event queries not supported.\n");
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(object);
|
2017-07-12 15:03:02 +02:00
|
|
|
return hr;
|
2016-07-22 00:43:48 +02:00
|
|
|
}
|
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
wined3d_query_init(&object->query, device, type, &object->signalled,
|
2017-05-10 15:54:07 +02:00
|
|
|
sizeof(object->signalled), &event_query_ops, parent, parent_ops);
|
2016-07-22 00:43:48 +02:00
|
|
|
|
|
|
|
TRACE("Created query %p.\n", object);
|
|
|
|
*query = &object->query;
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
2017-05-26 10:48:03 +02:00
|
|
|
static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
|
|
|
|
|
2019-05-10 18:31:07 +02:00
|
|
|
if (oq->context_gl)
|
|
|
|
wined3d_context_gl_free_occlusion_query(oq);
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(oq);
|
2017-05-26 10:48:03 +02:00
|
|
|
}
|
|
|
|
|
2011-02-03 20:14:05 +01:00
|
|
|
static const struct wined3d_query_ops occlusion_query_ops =
|
|
|
|
{
|
2016-07-28 13:29:41 +02:00
|
|
|
wined3d_occlusion_query_ops_poll,
|
2011-02-03 20:14:05 +01:00
|
|
|
wined3d_occlusion_query_ops_issue,
|
2017-05-26 10:48:03 +02:00
|
|
|
wined3d_occlusion_query_ops_destroy,
|
2008-02-28 21:02:58 +01:00
|
|
|
};
|
2008-02-28 21:03:41 +01:00
|
|
|
|
2016-07-22 00:43:49 +02:00
|
|
|
static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
|
2017-05-10 15:54:07 +02:00
|
|
|
enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
|
|
struct wined3d_query **query)
|
2016-07-22 00:43:49 +02:00
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
|
|
|
struct wined3d_occlusion_query *object;
|
|
|
|
|
2017-05-10 15:54:07 +02:00
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
2016-07-22 00:43:49 +02:00
|
|
|
|
|
|
|
if (!gl_info->supported[ARB_OCCLUSION_QUERY])
|
|
|
|
{
|
|
|
|
WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
|
2018-02-14 07:39:59 +01:00
|
|
|
if (!(object = heap_alloc_zero(sizeof(*object))))
|
2016-07-22 00:43:49 +02:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
wined3d_query_init(&object->query, device, type, &object->samples,
|
2017-05-10 15:54:07 +02:00
|
|
|
sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
|
2016-07-22 00:43:49 +02:00
|
|
|
|
|
|
|
TRACE("Created query %p.\n", object);
|
|
|
|
*query = &object->query;
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
2017-05-26 10:48:03 +02:00
|
|
|
static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
|
|
|
|
|
2019-05-14 12:56:20 +02:00
|
|
|
if (tq->context_gl)
|
|
|
|
wined3d_context_gl_free_timestamp_query(tq);
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(tq);
|
2017-05-26 10:48:03 +02:00
|
|
|
}
|
|
|
|
|
2014-04-16 18:14:48 +02:00
|
|
|
static const struct wined3d_query_ops timestamp_query_ops =
|
|
|
|
{
|
2016-07-28 13:29:41 +02:00
|
|
|
wined3d_timestamp_query_ops_poll,
|
2014-04-16 18:14:48 +02:00
|
|
|
wined3d_timestamp_query_ops_issue,
|
2017-05-26 10:48:03 +02:00
|
|
|
wined3d_timestamp_query_ops_destroy,
|
2014-04-16 18:14:48 +02:00
|
|
|
};
|
|
|
|
|
2016-07-22 00:43:50 +02:00
|
|
|
static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
|
2017-05-10 15:54:07 +02:00
|
|
|
enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
|
|
struct wined3d_query **query)
|
2016-07-22 00:43:50 +02:00
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
|
|
|
struct wined3d_timestamp_query *object;
|
|
|
|
|
2017-05-10 15:54:07 +02:00
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
2016-07-22 00:43:50 +02:00
|
|
|
|
|
|
|
if (!gl_info->supported[ARB_TIMER_QUERY])
|
|
|
|
{
|
|
|
|
WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
|
2018-02-14 07:39:59 +01:00
|
|
|
if (!(object = heap_alloc_zero(sizeof(*object))))
|
2016-07-22 00:43:50 +02:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
2016-07-28 13:29:41 +02:00
|
|
|
wined3d_query_init(&object->query, device, type, &object->timestamp,
|
2017-05-10 15:54:07 +02:00
|
|
|
sizeof(object->timestamp), ×tamp_query_ops, parent, parent_ops);
|
2016-07-22 00:43:50 +02:00
|
|
|
|
|
|
|
TRACE("Created query %p.\n", object);
|
|
|
|
*query = &object->query;
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
2017-05-26 10:48:03 +02:00
|
|
|
static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
|
|
|
|
{
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(query);
|
2017-05-26 10:48:03 +02:00
|
|
|
}
|
|
|
|
|
2014-04-16 18:14:48 +02:00
|
|
|
static const struct wined3d_query_ops timestamp_disjoint_query_ops =
|
|
|
|
{
|
2016-07-28 13:29:41 +02:00
|
|
|
wined3d_timestamp_disjoint_query_ops_poll,
|
2014-04-16 18:14:48 +02:00
|
|
|
wined3d_timestamp_disjoint_query_ops_issue,
|
2017-05-26 10:48:03 +02:00
|
|
|
wined3d_timestamp_disjoint_query_ops_destroy,
|
2014-04-16 18:14:48 +02:00
|
|
|
};
|
|
|
|
|
2016-07-22 00:43:51 +02:00
|
|
|
static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
|
2017-05-10 15:54:07 +02:00
|
|
|
enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
|
|
struct wined3d_query **query)
|
2010-01-17 21:31:30 +01:00
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
2016-07-22 00:43:51 +02:00
|
|
|
struct wined3d_query *object;
|
2010-01-17 21:31:30 +01:00
|
|
|
|
2017-05-10 15:54:07 +02:00
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
2014-09-19 10:41:47 +02:00
|
|
|
|
2016-07-22 00:43:51 +02:00
|
|
|
if (!gl_info->supported[ARB_TIMER_QUERY])
|
2010-01-17 21:31:30 +01:00
|
|
|
{
|
2016-07-22 00:43:51 +02:00
|
|
|
WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
2010-01-17 21:31:30 +01:00
|
|
|
}
|
|
|
|
|
2018-02-14 07:39:59 +01:00
|
|
|
if (!(object = heap_alloc_zero(sizeof(*object))))
|
2016-07-22 00:43:51 +02:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
|
2016-07-28 13:29:41 +02:00
|
|
|
{
|
|
|
|
static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
|
|
|
|
|
|
|
|
wined3d_query_init(object, device, type, &disjoint_data,
|
2017-05-10 15:54:07 +02:00
|
|
|
sizeof(disjoint_data), ×tamp_disjoint_query_ops, parent, parent_ops);
|
2016-07-28 13:29:41 +02:00
|
|
|
}
|
2016-07-22 00:43:51 +02:00
|
|
|
else
|
2016-07-28 13:29:41 +02:00
|
|
|
{
|
|
|
|
static const UINT64 freq = 1000 * 1000 * 1000;
|
|
|
|
|
|
|
|
wined3d_query_init(object, device, type, &freq,
|
2017-05-10 15:54:07 +02:00
|
|
|
sizeof(freq), ×tamp_disjoint_query_ops, parent, parent_ops);
|
2016-07-28 13:29:41 +02:00
|
|
|
}
|
2016-07-22 00:43:51 +02:00
|
|
|
|
|
|
|
TRACE("Created query %p.\n", object);
|
|
|
|
*query = object;
|
2010-01-17 21:31:30 +01:00
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
2011-05-10 21:18:47 +02:00
|
|
|
|
2017-05-26 10:48:03 +02:00
|
|
|
static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
|
|
|
|
|
2019-05-14 12:56:21 +02:00
|
|
|
if (pq->context_gl)
|
|
|
|
wined3d_context_gl_free_so_statistics_query(pq);
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(pq);
|
2017-05-26 10:48:03 +02:00
|
|
|
}
|
|
|
|
|
2017-05-24 17:09:59 +02:00
|
|
|
static const struct wined3d_query_ops so_statistics_query_ops =
|
|
|
|
{
|
|
|
|
wined3d_so_statistics_query_ops_poll,
|
|
|
|
wined3d_so_statistics_query_ops_issue,
|
2017-05-26 10:48:03 +02:00
|
|
|
wined3d_so_statistics_query_ops_destroy,
|
2017-05-24 17:09:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
|
|
|
|
enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
|
|
struct wined3d_query **query)
|
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
|
|
|
struct wined3d_so_statistics_query *object;
|
2017-06-05 00:47:38 +02:00
|
|
|
unsigned int stream_idx;
|
|
|
|
|
|
|
|
if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
|
|
|
|
stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
|
2018-11-21 15:14:02 +01:00
|
|
|
else if (type == WINED3D_QUERY_TYPE_SO_STATISTICS)
|
|
|
|
stream_idx = 0;
|
2017-06-05 00:47:38 +02:00
|
|
|
else
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
2017-05-24 17:09:59 +02:00
|
|
|
|
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
|
|
|
|
|
|
|
if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
|
|
|
|
{
|
|
|
|
WARN("OpenGL implementation does not support primitive queries.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
2018-11-21 15:14:01 +01:00
|
|
|
if (stream_idx && !gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
|
2017-05-24 17:09:59 +02:00
|
|
|
{
|
|
|
|
WARN("OpenGL implementation does not support indexed queries.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
|
2018-02-14 07:39:59 +01:00
|
|
|
if (!(object = heap_alloc_zero(sizeof(*object))))
|
2017-05-24 17:09:59 +02:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
wined3d_query_init(&object->query, device, type, &object->statistics,
|
|
|
|
sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
|
2017-06-05 00:47:38 +02:00
|
|
|
object->stream_idx = stream_idx;
|
2017-05-24 17:09:59 +02:00
|
|
|
|
|
|
|
TRACE("Created query %p.\n", object);
|
|
|
|
*query = &object->query;
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
2017-06-05 00:47:34 +02:00
|
|
|
static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
|
2019-05-14 12:56:22 +02:00
|
|
|
if (pq->context_gl)
|
|
|
|
wined3d_context_gl_free_pipeline_statistics_query(pq);
|
2018-02-14 07:39:59 +01:00
|
|
|
heap_free(pq);
|
2017-06-05 00:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wined3d_query_ops pipeline_query_ops =
|
|
|
|
{
|
|
|
|
wined3d_pipeline_query_ops_poll,
|
|
|
|
wined3d_pipeline_query_ops_issue,
|
|
|
|
wined3d_pipeline_query_ops_destroy,
|
|
|
|
};
|
|
|
|
|
|
|
|
static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
|
|
|
|
enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
|
|
|
|
struct wined3d_query **query)
|
|
|
|
{
|
|
|
|
const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
|
|
|
|
struct wined3d_pipeline_statistics_query *object;
|
|
|
|
|
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
|
|
|
|
|
|
|
if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
|
|
|
|
{
|
|
|
|
WARN("OpenGL implementation does not support pipeline statistics queries.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
|
2018-02-14 07:39:59 +01:00
|
|
|
if (!(object = heap_alloc_zero(sizeof(*object))))
|
2017-06-05 00:47:34 +02:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
wined3d_query_init(&object->query, device, type, &object->statistics,
|
|
|
|
sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
|
|
|
|
|
|
|
|
TRACE("Created query %p.\n", object);
|
|
|
|
*query = &object->query;
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
2019-08-15 11:50:00 +02:00
|
|
|
HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_query_type type,
|
2017-05-10 15:54:07 +02:00
|
|
|
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
|
2011-05-10 21:18:47 +02:00
|
|
|
{
|
2017-05-10 15:54:07 +02:00
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
2011-05-10 21:18:47 +02:00
|
|
|
|
2016-07-22 00:43:48 +02:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case WINED3D_QUERY_TYPE_EVENT:
|
2017-05-10 15:54:07 +02:00
|
|
|
return wined3d_event_query_create(device, type, parent, parent_ops, query);
|
2016-07-22 00:43:48 +02:00
|
|
|
|
2016-07-22 00:43:49 +02:00
|
|
|
case WINED3D_QUERY_TYPE_OCCLUSION:
|
2017-05-10 15:54:07 +02:00
|
|
|
return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
|
2016-07-22 00:43:49 +02:00
|
|
|
|
2016-07-22 00:43:50 +02:00
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP:
|
2017-05-10 15:54:07 +02:00
|
|
|
return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
|
2016-07-22 00:43:50 +02:00
|
|
|
|
2016-07-22 00:43:51 +02:00
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
|
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
|
2017-05-10 15:54:07 +02:00
|
|
|
return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
|
2011-05-10 21:18:47 +02:00
|
|
|
|
2018-11-21 15:14:02 +01:00
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS:
|
2017-05-24 17:09:59 +02:00
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
|
|
|
|
return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
|
|
|
|
|
2017-06-05 00:47:34 +02:00
|
|
|
case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
|
|
|
|
return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
|
|
|
|
|
2016-07-22 00:43:51 +02:00
|
|
|
default:
|
|
|
|
FIXME("Unhandled query type %#x.\n", type);
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
2011-05-10 21:18:47 +02:00
|
|
|
}
|
|
|
|
}
|
2019-08-15 11:50:00 +02:00
|
|
|
|
2021-06-28 17:52:41 +02:00
|
|
|
static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx,
|
|
|
|
struct wined3d_context_vk *context_vk)
|
2020-05-26 18:10:11 +02:00
|
|
|
{
|
wined3d: Avoid waiting for a command buffer to finish executing to read off its queries.
Some games wait for query results on the frame executing the query,
expecting that enough time have passed for it to be available. By
requiring that the entire command buffer is done, we risk stalling the
whole frame if it wasn't flushed along the way. This patch drops this
requirement.
Mainly, we need to ensure that we don't call vkGetQueryPoolResults()
before the reset command is executed, and accidentally retrieve result
from previous usage. Using host query reset doesn't quite solve the
problem, as it might get called too early, if the application decides to
reuse a query without waiting for results. Besides, we want to support
devices where host query reset is not available.
To make it work, when a Vulkan query is no longer needed, we queue it
for resetting at command buffer submission time, and only mark it free
for reuse after this command buffer is finished executing.
Signed-off-by: Jan Sikorski <jsikorski@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2022-02-10 15:21:56 +01:00
|
|
|
/* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
|
|
|
|
* outside of a render pass. Queue the query to be reset at the very end of the current
|
|
|
|
* command buffer instead. */
|
|
|
|
wined3d_bitmap_set(pool_vk->completed, idx);
|
|
|
|
if (list_empty(&pool_vk->completed_entry))
|
|
|
|
list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry);
|
2020-05-26 18:10:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
|
|
|
|
{
|
|
|
|
if ((*idx = wined3d_bitmap_ffz(pool_vk->allocated, WINED3D_QUERY_POOL_SIZE, 0)) > WINED3D_QUERY_POOL_SIZE)
|
|
|
|
return false;
|
|
|
|
wined3d_bitmap_set(pool_vk->allocated, *idx);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
wined3d: Avoid waiting for a command buffer to finish executing to read off its queries.
Some games wait for query results on the frame executing the query,
expecting that enough time have passed for it to be available. By
requiring that the entire command buffer is done, we risk stalling the
whole frame if it wasn't flushed along the way. This patch drops this
requirement.
Mainly, we need to ensure that we don't call vkGetQueryPoolResults()
before the reset command is executed, and accidentally retrieve result
from previous usage. Using host query reset doesn't quite solve the
problem, as it might get called too early, if the application decides to
reuse a query without waiting for results. Besides, we want to support
devices where host query reset is not available.
To make it work, when a Vulkan query is no longer needed, we queue it
for resetting at command buffer submission time, and only mark it free
for reuse after this command buffer is finished executing.
Signed-off-by: Jan Sikorski <jsikorski@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2022-02-10 15:21:56 +01:00
|
|
|
void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk *context_vk, struct wined3d_query_pool_vk *pool_vk,
|
|
|
|
uint32_t start, uint32_t count)
|
|
|
|
{
|
|
|
|
unsigned int idx, end = start + count;
|
|
|
|
|
|
|
|
for (idx = start; idx < end; ++idx)
|
|
|
|
wined3d_bitmap_clear(pool_vk->allocated, idx);
|
|
|
|
|
|
|
|
if (list_empty(&pool_vk->entry))
|
|
|
|
list_add_tail(pool_vk->free_list, &pool_vk->entry);
|
|
|
|
}
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk)
|
|
|
|
{
|
|
|
|
struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
|
|
|
|
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
|
|
|
|
|
|
|
|
VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
|
wined3d: Avoid waiting for a command buffer to finish executing to read off its queries.
Some games wait for query results on the frame executing the query,
expecting that enough time have passed for it to be available. By
requiring that the entire command buffer is done, we risk stalling the
whole frame if it wasn't flushed along the way. This patch drops this
requirement.
Mainly, we need to ensure that we don't call vkGetQueryPoolResults()
before the reset command is executed, and accidentally retrieve result
from previous usage. Using host query reset doesn't quite solve the
problem, as it might get called too early, if the application decides to
reuse a query without waiting for results. Besides, we want to support
devices where host query reset is not available.
To make it work, when a Vulkan query is no longer needed, we queue it
for resetting at command buffer submission time, and only mark it free
for reuse after this command buffer is finished executing.
Signed-off-by: Jan Sikorski <jsikorski@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2022-02-10 15:21:56 +01:00
|
|
|
if (pool_vk->vk_event)
|
|
|
|
VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_vk->vk_event, NULL));
|
2020-05-26 18:10:11 +02:00
|
|
|
list_remove(&pool_vk->entry);
|
2021-06-28 17:52:41 +02:00
|
|
|
list_remove(&pool_vk->completed_entry);
|
|
|
|
}
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk,
|
|
|
|
struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
|
|
|
|
{
|
|
|
|
struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
|
|
|
|
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
|
|
|
|
VkQueryPoolCreateInfo pool_info;
|
|
|
|
VkResult vr;
|
|
|
|
|
|
|
|
list_init(&pool_vk->entry);
|
2021-06-28 17:52:41 +02:00
|
|
|
list_init(&pool_vk->completed_entry);
|
2020-05-26 18:10:11 +02:00
|
|
|
pool_vk->free_list = free_pools;
|
|
|
|
|
|
|
|
pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
|
|
|
|
pool_info.pNext = NULL;
|
|
|
|
pool_info.flags = 0;
|
|
|
|
pool_info.queryCount = WINED3D_QUERY_POOL_SIZE;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case WINED3D_QUERY_TYPE_OCCLUSION:
|
|
|
|
pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
|
|
|
|
pool_info.pipelineStatistics = 0;
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:12 +02:00
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP:
|
|
|
|
pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
|
|
|
|
pool_info.pipelineStatistics = 0;
|
|
|
|
break;
|
|
|
|
|
2020-05-27 17:55:34 +02:00
|
|
|
case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
|
|
|
|
pool_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
|
|
|
|
pool_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
|
|
|
|
| VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
|
|
|
|
break;
|
|
|
|
|
2020-10-07 14:57:13 +02:00
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
|
|
|
|
pool_info.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
|
|
|
|
pool_info.pipelineStatistics = 0;
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
default:
|
|
|
|
FIXME("Unhandled query type %#x.\n", type);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((vr = VK_CALL(vkCreateQueryPool(device_vk->vk_device, &pool_info, NULL, &pool_vk->vk_query_pool))) < 0)
|
|
|
|
{
|
|
|
|
ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_add_head(free_pools, &pool_vk->entry);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk,
|
|
|
|
struct wined3d_context_vk *context_vk, const struct wined3d_query_pool_idx_vk *pool_idx)
|
|
|
|
{
|
|
|
|
struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
|
2020-05-27 17:55:34 +02:00
|
|
|
const struct wined3d_query_data_pipeline_statistics *ps_tmp;
|
2020-05-26 18:10:11 +02:00
|
|
|
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
|
2020-05-27 17:55:34 +02:00
|
|
|
struct wined3d_query_data_pipeline_statistics *ps_result;
|
2020-05-26 18:10:11 +02:00
|
|
|
VkResult vr;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
uint64_t occlusion;
|
2020-05-26 18:10:12 +02:00
|
|
|
uint64_t timestamp;
|
2020-05-27 17:55:34 +02:00
|
|
|
struct wined3d_query_data_pipeline_statistics pipeline_statistics;
|
2020-10-07 14:57:13 +02:00
|
|
|
struct wined3d_query_data_so_statistics so_statistics;
|
2020-05-26 18:10:11 +02:00
|
|
|
} tmp, *result;
|
|
|
|
|
wined3d: Avoid waiting for a command buffer to finish executing to read off its queries.
Some games wait for query results on the frame executing the query,
expecting that enough time have passed for it to be available. By
requiring that the entire command buffer is done, we risk stalling the
whole frame if it wasn't flushed along the way. This patch drops this
requirement.
Mainly, we need to ensure that we don't call vkGetQueryPoolResults()
before the reset command is executed, and accidentally retrieve result
from previous usage. Using host query reset doesn't quite solve the
problem, as it might get called too early, if the application decides to
reuse a query without waiting for results. Besides, we want to support
devices where host query reset is not available.
To make it work, when a Vulkan query is no longer needed, we queue it
for resetting at command buffer submission time, and only mark it free
for reuse after this command buffer is finished executing.
Signed-off-by: Jan Sikorski <jsikorski@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2022-02-10 15:21:56 +01:00
|
|
|
if (pool_idx->pool_vk->vk_event)
|
|
|
|
{
|
|
|
|
/* Check if the pool's initial reset command executed. */
|
|
|
|
vr = VK_CALL(vkGetEventStatus(device_vk->vk_device,
|
|
|
|
pool_idx->pool_vk->vk_event));
|
|
|
|
if (vr == VK_EVENT_RESET)
|
|
|
|
return false;
|
|
|
|
else if (vr != VK_EVENT_SET)
|
|
|
|
{
|
|
|
|
ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_idx->pool_vk->vk_event, NULL));
|
|
|
|
pool_idx->pool_vk->vk_event = VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool,
|
|
|
|
pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
|
|
|
|
{
|
|
|
|
ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vr == VK_NOT_READY)
|
|
|
|
return false;
|
|
|
|
|
2021-06-28 17:52:41 +02:00
|
|
|
wined3d_query_pool_vk_mark_complete(pool_idx->pool_vk, pool_idx->idx, context_vk);
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
result = (void *)query_vk->q.data;
|
|
|
|
switch (query_vk->q.type)
|
|
|
|
{
|
|
|
|
case WINED3D_QUERY_TYPE_OCCLUSION:
|
|
|
|
result->occlusion += tmp.occlusion;
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:12 +02:00
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP:
|
|
|
|
result->timestamp = tmp.timestamp;
|
|
|
|
break;
|
|
|
|
|
2020-05-27 17:55:34 +02:00
|
|
|
case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
|
|
|
|
ps_result = &result->pipeline_statistics;
|
|
|
|
ps_tmp = &tmp.pipeline_statistics;
|
|
|
|
ps_result->vertices_submitted += ps_tmp->vertices_submitted;
|
|
|
|
ps_result->primitives_submitted += ps_tmp->primitives_submitted;
|
|
|
|
ps_result->vs_invocations += ps_tmp->vs_invocations;
|
|
|
|
ps_result->gs_invocations += ps_tmp->gs_invocations;
|
|
|
|
ps_result->gs_primitives += ps_tmp->gs_primitives;
|
|
|
|
ps_result->clipping_input_primitives += ps_tmp->clipping_input_primitives;
|
|
|
|
ps_result->clipping_output_primitives += ps_tmp->clipping_output_primitives;
|
|
|
|
ps_result->ps_invocations += ps_tmp->ps_invocations;
|
|
|
|
ps_result->hs_invocations += ps_tmp->hs_invocations;
|
|
|
|
ps_result->ds_invocations += ps_tmp->ds_invocations;
|
|
|
|
ps_result->cs_invocations += ps_tmp->cs_invocations;
|
|
|
|
break;
|
|
|
|
|
2020-10-07 14:57:13 +02:00
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
|
|
|
|
result->so_statistics.primitives_written += tmp.so_statistics.primitives_written;
|
|
|
|
result->so_statistics.primitives_generated += tmp.so_statistics.primitives_generated;
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
default:
|
|
|
|
FIXME("Unhandled query type %#x.\n", query_vk->q.type);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk,
|
|
|
|
struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
|
|
|
|
{
|
|
|
|
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
|
|
|
|
struct wined3d_query_pool_vk *pool_vk;
|
|
|
|
size_t idx;
|
|
|
|
|
|
|
|
pool_vk = query_vk->pool_idx.pool_vk;
|
|
|
|
idx = query_vk->pool_idx.idx;
|
|
|
|
|
2020-10-07 14:57:13 +02:00
|
|
|
if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
|
|
|
|
&& query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
|
|
|
|
VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool, idx,
|
|
|
|
query_vk->control_flags, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
|
|
|
|
else
|
|
|
|
VK_CALL(vkCmdBeginQuery(vk_command_buffer, pool_vk->vk_query_pool, idx, query_vk->control_flags));
|
2020-05-26 18:10:11 +02:00
|
|
|
wined3d_context_vk_reference_query(context_vk, query_vk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wined3d_query_vk_end(struct wined3d_query_vk *query_vk,
|
|
|
|
struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
|
|
|
|
{
|
|
|
|
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
|
|
|
|
struct wined3d_query_pool_vk *pool_vk;
|
|
|
|
size_t idx;
|
|
|
|
|
|
|
|
pool_vk = query_vk->pool_idx.pool_vk;
|
|
|
|
idx = query_vk->pool_idx.idx;
|
|
|
|
|
2020-10-07 14:57:13 +02:00
|
|
|
if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
|
|
|
|
&& query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
|
|
|
|
VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool,
|
|
|
|
idx, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
|
|
|
|
else
|
|
|
|
VK_CALL(vkCmdEndQuery(vk_command_buffer, pool_vk->vk_query_pool, idx));
|
2020-05-26 18:10:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
|
|
|
|
{
|
|
|
|
VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
|
|
|
|
|
|
|
|
wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
|
2021-07-28 13:42:13 +02:00
|
|
|
query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
|
2020-05-26 18:10:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
|
|
|
|
{
|
|
|
|
VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
|
|
|
|
|
|
|
|
wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
|
|
|
|
wined3d_context_vk_add_pending_query(context_vk, query_vk);
|
|
|
|
query_vk->pool_idx.pool_vk = NULL;
|
2021-07-28 13:42:13 +02:00
|
|
|
query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE;
|
2020-05-26 18:10:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
|
|
|
|
{
|
|
|
|
struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
|
|
|
|
struct wined3d_context_vk *context_vk;
|
|
|
|
|
|
|
|
context_vk = wined3d_context_vk(context_acquire(query->device, NULL, 0));
|
|
|
|
|
|
|
|
if (flags & WINED3DGETDATA_FLUSH)
|
|
|
|
wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
|
|
|
|
if (query_vk->command_buffer_id == context_vk->current_command_buffer.id)
|
|
|
|
goto unavailable;
|
|
|
|
|
|
|
|
if (query_vk->pending_count)
|
|
|
|
wined3d_context_vk_accumulate_pending_queries(context_vk);
|
|
|
|
if (query_vk->pending_count)
|
|
|
|
goto unavailable;
|
|
|
|
|
2020-09-23 15:51:59 +02:00
|
|
|
/* If the query was suspended, and then ended before it was resumed,
|
|
|
|
* there's no data to accumulate here. */
|
|
|
|
if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, context_vk, &query_vk->pool_idx))
|
2020-05-26 18:10:11 +02:00
|
|
|
goto unavailable;
|
|
|
|
|
2021-06-28 17:52:41 +02:00
|
|
|
query_vk->pool_idx.pool_vk = NULL;
|
2020-05-26 18:10:11 +02:00
|
|
|
context_release(&context_vk->c);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
unavailable:
|
|
|
|
context_release(&context_vk->c);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags)
|
|
|
|
{
|
|
|
|
struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
|
|
|
|
struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
|
|
|
|
struct wined3d_context_vk *context_vk;
|
|
|
|
VkCommandBuffer vk_command_buffer;
|
|
|
|
bool poll = false;
|
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
|
|
|
if (flags & WINED3DISSUE_BEGIN)
|
|
|
|
{
|
|
|
|
context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
|
|
|
|
|
|
|
|
if (query_vk->pending_count)
|
|
|
|
wined3d_context_vk_remove_pending_queries(context_vk, query_vk);
|
|
|
|
memset((void *)query->data, 0, query->data_size);
|
|
|
|
vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
|
2021-07-28 13:42:13 +02:00
|
|
|
if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
|
2021-03-11 13:54:34 +01:00
|
|
|
{
|
2021-07-28 13:42:13 +02:00
|
|
|
if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
|
|
|
|
wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
|
2021-03-11 13:54:34 +01:00
|
|
|
list_remove(&query_vk->entry);
|
|
|
|
}
|
2021-06-28 17:52:41 +02:00
|
|
|
if (query_vk->pool_idx.pool_vk)
|
|
|
|
wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
|
|
|
|
query_vk->pool_idx.idx, context_vk);
|
2020-05-26 18:10:11 +02:00
|
|
|
|
2021-07-28 13:42:13 +02:00
|
|
|
if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
|
|
|
|
{
|
|
|
|
ERR("Failed to allocate new query.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:50:00 +01:00
|
|
|
/* A query needs to either begin and end inside a single render pass
|
|
|
|
* or begin and end outside of a render pass. Occlusion queries, if
|
|
|
|
* issued outside of a render pass, are queued up and only begun when
|
|
|
|
* a render pass is started, to avoid interrupting the render pass
|
|
|
|
* when the query ends. */
|
2021-07-28 13:42:13 +02:00
|
|
|
if (context_vk->vk_render_pass)
|
|
|
|
{
|
|
|
|
wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
|
|
|
|
list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
|
|
|
|
query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE | WINED3D_QUERY_VK_FLAG_RENDER_PASS;
|
|
|
|
}
|
|
|
|
else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
|
|
|
|
{
|
|
|
|
list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
|
|
|
|
query_vk->flags |= WINED3D_QUERY_VK_FLAG_RENDER_PASS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
|
|
|
|
list_add_head(&context_vk->active_queries, &query_vk->entry);
|
|
|
|
query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
query_vk->flags |= WINED3D_QUERY_VK_FLAG_STARTED;
|
2020-05-26 18:10:11 +02:00
|
|
|
context_release(&context_vk->c);
|
|
|
|
}
|
2021-07-28 13:42:13 +02:00
|
|
|
if (flags & WINED3DISSUE_END && query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
|
2020-05-26 18:10:11 +02:00
|
|
|
{
|
|
|
|
context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
|
|
|
|
|
|
|
|
/* If the query was already ended because the command buffer was
|
2021-07-28 13:42:13 +02:00
|
|
|
* flushed or the render pass ended, we don't need to end it here. */
|
|
|
|
if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
|
|
|
|
{
|
|
|
|
vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
|
|
|
|
if (!(query_vk->flags & WINED3D_QUERY_VK_FLAG_RENDER_PASS))
|
|
|
|
wined3d_context_vk_end_current_render_pass(context_vk);
|
2020-05-26 18:10:11 +02:00
|
|
|
wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
|
2021-07-28 13:42:13 +02:00
|
|
|
}
|
|
|
|
else if (query_vk->pool_idx.pool_vk)
|
|
|
|
{
|
|
|
|
/* It was queued, but never activated. */
|
|
|
|
wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
|
|
|
|
query_vk->pool_idx.idx, context_vk);
|
|
|
|
query_vk->pool_idx.pool_vk = NULL;
|
|
|
|
}
|
2020-05-26 18:10:11 +02:00
|
|
|
list_remove(&query_vk->entry);
|
2021-07-28 13:42:13 +02:00
|
|
|
query_vk->flags = 0;
|
2020-05-26 18:10:11 +02:00
|
|
|
poll = true;
|
|
|
|
|
|
|
|
context_release(&context_vk->c);
|
|
|
|
}
|
|
|
|
|
|
|
|
return poll;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wined3d_query_vk_destroy(struct wined3d_query *query)
|
|
|
|
{
|
|
|
|
struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
|
|
|
|
struct wined3d_context_vk *context_vk;
|
|
|
|
|
2021-09-28 20:05:14 +02:00
|
|
|
if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
|
|
|
|
list_remove(&query_vk->entry);
|
2020-05-26 18:10:11 +02:00
|
|
|
if (query_vk->pending_count)
|
|
|
|
{
|
|
|
|
context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0));
|
|
|
|
wined3d_context_vk_remove_pending_queries(context_vk, query_vk);
|
|
|
|
context_release(&context_vk->c);
|
|
|
|
}
|
|
|
|
heap_free(query_vk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wined3d_query_ops wined3d_query_vk_ops =
|
|
|
|
{
|
|
|
|
.query_poll = wined3d_query_vk_poll,
|
|
|
|
.query_issue = wined3d_query_vk_issue,
|
|
|
|
.query_destroy = wined3d_query_vk_destroy,
|
|
|
|
};
|
|
|
|
|
2020-05-27 17:55:33 +02:00
|
|
|
static BOOL wined3d_query_event_vk_poll(struct wined3d_query *query, uint32_t flags)
|
|
|
|
{
|
|
|
|
struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
|
|
|
|
struct wined3d_context_vk *context_vk;
|
|
|
|
BOOL *signalled;
|
|
|
|
|
|
|
|
context_vk = wined3d_context_vk(context_acquire(query->device, NULL, 0));
|
|
|
|
|
|
|
|
signalled = (BOOL *)query->data;
|
|
|
|
if (flags & WINED3DGETDATA_FLUSH)
|
|
|
|
wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
|
|
|
|
if (query_vk->command_buffer_id == context_vk->current_command_buffer.id)
|
|
|
|
{
|
|
|
|
context_release(&context_vk->c);
|
|
|
|
return *signalled = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
|
|
|
|
wined3d_context_vk_poll_command_buffers(context_vk);
|
|
|
|
*signalled = context_vk->completed_command_buffer_id >= query_vk->command_buffer_id;
|
|
|
|
|
|
|
|
context_release(&context_vk->c);
|
|
|
|
|
|
|
|
return *signalled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL wined3d_query_event_vk_issue(struct wined3d_query *query, uint32_t flags)
|
|
|
|
{
|
|
|
|
struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
|
|
|
|
struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
|
|
|
|
struct wined3d_context_vk *context_vk;
|
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
|
|
|
if (flags & WINED3DISSUE_END)
|
|
|
|
{
|
|
|
|
context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
|
|
|
|
wined3d_context_vk_reference_query(context_vk, query_vk);
|
2020-12-15 14:14:21 +01:00
|
|
|
/* Because we don't actually submit any commands to the command buffer
|
|
|
|
* for event queries, the context's current command buffer may still
|
|
|
|
* be empty, and we should wait on the preceding command buffer
|
|
|
|
* instead. That's not merely an optimisation; if the command buffer
|
|
|
|
* referenced by the query is still empty by the time the application
|
|
|
|
* waits for it, that wait will never complete. */
|
|
|
|
if (!context_vk->current_command_buffer.vk_command_buffer)
|
|
|
|
--query_vk->command_buffer_id;
|
2020-05-27 17:55:33 +02:00
|
|
|
context_release(&context_vk->c);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wined3d_query_ops wined3d_query_event_vk_ops =
|
|
|
|
{
|
|
|
|
.query_poll = wined3d_query_event_vk_poll,
|
|
|
|
.query_issue = wined3d_query_event_vk_issue,
|
|
|
|
.query_destroy = wined3d_query_vk_destroy,
|
|
|
|
};
|
|
|
|
|
2020-05-26 18:10:12 +02:00
|
|
|
static BOOL wined3d_query_timestamp_vk_issue(struct wined3d_query *query, uint32_t flags)
|
|
|
|
{
|
|
|
|
struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
|
|
|
|
struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
|
|
|
|
const struct wined3d_vk_info *vk_info;
|
|
|
|
struct wined3d_context_vk *context_vk;
|
|
|
|
VkCommandBuffer command_buffer;
|
|
|
|
|
|
|
|
TRACE("query %p, flags %#x.\n", query, flags);
|
|
|
|
|
|
|
|
if (flags & WINED3DISSUE_BEGIN)
|
|
|
|
TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
|
|
|
|
|
|
|
|
if (flags & WINED3DISSUE_END)
|
|
|
|
{
|
|
|
|
context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
|
|
|
|
vk_info = context_vk->vk_info;
|
|
|
|
|
|
|
|
command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
|
2021-08-04 17:25:01 +02:00
|
|
|
if (query_vk->pool_idx.pool_vk)
|
|
|
|
wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
|
|
|
|
if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
|
|
|
|
{
|
|
|
|
ERR("Failed to allocate new query.\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2020-05-26 18:10:12 +02:00
|
|
|
VK_CALL(vkCmdWriteTimestamp(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
|
|
|
query_vk->pool_idx.pool_vk->vk_query_pool, query_vk->pool_idx.idx));
|
|
|
|
wined3d_context_vk_reference_query(context_vk, query_vk);
|
|
|
|
|
|
|
|
context_release(&context_vk->c);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops =
|
|
|
|
{
|
|
|
|
.query_poll = wined3d_query_vk_poll,
|
|
|
|
.query_issue = wined3d_query_timestamp_vk_issue,
|
|
|
|
.query_destroy = wined3d_query_vk_destroy,
|
|
|
|
};
|
|
|
|
|
2020-05-26 18:10:13 +02:00
|
|
|
static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops =
|
|
|
|
{
|
|
|
|
.query_poll = wined3d_timestamp_disjoint_query_ops_poll,
|
|
|
|
.query_issue = wined3d_timestamp_disjoint_query_ops_issue,
|
|
|
|
.query_destroy = wined3d_query_vk_destroy,
|
|
|
|
};
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_query_type type,
|
|
|
|
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
|
|
|
|
{
|
2020-05-26 18:10:13 +02:00
|
|
|
struct wined3d_query_data_timestamp_disjoint *disjoint_data;
|
2020-05-26 18:10:12 +02:00
|
|
|
const struct wined3d_query_ops *ops = &wined3d_query_vk_ops;
|
2020-05-26 18:10:11 +02:00
|
|
|
struct wined3d_query_vk *query_vk;
|
|
|
|
unsigned int data_size;
|
2020-05-26 18:10:13 +02:00
|
|
|
void *data;
|
2020-05-26 18:10:11 +02:00
|
|
|
|
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
2020-05-27 17:55:33 +02:00
|
|
|
case WINED3D_QUERY_TYPE_EVENT:
|
|
|
|
ops = &wined3d_query_event_vk_ops;
|
|
|
|
data_size = sizeof(BOOL);
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
case WINED3D_QUERY_TYPE_OCCLUSION:
|
|
|
|
data_size = sizeof(uint64_t);
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:12 +02:00
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP:
|
|
|
|
if (!wined3d_device_vk(device)->timestamp_bits)
|
|
|
|
{
|
|
|
|
WARN("Timestamp queries not supported.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
ops = &wined3d_query_timestamp_vk_ops;
|
|
|
|
data_size = sizeof(uint64_t);
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:13 +02:00
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
|
|
|
|
if (!wined3d_device_vk(device)->timestamp_bits)
|
|
|
|
{
|
|
|
|
WARN("Timestamp queries not supported.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
ops = &wined3d_query_timestamp_disjoint_vk_ops;
|
|
|
|
data_size = sizeof(struct wined3d_query_data_timestamp_disjoint);
|
|
|
|
break;
|
|
|
|
|
2020-05-27 17:55:34 +02:00
|
|
|
case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
|
|
|
|
data_size = sizeof(struct wined3d_query_data_pipeline_statistics);
|
|
|
|
break;
|
|
|
|
|
2020-10-07 14:57:13 +02:00
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
|
|
|
|
case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
|
|
|
|
if (!wined3d_adapter_vk(device->adapter)->vk_info.supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK])
|
|
|
|
{
|
|
|
|
WARN("Stream output queries not supported.\n");
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
data_size = sizeof(struct wined3d_query_data_so_statistics);
|
|
|
|
break;
|
|
|
|
|
2020-05-26 18:10:11 +02:00
|
|
|
default:
|
|
|
|
FIXME("Unhandled query type %#x.\n", type);
|
|
|
|
return WINED3DERR_NOTAVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(query_vk = heap_alloc_zero(sizeof(*query_vk) + data_size)))
|
|
|
|
return E_OUTOFMEMORY;
|
2020-05-26 18:10:13 +02:00
|
|
|
data = query_vk + 1;
|
2020-05-26 18:10:11 +02:00
|
|
|
|
2020-05-26 18:10:13 +02:00
|
|
|
wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops);
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case WINED3D_QUERY_TYPE_OCCLUSION:
|
|
|
|
query_vk->control_flags = VK_QUERY_CONTROL_PRECISE_BIT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
|
|
|
|
disjoint_data = data;
|
|
|
|
disjoint_data->frequency = 1000000000 / wined3d_adapter_vk(device->adapter)->device_limits.timestampPeriod;
|
|
|
|
disjoint_data->disjoint = FALSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2020-05-26 18:10:11 +02:00
|
|
|
|
|
|
|
TRACE("Created query %p.\n", query_vk);
|
|
|
|
*query = &query_vk->q;
|
|
|
|
|
|
|
|
return WINED3D_OK;
|
|
|
|
}
|
|
|
|
|
2019-08-15 11:50:00 +02:00
|
|
|
HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
|
|
|
|
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
|
|
|
|
{
|
|
|
|
TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
|
|
|
|
device, type, parent, parent_ops, query);
|
|
|
|
|
|
|
|
return device->adapter->adapter_ops->adapter_create_query(device, type, parent, parent_ops, query);
|
|
|
|
}
|