af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * IWineD3DQuery implementation
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright 2005 Oliver Stieber
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
5112e32d7072e280613921c982a6672f2c859cf3vboxsync * Copyright 2009 Henri Verbeet for CodeWeavers.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This library is free software; you can redistribute it and/or
af062818b47340eef15700d2f0211576ba3506eevboxsync * modify it under the terms of the GNU Lesser General Public
af062818b47340eef15700d2f0211576ba3506eevboxsync * License as published by the Free Software Foundation; either
af062818b47340eef15700d2f0211576ba3506eevboxsync * version 2.1 of the License, or (at your option) any later version.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This library is distributed in the hope that it will be useful,
af062818b47340eef15700d2f0211576ba3506eevboxsync * but WITHOUT ANY WARRANTY; without even the implied warranty of
af062818b47340eef15700d2f0211576ba3506eevboxsync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * Lesser General Public License for more details.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * You should have received a copy of the GNU Lesser General Public
af062818b47340eef15700d2f0211576ba3506eevboxsync * License along with this library; if not, write to the Free Software
af062818b47340eef15700d2f0211576ba3506eevboxsync * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync/*
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * a choice of LGPL license versions is made available with the language indicating
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * that LGPLv2 or any later version may be used, or where a choice of which version
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * of the LGPL is applied is otherwise unspecified.
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync */
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "config.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "wined3d_private.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncWINE_DEFAULT_DEBUG_CHANNEL(d3d);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync#define GLINFO_LOCATION (*gl_info)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncBOOL wined3d_event_query_supported(const struct wined3d_gl_info *gl_info)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync{
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync}
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncvoid wined3d_event_query_destroy(struct wined3d_event_query *query)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync{
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (query->context) context_free_event_query(query);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync HeapFree(GetProcessHeap(), 0, query);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync}
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncenum wined3d_event_query_result wined3d_event_query_test(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync{
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync struct wined3d_context *context;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync const struct wined3d_gl_info *gl_info;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync enum wined3d_event_query_result ret;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync BOOL fence_result;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync TRACE("(%p) : device %p\n", query, device);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (query->context == NULL)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync TRACE("Query not started\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3D_EVENT_QUERY_NOT_STARTED;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync WARN("Event query tested from wrong thread\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3D_EVENT_QUERY_WRONG_THREAD;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync#endif
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context = context_acquire(device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync gl_info = context->gl_info;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ENTER_GL();
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (gl_info->supported[ARB_SYNC])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, 0));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glClientWaitSync");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync switch (gl_ret)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case GL_ALREADY_SIGNALED:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case GL_CONDITION_SATISFIED:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case GL_TIMEOUT_EXPIRED:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_WAITING;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case GL_WAIT_FAILED:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync default:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ERR("glClientWaitSync returned %#x.\n", gl_ret);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_ERROR;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else if (gl_info->supported[APPLE_FENCE])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync fence_result = GL_EXTCALL(glTestFenceAPPLE(query->object.id));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glTestFenceAPPLE");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else ret = WINED3D_EVENT_QUERY_WAITING;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else if (gl_info->supported[NV_FENCE])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync fence_result = GL_EXTCALL(glTestFenceNV(query->object.id));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glTestFenceNV");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else ret = WINED3D_EVENT_QUERY_WAITING;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync#ifdef VBOX_WITH_WDDM
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync /* doing Flush (rather than Finish) should be enough since we're serialized on the host in any way */
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync wglFlush();
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync ret = WINED3D_EVENT_QUERY_OK;
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync#else
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ERR("Event query created despite lack of GL support\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_ERROR;
fc50d11e45d83ecb4fbb2a6761d1adb5d6cc268fvboxsync#endif
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync LEAVE_GL();
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context_release(context);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return ret;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync}
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncenum wined3d_event_query_result wined3d_event_query_finish(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync{
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync struct wined3d_context *context;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync const struct wined3d_gl_info *gl_info;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync enum wined3d_event_query_result ret;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync TRACE("(%p)\n", query);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!query->context)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync TRACE("Query not started\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3D_EVENT_QUERY_NOT_STARTED;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync gl_info = query->context->gl_info;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (query->context->tid != GetCurrentThreadId() && !gl_info->supported[ARB_SYNC])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync /* A glFinish does not reliably wait for draws in other contexts. The caller has
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync * to find its own way to cope with the thread switch
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync */
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync ERR("Event query finished from wrong thread\n");
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync#else
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync WARN("Event query finished from wrong thread\n");
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync#endif
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3D_EVENT_QUERY_WRONG_THREAD;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context = context_acquire(device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ENTER_GL();
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (gl_info->supported[ARB_SYNC])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, ~(GLuint64)0));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glClientWaitSync");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync switch (gl_ret)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case GL_ALREADY_SIGNALED:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case GL_CONDITION_SATISFIED:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync /* We don't expect a timeout for a ~584 year wait */
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync default:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ERR("glClientWaitSync returned %#x.\n", gl_ret);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_ERROR;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else if (context->gl_info->supported[APPLE_FENCE])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync GL_EXTCALL(glFinishFenceAPPLE(query->object.id));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glFinishFenceAPPLE");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else if (context->gl_info->supported[NV_FENCE])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync GL_EXTCALL(glFinishFenceNV(query->object.id));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glFinishFenceNV");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ERR("Event query created without GL support\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = WINED3D_EVENT_QUERY_ERROR;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync LEAVE_GL();
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context_release(context);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return ret;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync}
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncvoid wined3d_event_query_issue(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync{
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync const struct wined3d_gl_info *gl_info;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync struct wined3d_context *context;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (query->context)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync ERR("unexpected\n");
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync#endif
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context_free_event_query(query);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context_alloc_event_query(context, query);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context = context_acquire(device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context_alloc_event_query(context, query);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync gl_info = context->gl_info;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ENTER_GL();
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (gl_info->supported[ARB_SYNC])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (query->object.sync) GL_EXTCALL(glDeleteSync(query->object.sync));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glDeleteSync");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glFenceSync");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else if (gl_info->supported[APPLE_FENCE])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync GL_EXTCALL(glSetFenceAPPLE(query->object.id));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glSetFenceAPPLE");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync else if (gl_info->supported[NV_FENCE])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync GL_EXTCALL(glSetFenceNV(query->object.id, GL_ALL_COMPLETED_NV));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync checkGLcall("glSetFenceNV");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync LEAVE_GL();
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync context_release(context);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync}
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Occlusion Queries:
af062818b47340eef15700d2f0211576ba3506eevboxsync * http://www.gris.uni-tuebingen.de/~bartz/Publications/paper/hww98.pdf
af062818b47340eef15700d2f0211576ba3506eevboxsync * http://oss.sgi.com/projects/ogl-sample/registry/ARB/occlusion_query.txt
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/* *******************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQuery IUnknown parts follow
af062818b47340eef15700d2f0211576ba3506eevboxsync ******************************************* */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic HRESULT WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (IsEqualGUID(riid, &IID_IUnknown)
af062818b47340eef15700d2f0211576ba3506eevboxsync || IsEqualGUID(riid, &IID_IWineD3DBase)
af062818b47340eef15700d2f0211576ba3506eevboxsync || IsEqualGUID(riid, &IID_IWineD3DQuery)) {
af062818b47340eef15700d2f0211576ba3506eevboxsync IUnknown_AddRef(iface);
af062818b47340eef15700d2f0211576ba3506eevboxsync *ppobj = This;
af062818b47340eef15700d2f0211576ba3506eevboxsync return S_OK;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync *ppobj = NULL;
af062818b47340eef15700d2f0211576ba3506eevboxsync return E_NOINTERFACE;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic ULONG WINAPI IWineD3DQueryImpl_AddRef(IWineD3DQuery *iface) {
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p) : AddRef increasing from %d\n", This, This->ref);
af062818b47340eef15700d2f0211576ba3506eevboxsync return InterlockedIncrement(&This->ref);
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic ULONG WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
af062818b47340eef15700d2f0211576ba3506eevboxsync ULONG ref;
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p) : Releasing from %d\n", This, This->ref);
af062818b47340eef15700d2f0211576ba3506eevboxsync ref = InterlockedDecrement(&This->ref);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ref == 0) {
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync /* Queries are specific to the GL context that created them. Not
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * deleting the query will obviously leak it, but that's still better
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * than potentially deleting a different query with the same id in this
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * context, and (still) leaking the actual query. */
040b4a09341f574825386333398110f4db3e1e51vboxsync if (This->type == WINED3DQUERYTYPE_EVENT)
040b4a09341f574825386333398110f4db3e1e51vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync struct wined3d_event_query *query = This->extendedData;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (query) wined3d_event_query_destroy(query);
040b4a09341f574825386333398110f4db3e1e51vboxsync }
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
040b4a09341f574825386333398110f4db3e1e51vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync struct wined3d_occlusion_query *query = This->extendedData;
040b4a09341f574825386333398110f4db3e1e51vboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (query->context) context_free_occlusion_query(query);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync HeapFree(GetProcessHeap(), 0, This->extendedData);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync HeapFree(GetProcessHeap(), 0, This);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return ref;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/* *******************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQuery IWineD3DQuery parts follow
af062818b47340eef15700d2f0211576ba3506eevboxsync ******************************************* */
5112e32d7072e280613921c982a6672f2c859cf3vboxsyncstatic HRESULT WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown **parent)
5112e32d7072e280613921c982a6672f2c859cf3vboxsync{
5112e32d7072e280613921c982a6672f2c859cf3vboxsync TRACE("iface %p, parent %p.\n", iface, parent);
af062818b47340eef15700d2f0211576ba3506eevboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync *parent = (IUnknown *)parent;
af062818b47340eef15700d2f0211576ba3506eevboxsync IUnknown_AddRef(*parent);
af062818b47340eef15700d2f0211576ba3506eevboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync TRACE("Returning %p.\n", *parent);
5112e32d7072e280613921c982a6672f2c859cf3vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return WINED3D_OK;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic HRESULT WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync struct wined3d_occlusion_query *query = This->extendedData;
5112e32d7072e280613921c982a6672f2c859cf3vboxsync IWineD3DDeviceImpl *device = This->device;
5112e32d7072e280613921c982a6672f2c859cf3vboxsync const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5112e32d7072e280613921c982a6672f2c859cf3vboxsync struct wined3d_context *context;
af062818b47340eef15700d2f0211576ba3506eevboxsync DWORD* data = pData;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync GLuint available;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync GLuint samples;
af062818b47340eef15700d2f0211576ba3506eevboxsync HRESULT res;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
af062818b47340eef15700d2f0211576ba3506eevboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (!query->context) This->state = QUERY_CREATED;
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync if (This->state == QUERY_CREATED)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("Query wasn't yet started, returning S_OK\n");
af062818b47340eef15700d2f0211576ba3506eevboxsync if(data) *data = 0;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync return S_OK;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync if (This->state == QUERY_BUILDING)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("Query is building, returning S_FALSE\n");
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync return S_FALSE;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync if (!gl_info->supported[ARB_OCCLUSION_QUERY])
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync WARN("(%p) : Occlusion queries not supported. Returning 1.\n", This);
af062818b47340eef15700d2f0211576ba3506eevboxsync *data = 1;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync return S_OK;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (query->context->tid != GetCurrentThreadId())
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
040b4a09341f574825386333398110f4db3e1e51vboxsync FIXME("%p Wrong thread, returning 1.\n", This);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync *data = 1;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync return S_OK;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
040b4a09341f574825386333398110f4db3e1e51vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync ENTER_GL();
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
040b4a09341f574825386333398110f4db3e1e51vboxsync checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync TRACE("(%p) : available %d.\n", This, available);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync if (available)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync if (data)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_ARB, &samples));
040b4a09341f574825386333398110f4db3e1e51vboxsync checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync TRACE("(%p) : Returning %d samples.\n", This, samples);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync *data = samples;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync res = S_OK;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync else
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync res = S_FALSE;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync LEAVE_GL();
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context_release(context);
5112e32d7072e280613921c982a6672f2c859cf3vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return res;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic HRESULT WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync struct wined3d_event_query *query = This->extendedData;
5112e32d7072e280613921c982a6672f2c859cf3vboxsync BOOL *data = pData;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync enum wined3d_event_query_result ret;
040b4a09341f574825386333398110f4db3e1e51vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
af062818b47340eef15700d2f0211576ba3506eevboxsync
040b4a09341f574825386333398110f4db3e1e51vboxsync if (!pData || !dwSize) return S_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!query)
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync WARN("(%p): Event query not supported by GL, reporting GPU idle\n", This);
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync *data = TRUE;
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync return S_OK;
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync }
a3133ef29cdf3656735d569fd64e54c9286effc0vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ret = wined3d_event_query_test(query, This->device);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync switch(ret)
040b4a09341f574825386333398110f4db3e1e51vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3D_EVENT_QUERY_OK:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3D_EVENT_QUERY_NOT_STARTED:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync *data = TRUE;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
040b4a09341f574825386333398110f4db3e1e51vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3D_EVENT_QUERY_WAITING:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync *data = FALSE;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
040b4a09341f574825386333398110f4db3e1e51vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3D_EVENT_QUERY_WRONG_THREAD:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync FIXME("(%p) Wrong thread, reporting GPU idle.\n", This);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync *data = TRUE;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
040b4a09341f574825386333398110f4db3e1e51vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3D_EVENT_QUERY_ERROR:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ERR("The GL event query failed, returning D3DERR_INVALIDCALL\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3DERR_INVALIDCALL;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return S_OK;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic DWORD WINAPI IWineD3DEventQueryImpl_GetDataSize(IWineD3DQuery* iface){
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p) : type D3DQUERY_EVENT\n", iface);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return sizeof(BOOL);
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic DWORD WINAPI IWineD3DOcclusionQueryImpl_GetDataSize(IWineD3DQuery* iface){
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p) : type D3DQUERY_OCCLUSION\n", iface);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return sizeof(DWORD);
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic WINED3DQUERYTYPE WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
af062818b47340eef15700d2f0211576ba3506eevboxsync return This->type;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic HRESULT WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIssueFlags) {
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags);
040b4a09341f574825386333398110f4db3e1e51vboxsync if (dwIssueFlags & WINED3DISSUE_END)
040b4a09341f574825386333398110f4db3e1e51vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync struct wined3d_event_query *query = This->extendedData;
040b4a09341f574825386333398110f4db3e1e51vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync /* Faked event query support */
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!query) return WINED3D_OK;
5112e32d7072e280613921c982a6672f2c859cf3vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync wined3d_event_query_issue(query, This->device);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync }
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync else if(dwIssueFlags & WINED3DISSUE_BEGIN)
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Started implicitly at device creation */
af062818b47340eef15700d2f0211576ba3506eevboxsync ERR("Event query issued with START flag - what to do?\n");
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if(dwIssueFlags & WINED3DISSUE_BEGIN) {
af062818b47340eef15700d2f0211576ba3506eevboxsync This->state = QUERY_BUILDING;
af062818b47340eef15700d2f0211576ba3506eevboxsync } else {
af062818b47340eef15700d2f0211576ba3506eevboxsync This->state = QUERY_SIGNALLED;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return WINED3D_OK;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic HRESULT WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIssueFlags) {
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
5112e32d7072e280613921c982a6672f2c859cf3vboxsync IWineD3DDeviceImpl *device = This->device;
5112e32d7072e280613921c982a6672f2c859cf3vboxsync const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
af062818b47340eef15700d2f0211576ba3506eevboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync if (gl_info->supported[ARB_OCCLUSION_QUERY])
040b4a09341f574825386333398110f4db3e1e51vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync struct wined3d_occlusion_query *query = This->extendedData;
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync struct wined3d_context *context;
040b4a09341f574825386333398110f4db3e1e51vboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync /* This is allowed according to msdn and our tests. Reset the query and restart */
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (dwIssueFlags & WINED3DISSUE_BEGIN)
040b4a09341f574825386333398110f4db3e1e51vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (This->state == QUERY_BUILDING)
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (query->context->tid != GetCurrentThreadId())
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync FIXME("Wrong thread, can't restart query.\n");
af062818b47340eef15700d2f0211576ba3506eevboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync context_free_occlusion_query(query);
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context = context_acquire(This->device, NULL, CTXUSAGE_RESOURCELOAD);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync context_alloc_occlusion_query(context, query);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync }
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync else
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync ENTER_GL();
af062818b47340eef15700d2f0211576ba3506eevboxsync GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
af062818b47340eef15700d2f0211576ba3506eevboxsync checkGLcall("glEndQuery()");
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync LEAVE_GL();
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync else
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (query->context) context_free_occlusion_query(query);
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context = context_acquire(This->device, NULL, CTXUSAGE_RESOURCELOAD);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync context_alloc_occlusion_query(context, query);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync }
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync ENTER_GL();
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query->id));
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync checkGLcall("glBeginQuery()");
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync LEAVE_GL();
5112e32d7072e280613921c982a6672f2c859cf3vboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context_release(context);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync }
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (dwIssueFlags & WINED3DISSUE_END) {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync /* Msdn says _END on a non-building occlusion query returns an error, but
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync * generating an error
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync */
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (This->state == QUERY_BUILDING)
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync if (query->context->tid != GetCurrentThreadId())
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync FIXME("Wrong thread, can't end query.\n");
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync }
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync else
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync {
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync ENTER_GL();
af062818b47340eef15700d2f0211576ba3506eevboxsync GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
af062818b47340eef15700d2f0211576ba3506eevboxsync checkGLcall("glEndQuery()");
114410893548b9522c46fdcbd8f63385eb8bfb68vboxsync LEAVE_GL();
5112e32d7072e280613921c982a6672f2c859cf3vboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync context_release(context);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync } else {
af062818b47340eef15700d2f0211576ba3506eevboxsync FIXME("(%p) : Occlusion queries not supported\n", This);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if(dwIssueFlags & WINED3DISSUE_BEGIN) {
af062818b47340eef15700d2f0211576ba3506eevboxsync This->state = QUERY_BUILDING;
af062818b47340eef15700d2f0211576ba3506eevboxsync } else {
af062818b47340eef15700d2f0211576ba3506eevboxsync This->state = QUERY_SIGNALLED;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncstatic const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl =
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /*** IUnknown methods ***/
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_QueryInterface,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_AddRef,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_Release,
af062818b47340eef15700d2f0211576ba3506eevboxsync /*** IWineD3Dquery methods ***/
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_GetParent,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DEventQueryImpl_GetData,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DEventQueryImpl_GetDataSize,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_GetType,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DEventQueryImpl_Issue
af062818b47340eef15700d2f0211576ba3506eevboxsync};
af062818b47340eef15700d2f0211576ba3506eevboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncstatic const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl =
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /*** IUnknown methods ***/
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_QueryInterface,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_AddRef,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_Release,
af062818b47340eef15700d2f0211576ba3506eevboxsync /*** IWineD3Dquery methods ***/
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_GetParent,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DOcclusionQueryImpl_GetData,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DOcclusionQueryImpl_GetDataSize,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DQueryImpl_GetType,
af062818b47340eef15700d2f0211576ba3506eevboxsync IWineD3DOcclusionQueryImpl_Issue
af062818b47340eef15700d2f0211576ba3506eevboxsync};
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsyncHRESULT query_init(IWineD3DQueryImpl *query, IWineD3DDeviceImpl *device,
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync WINED3DQUERYTYPE type, IUnknown *parent)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync{
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync switch (type)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_OCCLUSION:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync TRACE("Occlusion query.\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!gl_info->supported[ARB_OCCLUSION_QUERY])
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3DERR_NOTAVAILABLE;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->lpVtbl = &IWineD3DOcclusionQuery_Vtbl;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!query->extendedData)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ERR("Failed to allocate occlusion query extended data.\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return E_OUTOFMEMORY;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ((struct wined3d_occlusion_query *)query->extendedData)->context = NULL;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_EVENT:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync TRACE("Event query.\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!wined3d_event_query_supported(gl_info))
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync /* Half-Life 2 needs this query. It does not render the main
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync * menu correctly otherwise. Pretend to support it, faking
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync * this query does not do much harm except potentially
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync * lowering performance. */
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync FIXME("Event query: Unimplemented, but pretending to be supported.\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->lpVtbl = &IWineD3DEventQuery_Vtbl;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wined3d_event_query));
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!query->extendedData)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync ERR("Failed to allocate event query memory.\n");
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return E_OUTOFMEMORY;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync break;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_VCACHE:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_RESOURCEMANAGER:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_VERTEXSTATS:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_TIMESTAMP:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_TIMESTAMPFREQ:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_PIPELINETIMINGS:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_INTERFACETIMINGS:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_VERTEXTIMINGS:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_PIXELTIMINGS:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync case WINED3DQUERYTYPE_CACHEUTILIZATION:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync default:
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync FIXME("Unhandled query type %#x.\n", type);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3DERR_NOTAVAILABLE;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync }
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->type = type;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->state = QUERY_CREATED;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->device = device;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->parent = parent;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync query->ref = 1;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync return WINED3D_OK;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync}