[PATCH 5/7] wined3d: Add support for D3DQUERY_TIMESTAMP* queries.

Adam Martinson amartinson at codeweavers.com
Mon May 2 11:52:37 CDT 2011


---
 dlls/d3d9/query.c              |   13 +-
 dlls/wined3d/context.c         |   81 +++++++
 dlls/wined3d/query.c           |  499 +++++++++++++++++++++++++++++++++++++++-
 dlls/wined3d/wined3d_private.h |   17 ++
 4 files changed, 594 insertions(+), 16 deletions(-)

diff --git a/dlls/d3d9/query.c b/dlls/d3d9/query.c
index 5e1bf12..3a21b5a 100644
--- a/dlls/d3d9/query.c
+++ b/dlls/d3d9/query.c
@@ -95,26 +95,31 @@ static HRESULT WINAPI IDirect3DQuery9Impl_GetDevice(IDirect3DQuery9 *iface,
 static D3DQUERYTYPE WINAPI IDirect3DQuery9Impl_GetType(IDirect3DQuery9 *iface)
 {
     IDirect3DQuery9Impl *This = impl_from_IDirect3DQuery9(iface);
-    HRESULT hr;
+    D3DQUERYTYPE ret;
 
     TRACE("iface %p.\n", iface);
 
     wined3d_mutex_lock();
-    hr = wined3d_query_get_type(This->wineD3DQuery);
+    ret = wined3d_query_get_type(This->wineD3DQuery);
     wined3d_mutex_unlock();
 
-    return hr;
+    return ret;
 }
 
 static DWORD WINAPI IDirect3DQuery9Impl_GetDataSize(IDirect3DQuery9 *iface)
 {
     IDirect3DQuery9Impl *This = impl_from_IDirect3DQuery9(iface);
     DWORD ret;
+    D3DQUERYTYPE type;
 
     TRACE("iface %p.\n", iface);
 
     wined3d_mutex_lock();
-    ret = wined3d_query_get_data_size(This->wineD3DQuery);
+    type = wined3d_query_get_type(This->wineD3DQuery);
+    if (type == D3DQUERYTYPE_TIMESTAMPDISJOINT)
+        ret = sizeof(BOOL);
+    else
+        ret = wined3d_query_get_data_size(This->wineD3DQuery);
     wined3d_mutex_unlock();
 
     return ret;
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 54fdafc..4d18b16 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -671,6 +671,67 @@ void context_free_event_query(struct wined3d_event_query *query)
     context->free_event_queries[context->free_event_query_count++] = query->object;
 }
 
+/* Context activation is done by the caller.
+ * Only called when GL_ARB_timer_query is supported. */
+void context_alloc_timestamp_query(struct wined3d_context *context, struct wined3d_timestamp_query *query)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    int i, n_new;
+
+    for (i = 0; i < query->n_ids && i < context->free_timestamp_query_count; ++i)
+    {
+        query->ids[i] = context->free_timestamp_queries[--context->free_timestamp_query_count];
+    }
+
+    if ((n_new = query->n_ids - i))
+    {
+
+        ENTER_GL();
+        GL_EXTCALL(glGenQueriesARB(n_new, &query->ids[i]));
+        checkGLcall("glGenQueriesARB");
+        LEAVE_GL();
+
+#ifndef WINE_NO_TRACE_MSGS
+        for (; i < query->n_ids; ++i)
+            TRACE("Allocated timestamp query %u in context %p.\n", query->ids[i], context);
+#endif
+    }
+
+    query->context = context;
+    list_add_head(&context->timestamp_queries, &query->entry);
+}
+
+/* Context activation is done by the caller.
+ * Only called when GL_ARB_timer_query is supported. */
+void context_free_timestamp_query(struct wined3d_timestamp_query *query)
+{
+    struct wined3d_context *context = query->context;
+    int i;
+
+    list_remove(&query->entry);
+    query->context = NULL;
+
+    if (context->free_timestamp_query_count + query->n_ids >= context->free_timestamp_query_size)
+    {
+        UINT new_size = context->free_timestamp_query_size << 1;
+        GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_timestamp_queries,
+                new_size * sizeof(*context->free_timestamp_queries));
+
+        if (!new_data)
+        {
+            for (i = 0; i < query->n_ids; ++i)
+                ERR("Failed to grow free list, leaking query %u in context %p.\n", query->ids[i], context);
+            return;
+        }
+
+        context->free_timestamp_query_size = new_size;
+        context->free_timestamp_queries = new_data;
+    }
+
+    for (i = 0; i < query->n_ids; ++i)
+        context->free_timestamp_queries[context->free_timestamp_query_count++] = query->ids[i];
+}
+
 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
 
 static void context_enum_surface_fbo_entries(IWineD3DDeviceImpl *device,
@@ -945,6 +1006,7 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct wined3d_occlusion_query *occlusion_query;
     struct wined3d_event_query *event_query;
+    struct wined3d_timestamp_query *timestamp_query;
     struct fbo_entry *entry, *entry2;
     HGLRC restore_ctx;
     HDC restore_dc;
@@ -981,6 +1043,13 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
         event_query->context = NULL;
     }
 
