Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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 "c99_alloca.h"
24
 
25
#include "device9.h"
26
#include "surface9.h"
27
#include "texture9.h"
28
#include "nine_helpers.h"
29
#include "nine_pipe.h"
30
#include "nine_dump.h"
31
 
32
#include "pipe/p_state.h"
33
#include "pipe/p_context.h"
34
#include "pipe/p_screen.h"
35
#include "util/u_inlines.h"
36
#include "util/u_resource.h"
37
 
38
#define DBG_CHANNEL DBG_TEXTURE
39
 
40
static HRESULT
41
NineTexture9_ctor( struct NineTexture9 *This,
42
                   struct NineUnknownParams *pParams,
43
                   UINT Width, UINT Height, UINT Levels,
44
                   DWORD Usage,
45
                   D3DFORMAT Format,
46
                   D3DPOOL Pool,
47
                   HANDLE *pSharedHandle )
48
{
49
    struct pipe_screen *screen = pParams->device->screen;
50
    struct pipe_resource *info = &This->base.base.info;
51
    struct pipe_resource *resource;
52
    enum pipe_format pf;
53
    unsigned *level_offsets;
54
    unsigned l;
55
    D3DSURFACE_DESC sfdesc;
56
    HRESULT hr;
57
    void *user_buffer = NULL, *user_buffer_for_level;
58
 
59
    DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
60
        "pSharedHandle=%p\n", This, Width, Height, Levels,
61
        nine_D3DUSAGE_to_str(Usage),
62
        d3dformat_to_string(Format), nine_D3DPOOL_to_str(Pool), pSharedHandle);
63
 
64
    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
65
                (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL);
66
 
67
    /* TODO: implement buffer sharing (should work with cross process too)
68
     *
69
     * Gem names may have fit but they're depreciated and won't work on render-nodes.
70
     * One solution is to use shm buffers. We would use a /dev/shm file, fill the first
71
     * values to tell it is a nine buffer, the size, which function created it, etc,
72
     * and then it would contain the data. The handle would be a number, corresponding to
73
     * the file to read (/dev/shm/nine-share-4 for example would be 4).
74
     *
75
     * Wine just ignores the argument, which works only if the app creates the handle
76
     * and won't use it. Instead of failing, we support that situation by putting an
77
     * invalid handle, that we would fail to import. Please note that we don't advertise
78
     * the flag indicating the support for that feature, but apps seem to not care.
79
     */
80
    user_assert(!pSharedHandle ||
81
                Pool == D3DPOOL_SYSTEMMEM ||
82
                Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
83
 
84
    if (pSharedHandle && Pool == D3DPOOL_DEFAULT) {
85
        if (!*pSharedHandle) {
86
            DBG("Creating Texture with invalid handle. Importing will fail\n.");
87
            *pSharedHandle = (HANDLE)1; /* Wine would keep it NULL */
88
            pSharedHandle = NULL;
89
        } else {
90
            ERR("Application tries to use cross-process sharing feature. Nine "
91
                "doesn't support it");
92
            return D3DERR_INVALIDCALL;
93
        }
94
    }
95
 
96
    if (Usage & D3DUSAGE_AUTOGENMIPMAP)
97
        Levels = 0;
98
 
99
    pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_2D, 0,
100
                                     PIPE_BIND_SAMPLER_VIEW, FALSE);
101
    if (Format != D3DFMT_NULL && pf == PIPE_FORMAT_NONE)
102
        return D3DERR_INVALIDCALL;
103
 
104
    info->screen = screen;
105
    info->target = PIPE_TEXTURE_2D;
106
    info->format = pf;
107
    info->width0 = Width;
108
    info->height0 = Height;
109
    info->depth0 = 1;
110
    if (Levels)
111
        info->last_level = Levels - 1;
112
    else
113
        info->last_level = util_logbase2(MAX2(Width, Height));
114
    info->array_size = 1;
115
    info->nr_samples = 0;
116
    info->bind = PIPE_BIND_SAMPLER_VIEW;
117
    info->usage = PIPE_USAGE_DEFAULT;
118
    info->flags = 0;
119
 
120
    if (Usage & D3DUSAGE_RENDERTARGET)
121
        info->bind |= PIPE_BIND_RENDER_TARGET;
122
    if (Usage & D3DUSAGE_DEPTHSTENCIL)
123
        info->bind |= PIPE_BIND_DEPTH_STENCIL;
124
 
125
    if (Usage & D3DUSAGE_DYNAMIC) {
126
        info->usage = PIPE_USAGE_DYNAMIC;
127
        info->bind |=
128
            PIPE_BIND_TRANSFER_READ |
129
            PIPE_BIND_TRANSFER_WRITE;
130
    }
