1b8e80941Smrg/* 2b8e80941Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 8b8e80941Smrg * license, and/or sell copies of the Software, and to permit persons to whom 9b8e80941Smrg * the Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22b8e80941Smrg 23b8e80941Smrg#include "device9.h" 24b8e80941Smrg#include "nine_state.h" 25b8e80941Smrg#include "query9.h" 26b8e80941Smrg#include "nine_helpers.h" 27b8e80941Smrg#include "pipe/p_screen.h" 28b8e80941Smrg#include "pipe/p_context.h" 29b8e80941Smrg#include "util/u_math.h" 30b8e80941Smrg#include "nine_dump.h" 31b8e80941Smrg 32b8e80941Smrg#define DBG_CHANNEL DBG_QUERY 33b8e80941Smrg 34b8e80941Smrgstatic inline unsigned 35b8e80941Smrgd3dquerytype_to_pipe_query(struct pipe_screen *screen, D3DQUERYTYPE type) 36b8e80941Smrg{ 37b8e80941Smrg switch (type) { 38b8e80941Smrg case D3DQUERYTYPE_EVENT: 39b8e80941Smrg return PIPE_QUERY_GPU_FINISHED; 40b8e80941Smrg case D3DQUERYTYPE_OCCLUSION: 41b8e80941Smrg return screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY) ? 42b8e80941Smrg PIPE_QUERY_OCCLUSION_COUNTER : PIPE_QUERY_TYPES; 43b8e80941Smrg case D3DQUERYTYPE_TIMESTAMP: 44b8e80941Smrg return screen->get_param(screen, PIPE_CAP_QUERY_TIMESTAMP) ? 45b8e80941Smrg PIPE_QUERY_TIMESTAMP : PIPE_QUERY_TYPES; 46b8e80941Smrg case D3DQUERYTYPE_TIMESTAMPDISJOINT: 47b8e80941Smrg case D3DQUERYTYPE_TIMESTAMPFREQ: 48b8e80941Smrg return screen->get_param(screen, PIPE_CAP_QUERY_TIMESTAMP) ? 49b8e80941Smrg PIPE_QUERY_TIMESTAMP_DISJOINT : PIPE_QUERY_TYPES; 50b8e80941Smrg case D3DQUERYTYPE_VERTEXSTATS: 51b8e80941Smrg return screen->get_param(screen, 52b8e80941Smrg PIPE_CAP_QUERY_PIPELINE_STATISTICS) ? 53b8e80941Smrg PIPE_QUERY_PIPELINE_STATISTICS : PIPE_QUERY_TYPES; 54b8e80941Smrg default: 55b8e80941Smrg return PIPE_QUERY_TYPES; /* Query not supported */ 56b8e80941Smrg } 57b8e80941Smrg} 58b8e80941Smrg 59b8e80941Smrg#define GET_DATA_SIZE_CASE2(a, b) case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_##b) 60b8e80941Smrg#define GET_DATA_SIZE_CASET(a, b) case D3DQUERYTYPE_##a: return sizeof(b) 61b8e80941Smrgstatic inline DWORD 62b8e80941Smrgnine_query_result_size(D3DQUERYTYPE type) 63b8e80941Smrg{ 64b8e80941Smrg switch (type) { 65b8e80941Smrg GET_DATA_SIZE_CASE2(VERTEXSTATS, D3DVERTEXSTATS); 66b8e80941Smrg GET_DATA_SIZE_CASET(EVENT, BOOL); 67b8e80941Smrg GET_DATA_SIZE_CASET(OCCLUSION, DWORD); 68b8e80941Smrg GET_DATA_SIZE_CASET(TIMESTAMP, UINT64); 69b8e80941Smrg GET_DATA_SIZE_CASET(TIMESTAMPDISJOINT, BOOL); 70b8e80941Smrg GET_DATA_SIZE_CASET(TIMESTAMPFREQ, UINT64); 71b8e80941Smrg default: 72b8e80941Smrg assert(0); 73b8e80941Smrg return 0; 74b8e80941Smrg } 75b8e80941Smrg} 76b8e80941Smrg 77b8e80941SmrgHRESULT 78b8e80941Smrgnine_is_query_supported(struct pipe_screen *screen, D3DQUERYTYPE type) 79b8e80941Smrg{ 80b8e80941Smrg const unsigned ptype = d3dquerytype_to_pipe_query(screen, type); 81b8e80941Smrg 82b8e80941Smrg user_assert(ptype != ~0, D3DERR_INVALIDCALL); 83b8e80941Smrg 84b8e80941Smrg if (ptype == PIPE_QUERY_TYPES) { 85b8e80941Smrg DBG("Query type %u (%s) not supported.\n", 86b8e80941Smrg type, nine_D3DQUERYTYPE_to_str(type)); 87b8e80941Smrg return D3DERR_NOTAVAILABLE; 88b8e80941Smrg } 89b8e80941Smrg return D3D_OK; 90b8e80941Smrg} 91b8e80941Smrg 92b8e80941SmrgHRESULT 93b8e80941SmrgNineQuery9_ctor( struct NineQuery9 *This, 94b8e80941Smrg struct NineUnknownParams *pParams, 95b8e80941Smrg D3DQUERYTYPE Type ) 96b8e80941Smrg{ 97b8e80941Smrg struct NineDevice9 *device = pParams->device; 98b8e80941Smrg const unsigned ptype = d3dquerytype_to_pipe_query(device->screen, Type); 99b8e80941Smrg HRESULT hr; 100b8e80941Smrg 101b8e80941Smrg DBG("This=%p pParams=%p Type=%d\n", This, pParams, Type); 102b8e80941Smrg 103b8e80941Smrg hr = NineUnknown_ctor(&This->base, pParams); 104b8e80941Smrg if (FAILED(hr)) 105b8e80941Smrg return hr; 106b8e80941Smrg 107b8e80941Smrg This->state = NINE_QUERY_STATE_FRESH; 108b8e80941Smrg This->type = Type; 109b8e80941Smrg 110b8e80941Smrg user_assert(ptype != ~0, D3DERR_INVALIDCALL); 111b8e80941Smrg 112b8e80941Smrg if (ptype < PIPE_QUERY_TYPES) { 113b8e80941Smrg This->pq = nine_context_create_query(device, ptype); 114b8e80941Smrg if (!This->pq) 115b8e80941Smrg return E_OUTOFMEMORY; 116b8e80941Smrg } else { 117b8e80941Smrg assert(0); /* we have checked this case before */ 118b8e80941Smrg } 119b8e80941Smrg 120b8e80941Smrg This->instant = 121b8e80941Smrg Type == D3DQUERYTYPE_EVENT || 122b8e80941Smrg Type == D3DQUERYTYPE_RESOURCEMANAGER || 123b8e80941Smrg Type == D3DQUERYTYPE_TIMESTAMP || 124b8e80941Smrg Type == D3DQUERYTYPE_TIMESTAMPFREQ || 125b8e80941Smrg Type == D3DQUERYTYPE_VCACHE || 126b8e80941Smrg Type == D3DQUERYTYPE_VERTEXSTATS; 127b8e80941Smrg 128b8e80941Smrg This->result_size = nine_query_result_size(Type); 129b8e80941Smrg 130b8e80941Smrg return D3D_OK; 131b8e80941Smrg} 132b8e80941Smrg 133b8e80941Smrgvoid 134b8e80941SmrgNineQuery9_dtor( struct NineQuery9 *This ) 135b8e80941Smrg{ 136b8e80941Smrg struct NineDevice9 *device = This->base.device; 137b8e80941Smrg 138b8e80941Smrg DBG("This=%p\n", This); 139b8e80941Smrg 140b8e80941Smrg if (This->pq) { 141b8e80941Smrg if (This->state == NINE_QUERY_STATE_RUNNING) 142b8e80941Smrg nine_context_end_query(device, &This->counter, This->pq); 143b8e80941Smrg nine_context_destroy_query(device, This->pq); 144b8e80941Smrg } 145b8e80941Smrg 146b8e80941Smrg NineUnknown_dtor(&This->base); 147b8e80941Smrg} 148b8e80941Smrg 149b8e80941SmrgD3DQUERYTYPE NINE_WINAPI 150b8e80941SmrgNineQuery9_GetType( struct NineQuery9 *This ) 151b8e80941Smrg{ 152b8e80941Smrg return This->type; 153b8e80941Smrg} 154b8e80941Smrg 155b8e80941SmrgDWORD NINE_WINAPI 156b8e80941SmrgNineQuery9_GetDataSize( struct NineQuery9 *This ) 157b8e80941Smrg{ 158b8e80941Smrg return This->result_size; 159b8e80941Smrg} 160b8e80941Smrg 161b8e80941SmrgHRESULT NINE_WINAPI 162b8e80941SmrgNineQuery9_Issue( struct NineQuery9 *This, 163b8e80941Smrg DWORD dwIssueFlags ) 164b8e80941Smrg{ 165b8e80941Smrg struct NineDevice9 *device = This->base.device; 166b8e80941Smrg 167b8e80941Smrg DBG("This=%p dwIssueFlags=%d\n", This, dwIssueFlags); 168b8e80941Smrg 169b8e80941Smrg user_assert((dwIssueFlags == D3DISSUE_BEGIN) || 170b8e80941Smrg (dwIssueFlags == 0) || 171b8e80941Smrg (dwIssueFlags == D3DISSUE_END), D3DERR_INVALIDCALL); 172b8e80941Smrg 173b8e80941Smrg /* Wine tests: always return D3D_OK on D3DISSUE_BEGIN 174b8e80941Smrg * even when the call is supposed to be forbidden */ 175b8e80941Smrg if (dwIssueFlags == D3DISSUE_BEGIN && This->instant) 176b8e80941Smrg return D3D_OK; 177b8e80941Smrg 178b8e80941Smrg if (dwIssueFlags == D3DISSUE_BEGIN) { 179b8e80941Smrg if (This->state == NINE_QUERY_STATE_RUNNING) 180b8e80941Smrg nine_context_end_query(device, &This->counter, This->pq); 181b8e80941Smrg nine_context_begin_query(device, &This->counter, This->pq); 182b8e80941Smrg This->state = NINE_QUERY_STATE_RUNNING; 183b8e80941Smrg } else { 184b8e80941Smrg if (This->state != NINE_QUERY_STATE_RUNNING && 185b8e80941Smrg This->type != D3DQUERYTYPE_EVENT && 186b8e80941Smrg This->type != D3DQUERYTYPE_TIMESTAMP) 187b8e80941Smrg nine_context_begin_query(device, &This->counter, This->pq); 188b8e80941Smrg nine_context_end_query(device, &This->counter, This->pq); 189b8e80941Smrg This->state = NINE_QUERY_STATE_ENDED; 190b8e80941Smrg } 191b8e80941Smrg return D3D_OK; 192b8e80941Smrg} 193b8e80941Smrg 194b8e80941Smrgunion nine_query_result 195b8e80941Smrg{ 196b8e80941Smrg D3DDEVINFO_D3DVERTEXSTATS vertexstats; 197b8e80941Smrg DWORD dw; 198b8e80941Smrg BOOL b; 199b8e80941Smrg UINT64 u64; 200b8e80941Smrg}; 201b8e80941Smrg 202b8e80941SmrgHRESULT NINE_WINAPI 203b8e80941SmrgNineQuery9_GetData( struct NineQuery9 *This, 204b8e80941Smrg void *pData, 205b8e80941Smrg DWORD dwSize, 206b8e80941Smrg DWORD dwGetDataFlags ) 207b8e80941Smrg{ 208b8e80941Smrg struct NineDevice9 *device = This->base.device; 209b8e80941Smrg boolean ok, wait_query_result = FALSE; 210b8e80941Smrg union pipe_query_result presult; 211b8e80941Smrg union nine_query_result nresult; 212b8e80941Smrg 213b8e80941Smrg DBG("This=%p pData=%p dwSize=%d dwGetDataFlags=%d\n", 214b8e80941Smrg This, pData, dwSize, dwGetDataFlags); 215b8e80941Smrg 216b8e80941Smrg /* according to spec we should return D3DERR_INVALIDCALL here, but 217b8e80941Smrg * wine returns S_FALSE because it is apparently the behaviour 218b8e80941Smrg * on windows */ 219b8e80941Smrg user_assert(This->state != NINE_QUERY_STATE_RUNNING, S_FALSE); 220b8e80941Smrg user_assert(dwSize == 0 || pData, D3DERR_INVALIDCALL); 221b8e80941Smrg user_assert(dwGetDataFlags == 0 || 222b8e80941Smrg dwGetDataFlags == D3DGETDATA_FLUSH, D3DERR_INVALIDCALL); 223b8e80941Smrg 224b8e80941Smrg if (This->state == NINE_QUERY_STATE_FRESH) { 225b8e80941Smrg /* App forgot calling Issue. call it for it. 226b8e80941Smrg * However Wine states that return value should 227b8e80941Smrg * be S_OK, so wait for the result to return S_OK. */ 228b8e80941Smrg NineQuery9_Issue(This, D3DISSUE_END); 229b8e80941Smrg wait_query_result = TRUE; 230b8e80941Smrg } 231b8e80941Smrg 232b8e80941Smrg /* The documention mentions no special case for D3DQUERYTYPE_TIMESTAMP. 233b8e80941Smrg * However Windows tests show that the query always succeeds when 234b8e80941Smrg * D3DGETDATA_FLUSH is specified. */ 235b8e80941Smrg if (This->type == D3DQUERYTYPE_TIMESTAMP && 236b8e80941Smrg (dwGetDataFlags & D3DGETDATA_FLUSH)) 237b8e80941Smrg wait_query_result = TRUE; 238b8e80941Smrg 239b8e80941Smrg 240b8e80941Smrg /* Note: We ignore dwGetDataFlags, because get_query_result will 241b8e80941Smrg * flush automatically if needed */ 242b8e80941Smrg 243b8e80941Smrg ok = nine_context_get_query_result(device, This->pq, &This->counter, 244b8e80941Smrg !!(dwGetDataFlags & D3DGETDATA_FLUSH), 245b8e80941Smrg wait_query_result, &presult); 246b8e80941Smrg 247b8e80941Smrg if (!ok) return S_FALSE; 248b8e80941Smrg 249b8e80941Smrg if (!dwSize) 250b8e80941Smrg return S_OK; 251b8e80941Smrg 252b8e80941Smrg switch (This->type) { 253b8e80941Smrg case D3DQUERYTYPE_EVENT: 254b8e80941Smrg nresult.b = presult.b; 255b8e80941Smrg break; 256b8e80941Smrg case D3DQUERYTYPE_OCCLUSION: 257b8e80941Smrg nresult.dw = presult.u64; 258b8e80941Smrg break; 259b8e80941Smrg case D3DQUERYTYPE_TIMESTAMP: 260b8e80941Smrg nresult.u64 = presult.u64; 261b8e80941Smrg break; 262b8e80941Smrg case D3DQUERYTYPE_TIMESTAMPDISJOINT: 263b8e80941Smrg nresult.b = presult.timestamp_disjoint.disjoint; 264b8e80941Smrg break; 265b8e80941Smrg case D3DQUERYTYPE_TIMESTAMPFREQ: 266b8e80941Smrg /* Applications use it to convert the TIMESTAMP value to time. 267b8e80941Smrg AMD drivers on win seem to return the actual hardware clock 268b8e80941Smrg resolution and corresponding values in TIMESTAMP. 269b8e80941Smrg However, this behaviour is not easy to replicate here. 270b8e80941Smrg So instead we do what wine and opengl do, and use 271b8e80941Smrg nanoseconds TIMESTAMPs. 272b8e80941Smrg (Which is also the unit used by PIPE_QUERY_TIMESTAMP.) 273b8e80941Smrg */ 274b8e80941Smrg nresult.u64 = 1000000000; 275b8e80941Smrg break; 276b8e80941Smrg case D3DQUERYTYPE_VERTEXSTATS: 277b8e80941Smrg nresult.vertexstats.NumRenderedTriangles = 278b8e80941Smrg presult.pipeline_statistics.c_invocations; 279b8e80941Smrg nresult.vertexstats.NumExtraClippingTriangles = 280b8e80941Smrg presult.pipeline_statistics.c_primitives; 281b8e80941Smrg break; 282b8e80941Smrg default: 283b8e80941Smrg assert(0); 284b8e80941Smrg break; 285b8e80941Smrg } 286b8e80941Smrg memcpy(pData, &nresult, MIN2(sizeof(nresult), dwSize)); 287b8e80941Smrg 288b8e80941Smrg return S_OK; 289b8e80941Smrg} 290b8e80941Smrg 291b8e80941SmrgIDirect3DQuery9Vtbl NineQuery9_vtable = { 292b8e80941Smrg (void *)NineUnknown_QueryInterface, 293b8e80941Smrg (void *)NineUnknown_AddRef, 294b8e80941Smrg (void *)NineUnknown_Release, 295b8e80941Smrg (void *)NineUnknown_GetDevice, /* actually part of Query9 iface */ 296b8e80941Smrg (void *)NineQuery9_GetType, 297b8e80941Smrg (void *)NineQuery9_GetDataSize, 298b8e80941Smrg (void *)NineQuery9_Issue, 299b8e80941Smrg (void *)NineQuery9_GetData 300b8e80941Smrg}; 301b8e80941Smrg 302b8e80941Smrgstatic const GUID *NineQuery9_IIDs[] = { 303b8e80941Smrg &IID_IDirect3DQuery9, 304b8e80941Smrg &IID_IUnknown, 305b8e80941Smrg NULL 306b8e80941Smrg}; 307b8e80941Smrg 308b8e80941SmrgHRESULT 309b8e80941SmrgNineQuery9_new( struct NineDevice9 *pDevice, 310b8e80941Smrg struct NineQuery9 **ppOut, 311b8e80941Smrg D3DQUERYTYPE Type ) 312b8e80941Smrg{ 313b8e80941Smrg NINE_DEVICE_CHILD_NEW(Query9, ppOut, pDevice, Type); 314b8e80941Smrg} 315