+    LIST_FOR_EACH_ENTRY(timestamp_query, &context->timestamp_queries, struct wined3d_timestamp_query, entry)
+    {
+        if (context->valid && gl_info->supported[ARB_TIMER_QUERY])
+            GL_EXTCALL(glDeleteQueriesARB(timestamp_query->n_ids, timestamp_query->ids));
+        timestamp_query->context = NULL;
+    }
+
     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
     {
         if (!context->valid) entry->id = 0;
@@ -1008,6 +1077,9 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
         if (gl_info->supported[ARB_OCCLUSION_QUERY])
             GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
 
+        if (gl_info->supported[ARB_TIMER_QUERY])
+            GL_EXTCALL(glDeleteQueriesARB(context->free_timestamp_query_count, context->free_timestamp_queries));
+
         if (gl_info->supported[ARB_SYNC])
         {
             for (i = 0; i < context->free_event_query_count; ++i)
@@ -1037,6 +1109,7 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
 
     HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
     HeapFree(GetProcessHeap(), 0, context->free_event_queries);
+    HeapFree(GetProcessHeap(), 0, context->free_timestamp_queries);
 
     if (restore_ctx)
     {
@@ -1531,6 +1604,13 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
 
     list_init(&ret->event_queries);
 
+    ret->free_timestamp_query_size = 4;
+    ret->free_timestamp_queries = HeapAlloc(GetProcessHeap(), 0,
+            ret->free_timestamp_query_size * sizeof(*ret->free_timestamp_queries));
+    if (!ret->free_timestamp_queries) goto out;
+
+    list_init(&ret->timestamp_queries);
+
     TRACE("Successfully created new context %p\n", ret);
 
     list_init(&ret->fbo_list);
@@ -1680,6 +1760,7 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
 out:
     HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
     HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
+    HeapFree(GetProcessHeap(), 0, ret->free_timestamp_queries);
     HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
     HeapFree(GetProcessHeap(), 0, ret->blit_targets);
     HeapFree(GetProcessHeap(), 0, ret->pshader_const_dirty);
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index 1751609..d513f15 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -4,6 +4,7 @@
  * Copyright 2005 Oliver Stieber
  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
  * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
+ * Copyright 2011 Adam Martinson for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,6 +27,29 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 
+#define ARB_TIMER_QUERY_FREQ 1000000000 /* nanoseconds */
+
+struct _wined3d_timestamp_query
+{
+    struct list             entry;
+    struct wined3d_context *context;
+    int                     n_ids;
+    GLuint                  ids[1];
+};
+
+struct _wined3d_timestampdisjoint_query
+{
+    struct list             entry;
+    struct wined3d_context *context;
+    int                     n_ids;
+    GLuint                  ids[3];
+};
+
+typedef struct D3D10_QUERY_DATA_TIMESTAMP_DISJOINT {
+    UINT64 Frequency;
+    BOOL Disjoint;
+} D3D10_QUERY_DATA_TIMESTAMP_DISJOINT;
+
 BOOL wined3d_event_query_supported(const struct wined3d_gl_info *gl_info)
 {
     return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
@@ -251,17 +275,36 @@ ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
          * deleting the query will obviously leak it, but that's still better
          * than potentially deleting a different query with the same id in this
          * context, and (still) leaking the actual query. */
-        if (query->type == WINED3DQUERYTYPE_EVENT)
+        switch (query->type)
         {
-            struct wined3d_event_query *event_query = query->extendedData;
-            if (event_query) wined3d_event_query_destroy(event_query);
-        }
-        else if (query->type == WINED3DQUERYTYPE_OCCLUSION)
-        {
-            struct wined3d_occlusion_query *oq = query->extendedData;
+        case WINED3DQUERYTYPE_EVENT:
+            {
+                struct wined3d_event_query *event_query = query->extendedData;
+                if (event_query) wined3d_event_query_destroy(event_query);
+            }
+            break;
+
+        case WINED3DQUERYTYPE_OCCLUSION:
+            {
+                struct wined3d_occlusion_query *oq = query->extendedData;
 
-            if (oq->context) context_free_occlusion_query(oq);
-            HeapFree(GetProcessHeap(), 0, query->extendedData);
+                if (oq->context) context_free_occlusion_query(oq);
+                HeapFree(GetProcessHeap(), 0, query->extendedData);
+            }
+            break;
+
+        case WINED3DQUERYTYPE_TIMESTAMP:
+        case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
+            {
+                struct wined3d_timestamp_query *tsq = query->extendedData;
+
+                if (tsq->context) context_free_timestamp_query(tsq);
+                HeapFree(GetProcessHeap(), 0, query->extendedData);
+            }
+            break;
+
+        default:
+            break;
         }
 
         HeapFree(GetProcessHeap(), 0, query);
@@ -412,6 +455,227 @@ static HRESULT wined3d_event_query_ops_get_data(struct wined3d_query *query,
     return S_OK;
 }
 
+/* Only called when GL_ARB_timer_query is supported. */
+static HRESULT wined3d_timestamp_query_ops_get_data(struct wined3d_query *query,
+                                                    void *pData, DWORD dwSize, DWORD flags)
+{
+    const struct wined3d_gl_info *gl_info = &query->device->adapter->gl_info;
+    struct wined3d_timestamp_query *This = query->extendedData;
+    struct wined3d_context *context;
+    GLuint available;
+    UINT64 *data = pData;
+    HRESULT res;
+
+    TRACE("(%p) : type D3DQUERY_TIMESTAMP, pData %p, dwSize %#x, flags %#x.\n", query, pData, dwSize, flags);
+
+    if (dwSize != sizeof(UINT64))
+        data = 0;
+
+    if (!This->context)
+        query->state = QUERY_CREATED;
+
+    if (query->state == QUERY_CREATED)
+    {
+        /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
+        TRACE("Query wasn't yet started, returning S_OK\n");
+        if (data) *data = 0;
+        return S_OK;
+    }
+
+    if (query->state == QUERY_BUILDING)
+    {
+        /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
+        TRACE("Query is building, returning S_FALSE\n");
+        return S_FALSE;
+    }
+
+    if (This->context->tid != GetCurrentThreadId())
+    {
+        FIXME("%p Wrong thread, returning 0.\n", query);
+        if (data) *data = 0;
+        return S_OK;
+    }
+
+    context = context_acquire(query->device, This->context->current_rt);
+
+    ENTER_GL();
+
+    GL_EXTCALL(glGetQueryObjectuivARB(This->ids[0], GL_QUERY_RESULT_AVAILABLE_ARB, &available));
+    checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
+    TRACE("available %#x.\n", available);
+
+    if (available)
+    {
+        if (data)
+        {
+            GL_EXTCALL(glGetQueryObjectui64v(This->ids[0], GL_QUERY_RESULT_ARB, data));
+            checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
+            TRACE("Returning 0x%08x%08x.\n", (UINT)((*data) >> 32), (UINT)((*data) & 0xFFFFFFFF));
+        }
+        res = S_OK;
+    }
+    else
+    {
+        res = S_FALSE;
+    }
+
+    LEAVE_GL();
+
+    context_release(context);
+
+    return res;
+}
+
+/* Only called when GL_ARB_timer_query is supported. */
+static HRESULT wined3d_timestampdisjoint_query_ops_get_data(struct wined3d_query *query,
+                                                            void *pData, DWORD dwSize, DWORD flags)
+{
+    const struct wined3d_gl_info *gl_info = &query->device->adapter->gl_info;
+    struct wined3d_timestamp_query *This = query->extendedData;
+    struct wined3d_context *context;
+    GLuint available;
+    UINT64 time_start, time_end, time_elapsed;
+    HRESULT res;
+
+    TRACE("(%p) : type D3DQUERY_TIMESTAMPDISJOINT, pData %p, dwSize %#x, flags %#x.\n", query, pData, dwSize, flags);
+
+    if (!This->context)
+        query->state = QUERY_CREATED;
+
+    if (query->state == QUERY_CREATED)
+    {
+        /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
+        TRACE("Query wasn't yet started, returning S_OK\n");
+        if (pData)
+            switch (dwSize)
+            {
+            case 0:
+                break;
+
+            case sizeof(BOOL): /* D3D9- */
+                *((BOOL*)pData) = TRUE;
+                break;
+
+            case sizeof(D3D10_QUERY_DATA_TIMESTAMP_DISJOINT): /* D3D10+ */
+                ((D3D10_QUERY_DATA_TIMESTAMP_DISJOINT*)pData)->Disjoint = TRUE;
+                ((D3D10_QUERY_DATA_TIMESTAMP_DISJOINT*)pData)->Frequency = 0;
+                break;
+
+            default:
+                FIXME("invalid dwSize %#x\n", dwSize);
+            }
+
+        return S_OK;
+    }
+
+    if (query->state == QUERY_BUILDING)
+    {
+        /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
+        TRACE("Query is building, returning S_FALSE\n");
+        return S_FALSE;
+    }
+
+    if (This->context->tid != GetCurrentThreadId())
+    {
+        FIXME("%p Wrong thread, returning 0.\n", query);
+        if (pData)
+            switch (dwSize)
+            {
+            case 0:
+                break;
+
+            case sizeof(BOOL): /* D3D9- */
+                *((BOOL*)pData) = TRUE;
+                break;
+
+            case sizeof(D3D10_QUERY_DATA_TIMESTAMP_DISJOINT): /* D3D10+ */
+                ((D3D10_QUERY_DATA_TIMESTAMP_DISJOINT*)pData)->Disjoint = TRUE;
+                ((D3D10_QUERY_DATA_TIMESTAMP_DISJOINT*)pData)->Frequency = 0;
+                break;
+
+            default:
+                FIXME("invalid dwSize %#x\n", dwSize);
+            }
+        return S_OK;
+    }
+
+    context = context_acquire(query->device, This->context->current_rt);
+
+    ENTER_GL();
+
+    GL_EXTCALL(glGetQueryObjectuivARB(This->ids[2], GL_QUERY_RESULT_AVAILABLE_ARB, &available));
+    checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
+    TRACE("available %#x.\n", available);
+
+    if (available)
+    {
+        if (pData)
+        {
+            BOOL disjoint;
+
+            GL_EXTCALL(glGetQueryObjectui64v(This->ids[0], GL_QUERY_RESULT_ARB, &time_start));
+            checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
+            GL_EXTCALL(glGetQueryObjectui64v(This->ids[1], GL_QUERY_RESULT_ARB, &time_end));
+            checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
+            GL_EXTCALL(glGetQueryObjectui64v(This->ids[2], GL_QUERY_RESULT_ARB, &time_elapsed));
+            checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
+
+            disjoint = ((time_start >= time_end) || ((time_end - time_start) > time_elapsed));
+
+            switch (dwSize)
+            {
+            case 0:
+                break;
+
+            case sizeof(BOOL): /* D3D9- */
+                *((BOOL*)pData) = disjoint;
+                break;
+
+            case sizeof(D3D10_QUERY_DATA_TIMESTAMP_DISJOINT): /* D3D10+ */
+                ((D3D10_QUERY_DATA_TIMESTAMP_DISJOINT*)pData)->Disjoint = disjoint;
+                ((D3D10_QUERY_DATA_TIMESTAMP_DISJOINT*)pData)->Frequency = ARB_TIMER_QUERY_FREQ;
+                break;
+
+            default:
+                FIXME("invalid dwSize %#x\n", dwSize);
+            }
+        }
+        res = S_OK;
+    }
+    else
+    {
+        res = S_FALSE;
+    }
+
+    LEAVE_GL();
+
+    context_release(context);
+
+    return res;
+}
+
+/* Only called when GL_ARB_timer_query is supported. */
+static HRESULT wined3d_timestampfreq_query_ops_get_data(struct wined3d_query *query,
+                                                        void *pData, DWORD dwSize, DWORD flags)
+{
+    UINT64 *data = pData;
+
+    TRACE("(%p) : type D3DQUERY_TIMESTAMPFREQ, pData %p, dwSize %#x, flags %#x.\n", query, pData, dwSize, flags);
+
+    if (query->state != QUERY_SIGNALLED)
+        return S_FALSE;
+
+    if (dwSize != sizeof(UINT64))
+        data = NULL;
+
+    if (data)
+    {
+        *data = ARB_TIMER_QUERY_FREQ;
+    }
+
+    return S_OK;
+}
+
 WINED3DQUERYTYPE CDECL wined3d_query_get_type(const struct wined3d_query *query)
 {
     TRACE("query %p.\n", query);
@@ -535,6 +799,132 @@ static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DW
     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
 }
 
+/* Only called when GL_ARB_timer_query is supported. */
+static HRESULT wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    const struct wined3d_gl_info *gl_info = &query->device->adapter->gl_info;
+    struct wined3d_timestamp_query *This = query->extendedData;
+    struct wined3d_context *context;
+
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    /* MSDN: D3DISSUE_BEGIN not supported */
+
+    if (!This->context)
+    {
+        context = context_acquire(query->device, NULL);
+        context_alloc_timestamp_query(context, This);
+    }
+    else
+    {
+        context = context_acquire(query->device, This->context->current_rt);
+    }
+
+    ENTER_GL();
+    GL_EXTCALL(glQueryCounter(This->ids[0], GL_TIMESTAMP_ARB));
+    checkGLcall("glQueryCounter(GL_TIMESTAMP)");
+    LEAVE_GL();
+
+    context_release(context);
+
+    query->state = QUERY_SIGNALLED;
+
+    return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
+}
+
+/* Only called when GL_ARB_timer_query is supported. */
+static HRESULT wined3d_timestampdisjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    const struct wined3d_gl_info *gl_info = &query->device->adapter->gl_info;
+    struct wined3d_timestamp_query *This = query->extendedData;
+    struct wined3d_context *context;
+
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    /* This is allowed according to msdn and our tests. Reset the query and restart */
+    if (flags & WINED3DISSUE_BEGIN)
+    {
+        if (query->state == QUERY_BUILDING)
+        {
+            if (This->context->tid != GetCurrentThreadId())
+            {
+                FIXME("Wrong thread, can't restart query.\n");
+
+                context_free_timestamp_query(This);
+                context = context_acquire(query->device, NULL);
+                context_alloc_timestamp_query(context, This);
+            }
+            else
+            {
+                context = context_acquire(query->device, This->context->current_rt);
+
+                ENTER_GL();
+                GL_EXTCALL(glEndQueryARB(GL_TIME_ELAPSED_ARB));
+                checkGLcall("glEndQuery(GL_TIME_ELAPSED)");
+                LEAVE_GL();
+            }
+        }
+        else
+        {
+            if (This->context) context_free_timestamp_query(This);
+            context = context_acquire(query->device, NULL);
+            context_alloc_timestamp_query(context, This);
+        }
+
+        ENTER_GL();
+        GL_EXTCALL(glBeginQueryARB(GL_TIME_ELAPSED_ARB, This->ids[2]));
+        checkGLcall("glBeginQuery(GL_TIME_ELAPSED)");
+        GL_EXTCALL(glQueryCounter(This->ids[0], GL_TIMESTAMP_ARB));
+        checkGLcall("glQueryCounter(GL_TIMESTAMP)");
+        LEAVE_GL();
+
+        context_release(context);
+        query->state = QUERY_BUILDING;
+    }
+    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
+         */
+        if (query->state == QUERY_BUILDING)
+        {
+            if (This->context->tid != GetCurrentThreadId())
+            {
+                FIXME("Wrong thread, can't end query.\n");
+            }
+            else
+            {
+                context = context_acquire(query->device, This->context->current_rt);
+
+                ENTER_GL();
+                GL_EXTCALL(glQueryCounter(This->ids[1], GL_TIMESTAMP_ARB));
+                checkGLcall("glQueryCounter(GL_TIMESTAMP)");
+                GL_EXTCALL(glEndQueryARB(GL_TIME_ELAPSED_ARB));
+                checkGLcall("glEndQuery(GL_TIME_ELAPSED)");
+                LEAVE_GL();
+
+                context_release(context);
+            }
+        }
+
+        query->state = QUERY_SIGNALLED;
+    }
+
+    return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
+}
+
+/* Only called when GL_ARB_timer_query is supported. */
+static HRESULT wined3d_timestampfreq_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    /* WINED3DISSUE_BEGIN not supported */
+
+    query->state = QUERY_SIGNALLED;
+    return WINED3D_OK;
+}
+
 static const struct wined3d_query_ops event_query_ops =
 {
     wined3d_event_query_ops_get_data,
@@ -547,6 +937,24 @@ static const struct wined3d_query_ops occlusion_query_ops =
     wined3d_occlusion_query_ops_issue,
 };
 
