surface.c 13 KB
Newer Older
1 2 3
/*
 * IDirect3DSurface9 implementation
 *
4
 * Copyright 2002-2005 Jason Edmeades
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *                     Raphael Junqueira
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22 23 24
 */

#include "config.h"
#include "d3d9_private.h"

25
WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
26 27

/* IDirect3DSurface9 IUnknown parts follow: */
28
static HRESULT WINAPI IDirect3DSurface9Impl_QueryInterface(LPDIRECT3DSURFACE9 iface, REFIID riid, LPVOID* ppobj) {
29
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
30

Henri Verbeet's avatar
Henri Verbeet committed
31 32
    TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), ppobj);

33
    if (IsEqualGUID(riid, &IID_IUnknown)
34
        || IsEqualGUID(riid, &IID_IDirect3DResource9)
35
        || IsEqualGUID(riid, &IID_IDirect3DSurface9)) {
36
        IDirect3DSurface9_AddRef(iface);
37
        *ppobj = This;
H. Verbeet's avatar
H. Verbeet committed
38
        return S_OK;
39 40 41
    }

    WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
H. Verbeet's avatar
H. Verbeet committed
42
    *ppobj = NULL;
43 44 45
    return E_NOINTERFACE;
}

46
static ULONG WINAPI IDirect3DSurface9Impl_AddRef(LPDIRECT3DSURFACE9 iface) {
47
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
48

Henri Verbeet's avatar
Henri Verbeet committed
49
    TRACE("iface %p.\n", iface);
50

51 52 53 54
    if (This->forwardReference) {
        /* Forward refcounting */
        TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference);
        return IUnknown_AddRef(This->forwardReference);
55 56 57
    } else {
        /* No container, handle our own refcounting */
        ULONG ref = InterlockedIncrement(&This->ref);
Henri Verbeet's avatar
Henri Verbeet committed
58 59 60

        TRACE("%p increasing refcount to %u.\n", iface, ref);

61 62 63 64 65 66 67
        if (ref == 1)
        {
            if (This->parentDevice) IDirect3DDevice9Ex_AddRef(This->parentDevice);
            wined3d_mutex_lock();
            IWineD3DSurface_AddRef(This->wineD3DSurface);
            wined3d_mutex_unlock();
        }
68 69 70

        return ref;
    }
71

72 73
}

74
static ULONG WINAPI IDirect3DSurface9Impl_Release(LPDIRECT3DSURFACE9 iface) {
75
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
76

Henri Verbeet's avatar
Henri Verbeet committed
77
    TRACE("iface %p.\n", iface);
78

79
    if (This->forwardReference) {
80
        /* Forward to the containerParent */
81 82
        TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference);
        return IUnknown_Release(This->forwardReference);
83 84 85
    } else {
        /* No container, handle our own refcounting */
        ULONG ref = InterlockedDecrement(&This->ref);
Henri Verbeet's avatar
Henri Verbeet committed
86 87

        TRACE("%p decreasing refcount to %u.\n", iface, ref);
88

89
        if (ref == 0) {
90 91
            IDirect3DDevice9Ex *parentDevice = This->parentDevice;

92 93 94
            wined3d_mutex_lock();
            IWineD3DSurface_Release(This->wineD3DSurface);
            wined3d_mutex_unlock();
95 96 97

            /* Release the device last, as it may cause the device to be destroyed. */
            if (parentDevice) IDirect3DDevice9Ex_Release(parentDevice);
98
        }
99

100
        return ref;
101 102 103 104
    }
}

/* IDirect3DSurface9 IDirect3DResource9 Interface follow: */
105 106
static HRESULT WINAPI IDirect3DSurface9Impl_GetDevice(IDirect3DSurface9 *iface, IDirect3DDevice9 **device)
{
107
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
Henri Verbeet's avatar
Henri Verbeet committed
108

109
    TRACE("iface %p, device %p.\n", iface, device);
110

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    if (This->forwardReference)
    {
        IDirect3DResource9 *resource;
        HRESULT hr;

        hr = IUnknown_QueryInterface(This->forwardReference, &IID_IDirect3DResource9, (void **)&resource);
        if (SUCCEEDED(hr))
        {
            hr = IDirect3DResource9_GetDevice(resource, device);
            IDirect3DResource9_Release(resource);

            TRACE("Returning device %p.\n", *device);
        }

        return hr;
    }

128 129
    *device = (IDirect3DDevice9 *)This->parentDevice;
    IDirect3DDevice9_AddRef(*device);
130

131 132 133
    TRACE("Returning device %p.\n", *device);

    return D3D_OK;
134 135
}