131
 
132
    if (Usage & D3DUSAGE_SOFTWAREPROCESSING)
133
        DBG("Application asked for Software Vertex Processing, "
134
            "but this is unimplemented\n");
135
 
136
    if (pSharedHandle)
137
        info->bind |= PIPE_BIND_SHARED;
138
 
139
    if (Pool == D3DPOOL_SYSTEMMEM)
140
        info->usage = PIPE_USAGE_STAGING;
141
 
142
    if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */
143
        user_buffer = (void *)*pSharedHandle;
144
        level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
145
        (void) nine_format_get_size_and_offsets(pf, level_offsets,
146
                                                Width, Height,
147
                                                info->last_level);
148
    } else if (Pool != D3DPOOL_DEFAULT) {
149
        /* TODO: For D3DUSAGE_AUTOGENMIPMAP, it is likely we only have to
150
         * allocate only for the first level, since it is the only lockable
151
         * level. Check apps don't crash if we allocate smaller buffer (some
152
         * apps access sublevels of texture even if they locked only first
153
         * level) */
154
        level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
155
        user_buffer = MALLOC(
156
            nine_format_get_size_and_offsets(pf, level_offsets,
157
                                             Width, Height,
158
                                             info->last_level));
159
        This->managed_buffer = user_buffer;
160
        if (!This->managed_buffer)
161
            return E_OUTOFMEMORY;
162
    }
163
 
164
    This->surfaces = CALLOC(info->last_level + 1, sizeof(*This->surfaces));
165
    if (!This->surfaces)
166
        return E_OUTOFMEMORY;
167
 
168
    hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage);
169
    if (FAILED(hr))
170
        return hr;
171
    This->base.pstype = (Height == 1) ? 1 : 0;
172
 
173
    /* Create all the surfaces right away.
174
     * They manage backing storage, and transfers (LockRect) are deferred
175
     * to them.
176
     */
177
    sfdesc.Format = Format;
178
    sfdesc.Type = D3DRTYPE_SURFACE;
179
    sfdesc.Usage = Usage;
180
    sfdesc.Pool = Pool;
181
    sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
182
    sfdesc.MultiSampleQuality = 0;
183
 
184
    if (Pool == D3DPOOL_SYSTEMMEM)
185
        resource = NULL;
186
    else
187
        resource = This->base.base.resource;
188
 
189
    for (l = 0; l <= info->last_level; ++l) {
190
        sfdesc.Width = u_minify(Width, l);
191
        sfdesc.Height = u_minify(Height, l);
192
        /* Some apps expect the memory to be allocated in
193
         * continous blocks */
194
        user_buffer_for_level = user_buffer ? user_buffer +
195
            level_offsets[l] : NULL;
196
 
197
        hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
198
                              resource, user_buffer_for_level,
199
                              D3DRTYPE_TEXTURE, l, 0,
200
                              &sfdesc, &This->surfaces[l]);
201
        if (FAILED(hr))
202
            return hr;
203
    }
204
 
205
    This->dirty_rect.depth = 1; /* widht == 0 means empty, depth stays 1 */
206
 
207
    if (pSharedHandle && !*pSharedHandle) {/* Pool == D3DPOOL_SYSTEMMEM */
208
        *pSharedHandle = This->surfaces[0]->data;
209
    }
210
 
211
    return D3D_OK;
212
}
213
 
214
static void
215
NineTexture9_dtor( struct NineTexture9 *This )
216
{
217
    unsigned l;
218
 
219
    if (This->surfaces) {
220
        /* The surfaces should have 0 references and be unbound now. */
221
        for (l = 0; l <= This->base.base.info.last_level; ++l)
222
            NineUnknown_Destroy(&This->surfaces[l]->base.base);
223
        FREE(This->surfaces);
224
    }
225
 
226
    if (This->managed_buffer)
227
        FREE(This->managed_buffer);
228
 
229
    NineBaseTexture9_dtor(&This->base);
230
}
231
 
232
HRESULT WINAPI
233
NineTexture9_GetLevelDesc( struct NineTexture9 *This,
234
                           UINT Level,
235
                           D3DSURFACE_DESC *pDesc )
236
{
237
    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
238
    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
239
                D3DERR_INVALIDCALL);
240
 
241
    *pDesc = This->surfaces[Level]->desc;
242
 
243
    return D3D_OK;
244
}
245
 
246
HRESULT WINAPI
247
NineTexture9_GetSurfaceLevel( struct NineTexture9 *This,
248
                              UINT Level,
249
                              IDirect3DSurface9 **ppSurfaceLevel )
250
{
251
    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
252
    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
253
                D3DERR_INVALIDCALL);
254
 