+static const struct wined3d_query_ops timestamp_query_ops =
+{
+    wined3d_timestamp_query_ops_get_data,
+    wined3d_timestamp_query_ops_issue,
+};
+
+static const struct wined3d_query_ops timestampdisjoint_query_ops =
+{
+    wined3d_timestampdisjoint_query_ops_get_data,
+    wined3d_timestampdisjoint_query_ops_issue,
+};
+
+static const struct wined3d_query_ops timestampfreq_query_ops =
+{
+    wined3d_timestampfreq_query_ops_get_data,
+    wined3d_timestampfreq_query_ops_issue,
+};
+
 HRESULT query_init(struct wined3d_query *query, IWineD3DDeviceImpl *device, WINED3DQUERYTYPE type)
 {
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
@@ -591,12 +999,79 @@ HRESULT query_init(struct wined3d_query *query, IWineD3DDeviceImpl *device, WINE
             }
             break;
 
-        case WINED3DQUERYTYPE_VCACHE:
-        case WINED3DQUERYTYPE_RESOURCEMANAGER:
-        case WINED3DQUERYTYPE_VERTEXSTATS:
         case WINED3DQUERYTYPE_TIMESTAMP:
+            TRACE("Timestamp query.\n");
+            if (!gl_info->supported[ARB_TIMER_QUERY])
+            {
+                static BOOL warned = FALSE;
+                if (!warned)
+                {
+                    WARN("GL_ARB_timer_query not supported, returning WINED3DERR_NOTAVAILABLE\n");
+                    warned = TRUE;
+                }
+                return WINED3DERR_NOTAVAILABLE;
+            }
+
+            query->data_size = sizeof(UINT64);
+            query->query_ops = &timestamp_query_ops;
+            query->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct _wined3d_timestamp_query));
+            if (!query->extendedData)
+            {
+                ERR("Failed to allocate event query memory.\n");
+                return E_OUTOFMEMORY;
+            }
+            ((struct wined3d_timestamp_query *)query->extendedData)->n_ids = 1;
+            ((struct wined3d_timestamp_query *)query->extendedData)->context = NULL;
+
+            break;
+
         case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