136
static HRESULT WINAPI IDirect3DSurface9Impl_SetPrivateData(LPDIRECT3DSURFACE9 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
137
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
138
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
139 140 141

    TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
            iface, debugstr_guid(refguid), pData, SizeOfData, Flags);
142

143
    wined3d_mutex_lock();
144
    hr = IWineD3DSurface_SetPrivateData(This->wineD3DSurface, refguid, pData, SizeOfData, Flags);
145 146
    wined3d_mutex_unlock();

147
    return hr;
148 149
}

150
static HRESULT WINAPI IDirect3DSurface9Impl_GetPrivateData(LPDIRECT3DSURFACE9 iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
151
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
152
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
153 154 155

    TRACE("iface %p, guid %s, data %p, data_size %p.\n",
            iface, debugstr_guid(refguid), pData, pSizeOfData);
156

157
    wined3d_mutex_lock();
158
    hr = IWineD3DSurface_GetPrivateData(This->wineD3DSurface, refguid, pData, pSizeOfData);
159 160
    wined3d_mutex_unlock();

161
    return hr;
162 163
}

164
static HRESULT WINAPI IDirect3DSurface9Impl_FreePrivateData(LPDIRECT3DSURFACE9 iface, REFGUID refguid) {
165
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
166
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
167 168

    TRACE("iface %p, guid %s.\n", iface, debugstr_guid(refguid));
169

170
    wined3d_mutex_lock();
171
    hr = IWineD3DSurface_FreePrivateData(This->wineD3DSurface, refguid);
172 173
    wined3d_mutex_unlock();

174
    return hr;
175 176
}

177
static DWORD WINAPI IDirect3DSurface9Impl_SetPriority(LPDIRECT3DSURFACE9 iface, DWORD PriorityNew) {
178
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
179
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
180 181

    TRACE("iface %p, priority %u.\n", iface, PriorityNew);
182

183
    wined3d_mutex_lock();
184
    hr = IWineD3DSurface_SetPriority(This->wineD3DSurface, PriorityNew);
185 186
    wined3d_mutex_unlock();

187
    return hr;
188 189
}

190
static DWORD WINAPI IDirect3DSurface9Impl_GetPriority(LPDIRECT3DSURFACE9 iface) {
191
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
192
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
193 194

    TRACE("iface %p.\n", iface);
195

196
    wined3d_mutex_lock();
197
    hr = IWineD3DSurface_GetPriority(This->wineD3DSurface);
198 199
    wined3d_mutex_unlock();

200
    return hr;
201 202
}

203
static void WINAPI IDirect3DSurface9Impl_PreLoad(LPDIRECT3DSURFACE9 iface) {
204
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
Henri Verbeet's avatar
Henri Verbeet committed
205 206

    TRACE("iface %p.\n", iface);
207

208
    wined3d_mutex_lock();
209
    IWineD3DSurface_PreLoad(This->wineD3DSurface);
210
    wined3d_mutex_unlock();
211 212
}

213
static D3DRESOURCETYPE WINAPI IDirect3DSurface9Impl_GetType(LPDIRECT3DSURFACE9 iface) {
214
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
215
    D3DRESOURCETYPE ret;
Henri Verbeet's avatar
Henri Verbeet committed
216 217

    TRACE("iface %p.\n", iface);
218

219
    wined3d_mutex_lock();
220
    ret = IWineD3DSurface_GetType(This->wineD3DSurface);
221 222
    wined3d_mutex_unlock();

223
    return ret;
224 225 226
}

