Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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