+            TRACE("Timestampdisjoint query.\n");
+            if (!gl_info->supported[ARB_TIMER_QUERY])
+            {
+                static BOOL warned = FALSE;
+                if (!warned)
+                {
+                    WARN("GL_ARB_timer_query not supported, returning WINED3DERR_NOTAVAILABLE\n");
+                    warned = TRUE;
+                }
+                return WINED3DERR_NOTAVAILABLE;
+            }
+
+            query->data_size = sizeof(D3D10_QUERY_DATA_TIMESTAMP_DISJOINT);
+            query->query_ops = &timestampdisjoint_query_ops;
+            query->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct _wined3d_timestampdisjoint_query));
+            if (!query->extendedData)
+            {
+                ERR("Failed to allocate event query memory.\n");
+                return E_OUTOFMEMORY;
+            }
+            ((struct wined3d_timestamp_query *)query->extendedData)->n_ids = 3;
+            ((struct wined3d_timestamp_query *)query->extendedData)->context = NULL;
+
+            break;
+
         case WINED3DQUERYTYPE_TIMESTAMPFREQ:
+            TRACE("Timestamp Freqency query.\n");
+            if (!gl_info->supported[ARB_TIMER_QUERY])
+            {
+                static BOOL warned = FALSE;
+                if (!warned)
+                {
+                    WARN("GL_ARB_timer_query not supported, returning WINED3DERR_NOTAVAILABLE\n");
+                    warned = TRUE;
+                }
+                return WINED3DERR_NOTAVAILABLE;
+            }
+
+            query->data_size = sizeof(UINT64);
+            query->query_ops = &timestampfreq_query_ops;
+            query->extendedData = NULL;
+            break;
+
+        case WINED3DQUERYTYPE_VCACHE:
+        case WINED3DQUERYTYPE_RESOURCEMANAGER:
+        case WINED3DQUERYTYPE_VERTEXSTATS:
         case WINED3DQUERYTYPE_PIPELINETIMINGS:
         case WINED3DQUERYTYPE_INTERFACETIMINGS:
         case WINED3DQUERYTYPE_VERTEXTIMINGS:
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 419e1ff..e847c68 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1017,6 +1017,15 @@ struct wined3d_event_query
     struct wined3d_context *context;
 };
 