255
    NineUnknown_AddRef(NineUnknown(This->surfaces[Level]));
256
    *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level];
257
 
258
    return D3D_OK;
259
}
260
 
261
HRESULT WINAPI
262
NineTexture9_LockRect( struct NineTexture9 *This,
263
                       UINT Level,
264
                       D3DLOCKED_RECT *pLockedRect,
265
                       const RECT *pRect,
266
                       DWORD Flags )
267
{
268
    DBG("This=%p Level=%u pLockedRect=%p pRect=%p Flags=%d\n",
269
        This, Level, pLockedRect, pRect, Flags);
270
 
271
    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
272
    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
273
                D3DERR_INVALIDCALL);
274
 
275
    return NineSurface9_LockRect(This->surfaces[Level], pLockedRect,
276
                                 pRect, Flags);
277
}
278
 
279
HRESULT WINAPI
280
NineTexture9_UnlockRect( struct NineTexture9 *This,
281
                         UINT Level )
282
{
283
    DBG("This=%p Level=%u\n", This, Level);
284
 
285
    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
286
 
287
    return NineSurface9_UnlockRect(This->surfaces[Level]);
288
}
289
 
290
HRESULT WINAPI
291
NineTexture9_AddDirtyRect( struct NineTexture9 *This,
292
                           const RECT *pDirtyRect )
293
{
294
    DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect,
295
        pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0,
296
        pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0);
297
 
298
    /* Tracking dirty regions on DEFAULT or SYSTEMMEM resources is pointless,
299
     * because we always write to the final storage. Just marked it dirty in
300
     * case we need to generate mip maps.
301
     */
302
    if (This->base.base.pool != D3DPOOL_MANAGED) {
303
        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP)
304
            This->base.dirty_mip = TRUE;
305
        return D3D_OK;
306
    }
307
    This->base.managed.dirty = TRUE;
308
 
309
    BASETEX_REGISTER_UPDATE(&This->base);
310
 
311
    if (!pDirtyRect) {
312
        u_box_origin_2d(This->base.base.info.width0,
313
                        This->base.base.info.height0, &This->dirty_rect);
314
    } else {
315
        struct pipe_box box;
316
        rect_to_pipe_box_clamp(&box, pDirtyRect);
317
        u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box);
318
        (void) u_box_clip_2d(&This->dirty_rect, &This->dirty_rect,
319
                             This->base.base.info.width0,
320
                             This->base.base.info.height0);
321
    }
322
    return D3D_OK;
323
}
324
 
325
IDirect3DTexture9Vtbl NineTexture9_vtable = {
326
    (void *)NineUnknown_QueryInterface,
327
    (void *)NineUnknown_AddRef,
328
    (void *)NineUnknown_Release,
329
    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
330
    (void *)NineResource9_SetPrivateData,
331
    (void *)NineResource9_GetPrivateData,
332
    (void *)NineResource9_FreePrivateData,
333
    (void *)NineResource9_SetPriority,
334
    (void *)NineResource9_GetPriority,
335
    (void *)NineBaseTexture9_PreLoad,
336
    (void *)NineResource9_GetType,
337
    (void *)NineBaseTexture9_SetLOD,
338
    (void *)NineBaseTexture9_GetLOD,
339
    (void *)NineBaseTexture9_GetLevelCount,
340
    (void *)NineBaseTexture9_SetAutoGenFilterType,
341
    (void *)NineBaseTexture9_GetAutoGenFilterType,
342
    (void *)NineBaseTexture9_GenerateMipSubLevels,
343
    (void *)NineTexture9_GetLevelDesc,
344
    (void *)NineTexture9_GetSurfaceLevel,
345
    (void *)NineTexture9_LockRect,
346
    (void *)NineTexture9_UnlockRect,
347
    (void *)NineTexture9_AddDirtyRect
348
};
349
 
350
static const GUID *NineTexture9_IIDs[] = {
351
    &IID_IDirect3DTexture9,
352
    &IID_IDirect3DBaseTexture9,
353
    &IID_IDirect3DResource9,
354
    &IID_IUnknown,
355
    NULL
356
};
357
 
358
HRESULT
359
NineTexture9_new( struct NineDevice9 *pDevice,
360
                  UINT Width, UINT Height, UINT Levels,
361
                  DWORD Usage,
362
                  D3DFORMAT Format,
363
                  D3DPOOL Pool,
364
                  struct NineTexture9 **ppOut,
365
                  HANDLE *pSharedHandle )
366
{
367
    NINE_DEVICE_CHILD_NEW(Texture9, ppOut, pDevice,
368
                          Width, Height, Levels,
369
                          Usage, Format, Pool, pSharedHandle);
370
}