/* IDirect3DSurface9 Interface follow: */
227
static HRESULT WINAPI IDirect3DSurface9Impl_GetContainer(LPDIRECT3DSURFACE9 iface, REFIID riid, void** ppContainer) {
228
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
229
    HRESULT res;
230

Henri Verbeet's avatar
Henri Verbeet committed
231
    TRACE("iface %p, riid %s, container %p.\n", iface, debugstr_guid(riid), ppContainer);
232

233 234
    if (!This->container) return E_NOINTERFACE;

235 236
    if (!ppContainer) {
        ERR("Called without a valid ppContainer\n");
237
    }
238

239
    res = IUnknown_QueryInterface(This->container, riid, ppContainer);
240 241 242

    TRACE("Returning ppContainer %p, *ppContainer %p\n", ppContainer, *ppContainer);

243 244 245
    return res;
}

246
static HRESULT WINAPI IDirect3DSurface9Impl_GetDesc(LPDIRECT3DSURFACE9 iface, D3DSURFACE_DESC* pDesc) {
247
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
248
    WINED3DSURFACE_DESC wined3ddesc;
249
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
250 251

    TRACE("iface %p, desc %p.\n", iface, pDesc);
252

253
    wined3d_mutex_lock();
254
    hr = IWineD3DSurface_GetDesc(This->wineD3DSurface, &wined3ddesc);
255
    wined3d_mutex_unlock();
256

257 258 259 260 261 262 263 264 265 266 267
    if (SUCCEEDED(hr))
    {
        pDesc->Format = d3dformat_from_wined3dformat(wined3ddesc.format);
        pDesc->Type = wined3ddesc.resource_type;
        pDesc->Usage = wined3ddesc.usage;
        pDesc->Pool = wined3ddesc.pool;
        pDesc->MultiSampleType = wined3ddesc.multisample_type;
        pDesc->MultiSampleQuality = wined3ddesc.multisample_quality;
        pDesc->Width = wined3ddesc.width;
        pDesc->Height = wined3ddesc.height;
    }
268

269
    return hr;
270 271
}

272
static HRESULT WINAPI IDirect3DSurface9Impl_LockRect(LPDIRECT3DSURFACE9 iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
273
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
274
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
275 276

    TRACE("iface %p, locked_rect %p, rect %p, flags %#x.\n", iface, pLockedRect, pRect, Flags);
277

278
    wined3d_mutex_lock();
279
    hr = IWineD3DSurface_LockRect(This->wineD3DSurface, (WINED3DLOCKED_RECT *) pLockedRect, pRect, Flags);
280 281
    wined3d_mutex_unlock();

282
    return hr;
283 284
}

285
static HRESULT WINAPI IDirect3DSurface9Impl_UnlockRect(LPDIRECT3DSURFACE9 iface) {
286
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
287
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
288 289

    TRACE("iface %p.\n", iface);
290

291
    wined3d_mutex_lock();
292
    hr = IWineD3DSurface_UnlockRect(This->wineD3DSurface);
293 294
    wined3d_mutex_unlock();

295 296 297 298 299
    switch(hr)
    {
        case WINEDDERR_NOTLOCKED:       return D3DERR_INVALIDCALL;
        default:                        return hr;
    }
300 301
}

302
static HRESULT WINAPI IDirect3DSurface9Impl_GetDC(LPDIRECT3DSURFACE9 iface, HDC* phdc) {
303
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
304
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
305 306

    TRACE("iface %p, hdc %p.\n", iface, phdc);
307

308 309 310 311 312 313 314
    if(!This->getdc_supported)
    {
        WARN("Surface does not support GetDC, returning D3DERR_INVALIDCALL\n");
        /* Don't touch the DC */
        return D3DERR_INVALIDCALL;
    }

315
    wined3d_mutex_lock();
316
    hr = IWineD3DSurface_GetDC(This->wineD3DSurface, phdc);
317 318
    wined3d_mutex_unlock();

319
    return hr;
320 321
}