+struct wined3d_timestamp_query
+{
+    struct list             entry;
+    struct wined3d_context *context;
+    int                     n_ids;
+    GLuint                  ids[];
+};
+
+
 enum wined3d_event_query_result
 {
     WINED3D_EVENT_QUERY_OK,
@@ -1109,6 +1118,11 @@ struct wined3d_context
     UINT free_event_query_count;
     struct list event_queries;
 
+    GLuint *free_timestamp_queries;
+    UINT free_timestamp_query_size;
+    UINT free_timestamp_query_count;
+    struct list timestamp_queries;
+
     /* Extension emulation */
     GLint                   gl_fog_source;
     GLfloat                 fog_coord_value;
@@ -1206,6 +1220,8 @@ void context_alloc_event_query(struct wined3d_context *context,
         struct wined3d_event_query *query) DECLSPEC_HIDDEN;
 void context_alloc_occlusion_query(struct wined3d_context *context,
         struct wined3d_occlusion_query *query) DECLSPEC_HIDDEN;
+void context_alloc_timestamp_query(struct wined3d_context *context,
+        struct wined3d_timestamp_query *query) DECLSPEC_HIDDEN;
 void context_apply_blit_state(struct wined3d_context *context, IWineD3DDeviceImpl *device) DECLSPEC_HIDDEN;
 BOOL context_apply_clear_state(struct wined3d_context *context, IWineD3DDeviceImpl *device,
         UINT rt_count, struct wined3d_surface **rts, struct wined3d_surface *depth_stencil) DECLSPEC_HIDDEN;
@@ -1221,6 +1237,7 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain, stru
 void context_destroy(IWineD3DDeviceImpl *This, struct wined3d_context *context) DECLSPEC_HIDDEN;
 void context_free_event_query(struct wined3d_event_query *query) DECLSPEC_HIDDEN;
 void context_free_occlusion_query(struct wined3d_occlusion_query *query) DECLSPEC_HIDDEN;
+void context_free_timestamp_query(struct wined3d_timestamp_query *query) DECLSPEC_HIDDEN;
 struct wined3d_context *context_get_current(void) DECLSPEC_HIDDEN;
 DWORD context_get_tls_idx(void) DECLSPEC_HIDDEN;
 void context_release(struct wined3d_context *context) DECLSPEC_HIDDEN;
-- 
1.7.1


--------------070704090506030703020704--



More information about the wine-devel mailing list