322
static HRESULT WINAPI IDirect3DSurface9Impl_ReleaseDC(LPDIRECT3DSURFACE9 iface, HDC hdc) {
323
    IDirect3DSurface9Impl *This = (IDirect3DSurface9Impl *)iface;
324
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
325 326

    TRACE("iface %p, hdc %p.\n", iface, hdc);
327

328
    wined3d_mutex_lock();
329
    hr = IWineD3DSurface_ReleaseDC(This->wineD3DSurface, hdc);
330 331
    wined3d_mutex_unlock();

332 333 334 335
    switch(hr) {
        case WINEDDERR_NODC:    return WINED3DERR_INVALIDCALL;
        default:                return hr;
    }
336 337
}

338
static const IDirect3DSurface9Vtbl Direct3DSurface9_Vtbl =
339
{
340
    /* IUnknown */
341 342 343
    IDirect3DSurface9Impl_QueryInterface,
    IDirect3DSurface9Impl_AddRef,
    IDirect3DSurface9Impl_Release,
344
    /* IDirect3DResource9 */
345 346 347 348 349 350 351 352
    IDirect3DSurface9Impl_GetDevice,
    IDirect3DSurface9Impl_SetPrivateData,
    IDirect3DSurface9Impl_GetPrivateData,
    IDirect3DSurface9Impl_FreePrivateData,
    IDirect3DSurface9Impl_SetPriority,
    IDirect3DSurface9Impl_GetPriority,
    IDirect3DSurface9Impl_PreLoad,
    IDirect3DSurface9Impl_GetType,
353
    /* IDirect3DSurface9 */
354 355 356 357 358 359 360
    IDirect3DSurface9Impl_GetContainer,
    IDirect3DSurface9Impl_GetDesc,
    IDirect3DSurface9Impl_LockRect,
    IDirect3DSurface9Impl_UnlockRect,
    IDirect3DSurface9Impl_GetDC,
    IDirect3DSurface9Impl_ReleaseDC
};
361

362 363 364 365 366 367 368 369 370 371
static void STDMETHODCALLTYPE surface_wined3d_object_destroyed(void *parent)
{
    HeapFree(GetProcessHeap(), 0, parent);
}

static const struct wined3d_parent_ops d3d9_surface_wined3d_parent_ops =
{
    surface_wined3d_object_destroyed,
};

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
HRESULT surface_init(IDirect3DSurface9Impl *surface, IDirect3DDevice9Impl *device,
        UINT width, UINT height, D3DFORMAT format, BOOL lockable, BOOL discard, UINT level,
        DWORD usage, D3DPOOL pool, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality)
{
    HRESULT hr;

    surface->lpVtbl = &Direct3DSurface9_Vtbl;
    surface->ref = 1;

    switch (format)
    {
        case D3DFMT_A8R8G8B8:
        case D3DFMT_X8R8G8B8:
        case D3DFMT_R5G6B5:
        case D3DFMT_X1R5G5B5:
        case D3DFMT_A1R5G5B5:
        case D3DFMT_R8G8B8:
            surface->getdc_supported = TRUE;
            break;

        default:
            surface->getdc_supported = FALSE;
            break;
    }

    /* FIXME: Check MAX bounds of MultisampleQuality. */
    if (multisample_quality > 0)
    {
        FIXME("Multisample quality set to %u, substituting 0.\n", multisample_quality);
        multisample_quality = 0;
    }

    wined3d_mutex_lock();
    hr = IWineD3DDevice_CreateSurface(device->WineD3DDevice, width, height, wined3dformat_from_d3dformat(format),
            lockable, discard, level, &surface->wineD3DSurface, usage & WINED3DUSAGE_MASK, (WINED3DPOOL)pool,
407 408
            multisample_type, multisample_quality, SURFACE_OPENGL, (IUnknown *)surface,
            &d3d9_surface_wined3d_parent_ops);
409 410 411 412 413 414 415 416 417 418 419 420
    wined3d_mutex_unlock();
    if (FAILED(hr))
    {
        WARN("Failed to create wined3d surface, hr %#x.\n", hr);
        return hr;
    }

    surface->parentDevice = (IDirect3DDevice9Ex *)device;
    IDirect3DDevice9Ex_AddRef(surface->parentDevice);

    return D3D_OK;
}