device.c 108 KB
Newer Older
1 2 3
/*
 * IDirect3DDevice8 implementation
 *
4 5
 * Copyright 2002-2004 Jason Edmeades
 * Copyright 2004 Christian Costa
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
#include "config.h"

24
#include <math.h>
25
#include <stdarg.h>
26

27 28 29 30 31 32 33 34
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "wingdi.h"
#include "wine/debug.h"

#include "d3d8_private.h"

35
WINE_DEFAULT_DEBUG_CHANNEL(d3d8);
36

37 38 39 40 41 42 43
static void STDMETHODCALLTYPE d3d8_null_wined3d_object_destroyed(void *parent) {}

static const struct wined3d_parent_ops d3d8_null_wined3d_parent_ops =
{
    d3d8_null_wined3d_object_destroyed,
};

44
D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format)
45 46 47 48 49 50 51 52 53
{
    BYTE *c = (BYTE *)&format;

    /* Don't translate FOURCC formats */
    if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;

    switch(format)
    {
        case WINED3DFMT_UNKNOWN: return D3DFMT_UNKNOWN;
54 55 56 57 58 59 60 61
        case WINED3DFMT_B8G8R8_UNORM: return D3DFMT_R8G8B8;
        case WINED3DFMT_B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8;
        case WINED3DFMT_B8G8R8X8_UNORM: return D3DFMT_X8R8G8B8;
        case WINED3DFMT_B5G6R5_UNORM: return D3DFMT_R5G6B5;
        case WINED3DFMT_B5G5R5X1_UNORM: return D3DFMT_X1R5G5B5;
        case WINED3DFMT_B5G5R5A1_UNORM: return D3DFMT_A1R5G5B5;
        case WINED3DFMT_B4G4R4A4_UNORM: return D3DFMT_A4R4G4B4;
        case WINED3DFMT_B2G3R3_UNORM: return D3DFMT_R3G3B2;
62
        case WINED3DFMT_A8_UNORM: return D3DFMT_A8;
63 64
        case WINED3DFMT_B2G3R3A8_UNORM: return D3DFMT_A8R3G3B2;
        case WINED3DFMT_B4G4R4X4_UNORM: return D3DFMT_X4R4G4B4;
65 66
        case WINED3DFMT_R10G10B10A2_UNORM: return D3DFMT_A2B10G10R10;
        case WINED3DFMT_R16G16_UNORM: return D3DFMT_G16R16;
67 68 69 70 71
        case WINED3DFMT_P8_UINT_A8_UNORM: return D3DFMT_A8P8;
        case WINED3DFMT_P8_UINT: return D3DFMT_P8;
        case WINED3DFMT_L8_UNORM: return D3DFMT_L8;
        case WINED3DFMT_L8A8_UNORM: return D3DFMT_A8L8;
        case WINED3DFMT_L4A4_UNORM: return D3DFMT_A4L4;
72
        case WINED3DFMT_R8G8_SNORM: return D3DFMT_V8U8;
73 74
        case WINED3DFMT_R5G5_SNORM_L6_UNORM: return D3DFMT_L6V5U5;
        case WINED3DFMT_R8G8_SNORM_L8X8_UNORM: return D3DFMT_X8L8V8U8;
75 76
        case WINED3DFMT_R8G8B8A8_SNORM: return D3DFMT_Q8W8V8U8;
        case WINED3DFMT_R16G16_SNORM: return D3DFMT_V16U16;
77 78
        case WINED3DFMT_R10G11B11_SNORM: return D3DFMT_W11V11U10;
        case WINED3DFMT_R10G10B10_SNORM_A2_UNORM: return D3DFMT_A2W10V10U10;
79
        case WINED3DFMT_D16_LOCKABLE: return D3DFMT_D16_LOCKABLE;
80 81
        case WINED3DFMT_D32_UNORM: return D3DFMT_D32;
        case WINED3DFMT_S1_UINT_D15_UNORM: return D3DFMT_D15S1;
82
        case WINED3DFMT_D24_UNORM_S8_UINT: return D3DFMT_D24S8;
83 84
        case WINED3DFMT_X8D24_UNORM: return D3DFMT_D24X8;
        case WINED3DFMT_S4X4_UINT_D24_UNORM: return D3DFMT_D24X4S4;
85
        case WINED3DFMT_D16_UNORM: return D3DFMT_D16;
86
        case WINED3DFMT_VERTEXDATA: return D3DFMT_VERTEXDATA;
87 88
        case WINED3DFMT_R16_UINT: return D3DFMT_INDEX16;
        case WINED3DFMT_R32_UINT: return D3DFMT_INDEX32;
89
        default:
90
            FIXME("Unhandled wined3d format %#x.\n", format);
91 92 93 94
            return D3DFMT_UNKNOWN;
    }
}

95
enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format)
96 97 98 99 100 101 102 103 104
{
    BYTE *c = (BYTE *)&format;

    /* Don't translate FOURCC formats */
    if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;

    switch(format)
    {
        case D3DFMT_UNKNOWN: return WINED3DFMT_UNKNOWN;
105 106 107 108 109 110 111 112
        case D3DFMT_R8G8B8: return WINED3DFMT_B8G8R8_UNORM;
        case D3DFMT_A8R8G8B8: return WINED3DFMT_B8G8R8A8_UNORM;
        case D3DFMT_X8R8G8B8: return WINED3DFMT_B8G8R8X8_UNORM;
        case D3DFMT_R5G6B5: return WINED3DFMT_B5G6R5_UNORM;
        case D3DFMT_X1R5G5B5: return WINED3DFMT_B5G5R5X1_UNORM;
        case D3DFMT_A1R5G5B5: return WINED3DFMT_B5G5R5A1_UNORM;
        case D3DFMT_A4R4G4B4: return WINED3DFMT_B4G4R4A4_UNORM;
        case D3DFMT_R3G3B2: return WINED3DFMT_B2G3R3_UNORM;
113
        case D3DFMT_A8: return WINED3DFMT_A8_UNORM;
114 115
        case D3DFMT_A8R3G3B2: return WINED3DFMT_B2G3R3A8_UNORM;
        case D3DFMT_X4R4G4B4: return WINED3DFMT_B4G4R4X4_UNORM;
116 117
        case D3DFMT_A2B10G10R10: return WINED3DFMT_R10G10B10A2_UNORM;
        case D3DFMT_G16R16: return WINED3DFMT_R16G16_UNORM;
118 119 120 121 122
        case D3DFMT_A8P8: return WINED3DFMT_P8_UINT_A8_UNORM;
        case D3DFMT_P8: return WINED3DFMT_P8_UINT;
        case D3DFMT_L8: return WINED3DFMT_L8_UNORM;
        case D3DFMT_A8L8: return WINED3DFMT_L8A8_UNORM;
        case D3DFMT_A4L4: return WINED3DFMT_L4A4_UNORM;
123
        case D3DFMT_V8U8: return WINED3DFMT_R8G8_SNORM;
124 125
        case D3DFMT_L6V5U5: return WINED3DFMT_R5G5_SNORM_L6_UNORM;
        case D3DFMT_X8L8V8U8: return WINED3DFMT_R8G8_SNORM_L8X8_UNORM;
126 127
        case D3DFMT_Q8W8V8U8: return WINED3DFMT_R8G8B8A8_SNORM;
        case D3DFMT_V16U16: return WINED3DFMT_R16G16_SNORM;
128 129
        case D3DFMT_W11V11U10: return WINED3DFMT_R10G11B11_SNORM;
        case D3DFMT_A2W10V10U10: return WINED3DFMT_R10G10B10_SNORM_A2_UNORM;
130
        case D3DFMT_D16_LOCKABLE: return WINED3DFMT_D16_LOCKABLE;
131 132
        case D3DFMT_D32: return WINED3DFMT_D32_UNORM;
        case D3DFMT_D15S1: return WINED3DFMT_S1_UINT_D15_UNORM;
133
        case D3DFMT_D24S8: return WINED3DFMT_D24_UNORM_S8_UINT;
134 135
        case D3DFMT_D24X8: return WINED3DFMT_X8D24_UNORM;
        case D3DFMT_D24X4S4: return WINED3DFMT_S4X4_UINT_D24_UNORM;
136
        case D3DFMT_D16: return WINED3DFMT_D16_UNORM;
137
        case D3DFMT_VERTEXDATA: return WINED3DFMT_VERTEXDATA;
138 139
        case D3DFMT_INDEX16: return WINED3DFMT_R16_UINT;
        case D3DFMT_INDEX32: return WINED3DFMT_R32_UINT;
140 141 142 143 144 145
        default:
            FIXME("Unhandled D3DFORMAT %#x\n", format);
            return WINED3DFMT_UNKNOWN;
    }
}

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
static UINT vertex_count_from_primitive_count(D3DPRIMITIVETYPE primitive_type, UINT primitive_count)
{
    switch(primitive_type)
    {
        case D3DPT_POINTLIST:
            return primitive_count;

        case D3DPT_LINELIST:
            return primitive_count * 2;

        case D3DPT_LINESTRIP:
            return primitive_count + 1;

        case D3DPT_TRIANGLELIST:
            return primitive_count * 3;

        case D3DPT_TRIANGLESTRIP:
        case D3DPT_TRIANGLEFAN:
            return primitive_count + 2;

        default:
            FIXME("Unhandled primitive type %#x\n", primitive_type);
            return 0;
    }
}

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
static void present_parameters_from_wined3d_swapchain_desc(D3DPRESENT_PARAMETERS *present_parameters,
        const struct wined3d_swapchain_desc *swapchain_desc)
{
    present_parameters->BackBufferWidth = swapchain_desc->backbuffer_width;
    present_parameters->BackBufferHeight = swapchain_desc->backbuffer_height;
    present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(swapchain_desc->backbuffer_format);
    present_parameters->BackBufferCount = swapchain_desc->backbuffer_count;
    present_parameters->MultiSampleType = swapchain_desc->multisample_type;
    present_parameters->SwapEffect = swapchain_desc->swap_effect;
    present_parameters->hDeviceWindow = swapchain_desc->device_window;
    present_parameters->Windowed = swapchain_desc->windowed;
    present_parameters->EnableAutoDepthStencil = swapchain_desc->enable_auto_depth_stencil;
    present_parameters->AutoDepthStencilFormat
            = d3dformat_from_wined3dformat(swapchain_desc->auto_depth_stencil_format);
    present_parameters->Flags = swapchain_desc->flags;
    present_parameters->FullScreen_RefreshRateInHz = swapchain_desc->refresh_rate;
    present_parameters->FullScreen_PresentationInterval = swapchain_desc->swap_interval;
}

191
static BOOL wined3d_swapchain_desc_from_present_parameters(struct wined3d_swapchain_desc *swapchain_desc,
192 193
        const D3DPRESENT_PARAMETERS *present_parameters)
{
194
    if (!present_parameters->SwapEffect || present_parameters->SwapEffect > D3DSWAPEFFECT_COPY_VSYNC)
195 196 197 198 199
    {
        WARN("Invalid swap effect %u passed.\n", present_parameters->SwapEffect);
        return FALSE;
    }
    if (present_parameters->BackBufferCount > 3
200 201
            || ((present_parameters->SwapEffect == D3DSWAPEFFECT_COPY
            || present_parameters->SwapEffect == D3DSWAPEFFECT_COPY_VSYNC)
202 203 204 205 206 207
            && present_parameters->BackBufferCount > 1))
    {
        WARN("Invalid backbuffer count %u.\n", present_parameters->BackBufferCount);
        return FALSE;
    }

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    swapchain_desc->backbuffer_width = present_parameters->BackBufferWidth;
    swapchain_desc->backbuffer_height = present_parameters->BackBufferHeight;
    swapchain_desc->backbuffer_format = wined3dformat_from_d3dformat(present_parameters->BackBufferFormat);
    swapchain_desc->backbuffer_count = max(1, present_parameters->BackBufferCount);
    swapchain_desc->multisample_type = present_parameters->MultiSampleType;
    swapchain_desc->multisample_quality = 0; /* d3d9 only */
    swapchain_desc->swap_effect = present_parameters->SwapEffect;
    swapchain_desc->device_window = present_parameters->hDeviceWindow;
    swapchain_desc->windowed = present_parameters->Windowed;
    swapchain_desc->enable_auto_depth_stencil = present_parameters->EnableAutoDepthStencil;
    swapchain_desc->auto_depth_stencil_format
            = wined3dformat_from_d3dformat(present_parameters->AutoDepthStencilFormat);
    swapchain_desc->flags = present_parameters->Flags;
    swapchain_desc->refresh_rate = present_parameters->FullScreen_RefreshRateInHz;
    swapchain_desc->swap_interval = present_parameters->FullScreen_PresentationInterval;
    swapchain_desc->auto_restore_display_mode = TRUE;
224 225

    return TRUE;
226 227
}

228
/* Handle table functions */
229
static DWORD d3d8_allocate_handle(struct d3d8_handle_table *t, void *object, enum d3d8_handle_type type)
230
{
231 232
    struct d3d8_handle_entry *entry;

233 234
    if (t->free_entries)
    {
235
        DWORD index = t->free_entries - t->entries;
236
        /* Use a free handle */
237 238 239
        entry = t->free_entries;
        if (entry->type != D3D8_HANDLE_FREE)
        {
240
            ERR("Handle %u(%p) is in the free list, but has type %#x.\n", index, entry, entry->type);
241 242 243 244 245 246
            return D3D8_INVALID_HANDLE;
        }
        t->free_entries = entry->object;
        entry->object = object;
        entry->type = type;

247
        return index;
248
    }
249 250 251

    if (!(t->entry_count < t->table_size))
    {
252
        /* Grow the table */
253
        UINT new_size = t->table_size + (t->table_size >> 1);
254 255 256 257 258 259 260
        struct d3d8_handle_entry *new_entries = HeapReAlloc(GetProcessHeap(),
                0, t->entries, new_size * sizeof(*t->entries));
        if (!new_entries)
        {
            ERR("Failed to grow the handle table.\n");
            return D3D8_INVALID_HANDLE;
        }
261 262
        t->entries = new_entries;
        t->table_size = new_size;
263 264
    }

265 266 267 268
    entry = &t->entries[t->entry_count];
    entry->object = object;
    entry->type = type;

269
    return t->entry_count++;
270 271
}

272
static void *d3d8_free_handle(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
273
{
274 275
    struct d3d8_handle_entry *entry;
    void *object;
276

277 278 279 280 281
    if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
    {
        WARN("Invalid handle %u passed.\n", handle);
        return NULL;
    }
282 283

    entry = &t->entries[handle];
284 285 286 287 288 289 290 291 292
    if (entry->type != type)
    {
        WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
        return NULL;
    }

    object = entry->object;
    entry->object = t->free_entries;
    entry->type = D3D8_HANDLE_FREE;
293 294 295 296 297
    t->free_entries = entry;

    return object;
}

298
static void *d3d8_get_object(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
299
{
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    struct d3d8_handle_entry *entry;

    if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
    {
        WARN("Invalid handle %u passed.\n", handle);
        return NULL;
    }

    entry = &t->entries[handle];
    if (entry->type != type)
    {
        WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
        return NULL;
    }

    return entry->object;
316 317
}

318
static HRESULT WINAPI d3d8_device_QueryInterface(IDirect3DDevice8 *iface, REFIID riid, void **out)
319
{
320 321
    TRACE("iface %p, riid %s, out %p.\n",
            iface, debugstr_guid(riid), out);
Henri Verbeet's avatar
Henri Verbeet committed
322

323 324 325
    if (IsEqualGUID(riid, &IID_IDirect3DDevice8)
            || IsEqualGUID(riid, &IID_IUnknown))
    {
326
        IDirect3DDevice8_AddRef(iface);
327
        *out = iface;
H. Verbeet's avatar
H. Verbeet committed
328
        return S_OK;
329 330
    }

331 332
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

333
    *out = NULL;
334 335 336
    return E_NOINTERFACE;
}

337
static ULONG WINAPI d3d8_device_AddRef(IDirect3DDevice8 *iface)
338
{
339 340
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    ULONG ref = InterlockedIncrement(&device->ref);
341

Henri Verbeet's avatar
Henri Verbeet committed
342
    TRACE("%p increasing refcount to %u.\n", iface, ref);
343 344

    return ref;
345 346
}

347
static ULONG WINAPI d3d8_device_Release(IDirect3DDevice8 *iface)
348
{
349
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
350 351
    ULONG ref;

352 353 354 355
    if (device->inDestruction)
        return 0;

    ref = InterlockedDecrement(&device->ref);
356

Henri Verbeet's avatar
Henri Verbeet committed
357
    TRACE("%p decreasing refcount to %u.\n", iface, ref);
358

359 360 361
    if (!ref)
    {
        IDirect3D8 *parent = device->d3d_parent;
362
        unsigned i;
363

364
        TRACE("Releasing wined3d device %p.\n", device->wined3d_device);
365 366 367

        wined3d_mutex_lock();

368
        device->inDestruction = TRUE;
369

370
        for (i = 0; i < device->numConvertedDecls; ++i)
371
        {
372
            d3d8_vertex_declaration_destroy(device->decls[i].declaration);
373
        }
374
        HeapFree(GetProcessHeap(), 0, device->decls);
375

376 377
        if (device->vertex_buffer)
            wined3d_buffer_decref(device->vertex_buffer);
378 379
        if (device->index_buffer)
            wined3d_buffer_decref(device->index_buffer);
380

381 382 383 384 385
        wined3d_device_uninit_3d(device->wined3d_device);
        wined3d_device_release_focus_window(device->wined3d_device);
        wined3d_device_decref(device->wined3d_device);
        HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
        HeapFree(GetProcessHeap(), 0, device);
386 387

        wined3d_mutex_unlock();
388 389

        IDirect3D8_Release(parent);
390 391 392 393
    }
    return ref;
}

394
static HRESULT WINAPI d3d8_device_TestCooperativeLevel(IDirect3DDevice8 *iface)
395
{
396
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
397

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

400 401 402
    TRACE("device state: %#x.\n", device->device_state);

    switch (device->device_state)
403
    {
404 405 406 407 408 409 410
        default:
        case D3D8_DEVICE_STATE_OK:
            return D3D_OK;
        case D3D8_DEVICE_STATE_LOST:
            return D3DERR_DEVICELOST;
        case D3D8_DEVICE_STATE_NOT_RESET:
            return D3DERR_DEVICENOTRESET;
411
    }
412 413
}

414
static UINT WINAPI d3d8_device_GetAvailableTextureMem(IDirect3DDevice8 *iface)
415
{
416
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
417
    UINT ret;
418

Henri Verbeet's avatar
Henri Verbeet committed
419
    TRACE("iface %p.\n", iface);
420 421

    wined3d_mutex_lock();
422
    ret = wined3d_device_get_available_texture_mem(device->wined3d_device);
423 424
    wined3d_mutex_unlock();

425
    return ret;
426 427
}

428
static HRESULT WINAPI d3d8_device_ResourceManagerDiscardBytes(IDirect3DDevice8 *iface, DWORD byte_count)
429
{
430
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
431

432 433 434 435
    TRACE("iface %p, byte_count %u.\n", iface, byte_count);

    if (byte_count)
        FIXME("Byte count ignored.\n");
436 437

    wined3d_mutex_lock();
438
    wined3d_device_evict_managed_resources(device->wined3d_device);
439 440
    wined3d_mutex_unlock();

441
    return D3D_OK;
442
}
443

444
static HRESULT WINAPI d3d8_device_GetDirect3D(IDirect3DDevice8 *iface, IDirect3D8 **d3d8)
445
{
446
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
447

448
    TRACE("iface %p, d3d8 %p.\n", iface, d3d8);
449

450
    if (!d3d8)
451
        return D3DERR_INVALIDCALL;
452

453
    return IDirect3D8_QueryInterface(device->d3d_parent, &IID_IDirect3D8, (void **)d3d8);
454
}
455

456
static HRESULT WINAPI d3d8_device_GetDeviceCaps(IDirect3DDevice8 *iface, D3DCAPS8 *caps)
457
{
458 459 460
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    WINED3DCAPS *wined3d_caps;
    HRESULT hr;
461

462
    TRACE("iface %p, caps %p.\n", iface, caps);
Henri Verbeet's avatar
Henri Verbeet committed
463

464
    if (!caps)
465
        return D3DERR_INVALIDCALL;
466 467

    if (!(wined3d_caps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wined3d_caps))))
468
        return D3DERR_INVALIDCALL; /* well this is what MSDN says to return */
469

470
    wined3d_mutex_lock();
471
    hr = wined3d_device_get_device_caps(device->wined3d_device, wined3d_caps);
472 473
    wined3d_mutex_unlock();

474 475 476
    fixup_caps(wined3d_caps);
    WINECAPSTOD3D8CAPS(caps, wined3d_caps)
    HeapFree(GetProcessHeap(), 0, wined3d_caps);
477

478
    return hr;
479
}
480

481
static HRESULT WINAPI d3d8_device_GetDisplayMode(IDirect3DDevice8 *iface, D3DDISPLAYMODE *mode)
482
{
483
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
484
    struct wined3d_display_mode wined3d_mode;
485
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
486

487
    TRACE("iface %p, mode %p.\n", iface, mode);
488

489
    wined3d_mutex_lock();
490
    hr = wined3d_device_get_display_mode(device->wined3d_device, 0, &wined3d_mode, NULL);
491
    wined3d_mutex_unlock();
492

493
    if (SUCCEEDED(hr))
494 495 496 497 498 499
    {
        mode->Width = wined3d_mode.width;
        mode->Height = wined3d_mode.height;
        mode->RefreshRate = wined3d_mode.refresh_rate;
        mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
    }
500

501
    return hr;
502
}
503

504 505
static HRESULT WINAPI d3d8_device_GetCreationParameters(IDirect3DDevice8 *iface,
        D3DDEVICE_CREATION_PARAMETERS *parameters)
506
{
507
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
508

509
    TRACE("iface %p, parameters %p.\n", iface, parameters);
510

511
    wined3d_mutex_lock();
512
    wined3d_device_get_creation_parameters(device->wined3d_device,
513
            (struct wined3d_device_creation_parameters *)parameters);
514 515
    wined3d_mutex_unlock();

516
    return D3D_OK;
517
}
518

519 520
static HRESULT WINAPI d3d8_device_SetCursorProperties(IDirect3DDevice8 *iface,
        UINT hotspot_x, UINT hotspot_y, IDirect3DSurface8 *bitmap)
521
{
522
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
523
    struct d3d8_surface *bitmap_impl = unsafe_impl_from_IDirect3DSurface8(bitmap);
524
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
525 526

    TRACE("iface %p, hotspot_x %u, hotspot_y %u, bitmap %p.\n",
527
            iface, hotspot_x, hotspot_y, bitmap);
Henri Verbeet's avatar
Henri Verbeet committed
528

529
    if (!bitmap)
530 531 532
    {
        WARN("No cursor bitmap, returning D3DERR_INVALIDCALL.\n");
        return D3DERR_INVALIDCALL;
533
    }
534

535
    wined3d_mutex_lock();
536
    hr = wined3d_device_set_cursor_properties(device->wined3d_device,
537
            hotspot_x, hotspot_y, bitmap_impl->wined3d_texture, bitmap_impl->sub_resource_idx);
538 539
    wined3d_mutex_unlock();

540
    return hr;
541
}
542

543
static void WINAPI d3d8_device_SetCursorPosition(IDirect3DDevice8 *iface, UINT x, UINT y, DWORD flags)
544
{
545
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
546

547
    TRACE("iface %p, x %u, y %u, flags %#x.\n", iface, x, y, flags);
548

549
    wined3d_mutex_lock();
550
    wined3d_device_set_cursor_position(device->wined3d_device, x, y, flags);
551
    wined3d_mutex_unlock();
552
}
553

554
static BOOL WINAPI d3d8_device_ShowCursor(IDirect3DDevice8 *iface, BOOL show)
555
{
556
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
557
    BOOL ret;
Henri Verbeet's avatar
Henri Verbeet committed
558

559
    TRACE("iface %p, show %#x.\n", iface, show);
560

561
    wined3d_mutex_lock();
562
    ret = wined3d_device_show_cursor(device->wined3d_device, show);
563 564
    wined3d_mutex_unlock();

565
    return ret;
566
}
567

568
static HRESULT WINAPI d3d8_device_CreateAdditionalSwapChain(IDirect3DDevice8 *iface,
569 570
        D3DPRESENT_PARAMETERS *present_parameters, IDirect3DSwapChain8 **swapchain)
{
571
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
572
    struct wined3d_swapchain_desc desc;
573
    struct d3d8_swapchain *object;
574
    UINT i, count;
575
    HRESULT hr;
576

Henri Verbeet's avatar
Henri Verbeet committed
577
    TRACE("iface %p, present_parameters %p, swapchain %p.\n",
578
            iface, present_parameters, swapchain);
579

580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
    if (!present_parameters->Windowed)
    {
        WARN("Trying to create an additional fullscreen swapchain, returning D3DERR_INVALIDCALL.\n");
        return D3DERR_INVALIDCALL;
    }

    wined3d_mutex_lock();
    count = wined3d_device_get_swapchain_count(device->wined3d_device);
    for (i = 0; i < count; ++i)
    {
        struct wined3d_swapchain *wined3d_swapchain;

        wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, i);
        wined3d_swapchain_get_desc(wined3d_swapchain, &desc);

        if (!desc.windowed)
        {
            wined3d_mutex_unlock();
            WARN("Trying to create an additional swapchain in fullscreen mode, returning D3DERR_INVALIDCALL.\n");
            return D3DERR_INVALIDCALL;
        }
    }
    wined3d_mutex_unlock();

604 605
    if (!wined3d_swapchain_desc_from_present_parameters(&desc, present_parameters))
        return D3DERR_INVALIDCALL;
606
    if (SUCCEEDED(hr = d3d8_swapchain_create(device, &desc, &object)))
607
        *swapchain = &object->IDirect3DSwapChain8_iface;
608
    present_parameters_from_wined3d_swapchain_desc(present_parameters, &desc);
609

610
    return hr;
611
}
612

613
static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
614 615 616 617
{
    struct wined3d_resource_desc desc;

    wined3d_resource_get_desc(resource, &desc);
618
    if (desc.pool == WINED3D_POOL_DEFAULT)
619
    {
620
        struct d3d8_surface *surface;
621

622
        if (desc.resource_type == WINED3D_RTYPE_TEXTURE_2D)
623 624 625 626 627 628 629 630 631 632 633 634 635 636
        {
            IUnknown *parent = wined3d_resource_get_parent(resource);
            IDirect3DBaseTexture8 *texture;

            if (SUCCEEDED(IUnknown_QueryInterface(parent, &IID_IDirect3DBaseTexture8, (void **)&texture)))
            {
                IDirect3DBaseTexture8_Release(texture);
                WARN("Texture %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", texture, resource);
                return D3DERR_DEVICELOST;
            }

            return D3D_OK;
        }

637
        if (desc.resource_type != WINED3D_RTYPE_SURFACE)
638 639
        {
            WARN("Resource %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", resource);
640
            return D3DERR_DEVICELOST;
641 642 643
        }

        surface = wined3d_resource_get_parent(resource);
644
        if (surface->resource.refcount)
645 646
        {
            WARN("Surface %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", surface, resource);
647
            return D3DERR_DEVICELOST;
648 649 650 651 652
        }

        WARN("Surface %p (resource %p) is an implicit resource with ref 0.\n", surface, resource);
    }

653
    return D3D_OK;
654 655
}

656 657
static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface,
        D3DPRESENT_PARAMETERS *present_parameters)
658
{
659
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
660
    struct wined3d_swapchain_desc swapchain_desc;
661 662
    HRESULT hr;

663
    TRACE("iface %p, present_parameters %p.\n", iface, present_parameters);
664

665 666 667 668 669
    if (device->device_state == D3D8_DEVICE_STATE_LOST)
    {
        WARN("App not active, returning D3DERR_DEVICELOST.\n");
        return D3DERR_DEVICELOST;
    }
670 671
    if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, present_parameters))
        return D3DERR_INVALIDCALL;
672

673
    wined3d_mutex_lock();
674 675 676 677 678 679 680

    if (device->vertex_buffer)
    {
        wined3d_buffer_decref(device->vertex_buffer);
        device->vertex_buffer = NULL;
        device->vertex_buffer_size = 0;
    }
681 682 683 684 685 686
    if (device->index_buffer)
    {
        wined3d_buffer_decref(device->index_buffer);
        device->index_buffer = NULL;
        device->index_buffer_size = 0;
    }
687

688 689
    if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc,
            NULL, reset_enum_callback, TRUE)))
690
    {
691
        present_parameters->BackBufferCount = swapchain_desc.backbuffer_count;
692
        wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
693
        device->device_state = D3D8_DEVICE_STATE_OK;
694 695 696
    }
    else
    {
697
        device->device_state = D3D8_DEVICE_STATE_NOT_RESET;
698
    }
699
    wined3d_mutex_unlock();
700 701

    return hr;
702
}
703

704 705
static HRESULT WINAPI d3d8_device_Present(IDirect3DDevice8 *iface, const RECT *src_rect,
        const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
706
{
707
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
708

709 710
    TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
            iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect), dst_window_override, dirty_region);
711

712 713 714 715 716 717 718
    /* Fraps does not hook IDirect3DDevice8::Present regardless of the hotpatch
     * attribute. It only hooks IDirect3DSwapChain8::Present. Yet it properly
     * shows a framerate on Windows in applications that only call the device
     * method, like e.g. the dx8 sdk samples. The conclusion is that native
     * calls the swapchain's public method from the device. */
    return IDirect3DSwapChain8_Present(&device->implicit_swapchain->IDirect3DSwapChain8_iface,
            src_rect, dst_rect, dst_window_override, dirty_region);
719
}
720

721 722
static HRESULT WINAPI d3d8_device_GetBackBuffer(IDirect3DDevice8 *iface,
        UINT backbuffer_idx, D3DBACKBUFFER_TYPE backbuffer_type, IDirect3DSurface8 **backbuffer)
723
{
724
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
725
    struct wined3d_swapchain *wined3d_swapchain;
726
    struct wined3d_texture *wined3d_texture;
727
    struct d3d8_surface *surface_impl;
728

Henri Verbeet's avatar
Henri Verbeet committed
729
    TRACE("iface %p, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
730
            iface, backbuffer_idx, backbuffer_type, backbuffer);
731

732 733
    /* backbuffer_type is ignored by native. */

734
    /* No need to check for backbuffer == NULL, Windows crashes in that case. */
735 736
    wined3d_mutex_lock();

737 738
    wined3d_swapchain = device->implicit_swapchain->wined3d_swapchain;
    if (!(wined3d_texture = wined3d_swapchain_get_back_buffer(wined3d_swapchain, backbuffer_idx)))
739 740 741 742 743 744
    {
        wined3d_mutex_unlock();
        *backbuffer = NULL;
        return D3DERR_INVALIDCALL;
    }

745
    surface_impl = wined3d_texture_get_sub_resource_parent(wined3d_texture, 0);
746 747 748 749 750
    *backbuffer = &surface_impl->IDirect3DSurface8_iface;
    IDirect3DSurface8_AddRef(*backbuffer);

    wined3d_mutex_unlock();
    return D3D_OK;
751
}
752

753
static HRESULT WINAPI d3d8_device_GetRasterStatus(IDirect3DDevice8 *iface, D3DRASTER_STATUS *raster_status)
754
{
755
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
756
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
757

758
    TRACE("iface %p, raster_status %p.\n", iface, raster_status);
759

760
    wined3d_mutex_lock();
761
    hr = wined3d_device_get_raster_status(device->wined3d_device, 0, (struct wined3d_raster_status *)raster_status);
762 763
    wined3d_mutex_unlock();

764
    return hr;
765
}
766

767
static void WINAPI d3d8_device_SetGammaRamp(IDirect3DDevice8 *iface, DWORD flags, const D3DGAMMARAMP *ramp)
768
{
769
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
770

771
    TRACE("iface %p, flags %#x, ramp %p.\n", iface, flags, ramp);
772

773
    /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
774
    wined3d_mutex_lock();
775
    wined3d_device_set_gamma_ramp(device->wined3d_device, 0, flags, (const struct wined3d_gamma_ramp *)ramp);
776
    wined3d_mutex_unlock();
777
}
778

779
static void WINAPI d3d8_device_GetGammaRamp(IDirect3DDevice8 *iface, D3DGAMMARAMP *ramp)
780
{
781
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
782

783
    TRACE("iface %p, ramp %p.\n", iface, ramp);
784

785
    /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
786
    wined3d_mutex_lock();
787
    wined3d_device_get_gamma_ramp(device->wined3d_device, 0, (struct wined3d_gamma_ramp *)ramp);
788
    wined3d_mutex_unlock();
789
}
790

791
static HRESULT WINAPI d3d8_device_CreateTexture(IDirect3DDevice8 *iface,
792 793 794
        UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format,
        D3DPOOL pool, IDirect3DTexture8 **texture)
{
795
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
796
    struct d3d8_texture *object;
797
    HRESULT hr;
798

799 800
    TRACE("iface %p, width %u, height %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
            iface, width, height, levels, usage, format, pool, texture);
801

802
    *texture = NULL;
803 804
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
805
        return D3DERR_OUTOFVIDEOMEMORY;
806

807
    hr = texture_init(object, device, width, height, levels, usage, format, pool);
808 809 810
    if (FAILED(hr))
    {
        WARN("Failed to initialize texture, hr %#x.\n", hr);
811
        HeapFree(GetProcessHeap(), 0, object);
812 813 814 815
        return hr;
    }

    TRACE("Created texture %p.\n", object);
816
    *texture = (IDirect3DTexture8 *)&object->IDirect3DBaseTexture8_iface;
817

818
    return D3D_OK;
819
}
820

821
static HRESULT WINAPI d3d8_device_CreateVolumeTexture(IDirect3DDevice8 *iface,
822 823
        UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format,
        D3DPOOL pool, IDirect3DVolumeTexture8 **texture)
824
{
825
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
826
    struct d3d8_texture *object;
827
    HRESULT hr;
828

829 830
    TRACE("iface %p, width %u, height %u, depth %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
            iface, width, height, depth, levels, usage, format, pool, texture);
831

832
    *texture = NULL;
833 834
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
835 836
        return D3DERR_OUTOFVIDEOMEMORY;

837
    hr = volumetexture_init(object, device, width, height, depth, levels, usage, format, pool);
838 839 840
    if (FAILED(hr))
    {
        WARN("Failed to initialize volume texture, hr %#x.\n", hr);
841
        HeapFree(GetProcessHeap(), 0, object);
842
        return hr;
843
    }
844 845

    TRACE("Created volume texture %p.\n", object);
846
    *texture = (IDirect3DVolumeTexture8 *)&object->IDirect3DBaseTexture8_iface;
847 848

    return D3D_OK;
849
}
850

851
static HRESULT WINAPI d3d8_device_CreateCubeTexture(IDirect3DDevice8 *iface, UINT edge_length,
852
        UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DCubeTexture8 **texture)
853
{
854
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
855
    struct d3d8_texture *object;
856
    HRESULT hr;
857

858 859
    TRACE("iface %p, edge_length %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
            iface, edge_length, levels, usage, format, pool, texture);
860

861
    *texture = NULL;
862
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
863
    if (!object)
864
        return D3DERR_OUTOFVIDEOMEMORY;
865

866
    hr = cubetexture_init(object, device, edge_length, levels, usage, format, pool);
867 868 869
    if (FAILED(hr))
    {
        WARN("Failed to initialize cube texture, hr %#x.\n", hr);
870
        HeapFree(GetProcessHeap(), 0, object);
871
        return hr;
872
    }
873

874
    TRACE("Created cube texture %p.\n", object);
875
    *texture = (IDirect3DCubeTexture8 *)&object->IDirect3DBaseTexture8_iface;
876

877
    return hr;
878 879
}

880
static HRESULT WINAPI d3d8_device_CreateVertexBuffer(IDirect3DDevice8 *iface, UINT size,
881
        DWORD usage, DWORD fvf, D3DPOOL pool, IDirect3DVertexBuffer8 **buffer)
882
{
883
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
884
    struct d3d8_vertexbuffer *object;
885
    HRESULT hr;
886

887 888 889 890 891
    TRACE("iface %p, size %u, usage %#x, fvf %#x, pool %#x, buffer %p.\n",
            iface, size, usage, fvf, pool, buffer);

    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
892 893
        return D3DERR_OUTOFVIDEOMEMORY;

894
    hr = vertexbuffer_init(object, device, size, usage, fvf, pool);
895 896 897
    if (FAILED(hr))
    {
        WARN("Failed to initialize vertex buffer, hr %#x.\n", hr);
898
        HeapFree(GetProcessHeap(), 0, object);
899
        return hr;
900
    }
901 902

    TRACE("Created vertex buffer %p.\n", object);
903
    *buffer = &object->IDirect3DVertexBuffer8_iface;
904 905

    return D3D_OK;
906 907
}

908
static HRESULT WINAPI d3d8_device_CreateIndexBuffer(IDirect3DDevice8 *iface, UINT size,
909
        DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DIndexBuffer8 **buffer)
910
{
911
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
912
    struct d3d8_indexbuffer *object;
913 914 915 916
    HRESULT hr;

    TRACE("iface %p, size %u, usage %#x, format %#x, pool %#x, buffer %p.\n",
            iface, size, usage, format, pool, buffer);
917

918
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
919
    if (!object)
920 921
        return D3DERR_OUTOFVIDEOMEMORY;

922
    hr = indexbuffer_init(object, device, size, usage, format, pool);
923 924 925
    if (FAILED(hr))
    {
        WARN("Failed to initialize index buffer, hr %#x.\n", hr);
926
        HeapFree(GetProcessHeap(), 0, object);
927
        return hr;
928
    }
929 930

    TRACE("Created index buffer %p.\n", object);
931
    *buffer = &object->IDirect3DIndexBuffer8_iface;
932 933

    return D3D_OK;
934
}
935

936
static HRESULT d3d8_device_create_surface(struct d3d8_device *device, UINT width, UINT height,
937 938
        D3DFORMAT format, DWORD flags, IDirect3DSurface8 **surface, UINT usage, D3DPOOL pool,
        D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality)
939
{
940 941 942
    struct wined3d_resource_desc desc;
    struct d3d8_surface *surface_impl;
    struct wined3d_texture *texture;
943
    HRESULT hr;
944

945
    TRACE("device %p, width %u, height %u, format %#x, flags %#x, surface %p,\n"
Henri Verbeet's avatar
Henri Verbeet committed
946
            "\tusage %#x, pool %#x, multisample_type %#x, multisample_quality %u.\n",
947
            device, width, height, format, flags, surface,
948
            usage, pool, multisample_type, multisample_quality);
949

950
    desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
951 952 953 954 955 956 957 958 959
    desc.format = wined3dformat_from_d3dformat(format);
    desc.multisample_type = multisample_type;
    desc.multisample_quality = multisample_quality;
    desc.usage = usage & WINED3DUSAGE_MASK;
    desc.pool = pool;
    desc.width = width;
    desc.height = height;
    desc.depth = 1;
    desc.size = 0;
960

961 962
    wined3d_mutex_lock();

963
    if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &desc,
964
            1, flags, NULL, NULL, &d3d8_null_wined3d_parent_ops, &texture)))
965
    {
966 967
        wined3d_mutex_unlock();
        WARN("Failed to create texture, hr %#x.\n", hr);
968
        return hr;
969
    }
970

971
    surface_impl = wined3d_texture_get_sub_resource_parent(texture, 0);
972 973 974 975 976 977
    surface_impl->parent_device = &device->IDirect3DDevice8_iface;
    *surface = &surface_impl->IDirect3DSurface8_iface;
    IDirect3DSurface8_AddRef(*surface);
    wined3d_texture_decref(texture);

    wined3d_mutex_unlock();
978 979

    return D3D_OK;
980 981
}

982 983 984
static HRESULT WINAPI d3d8_device_CreateRenderTarget(IDirect3DDevice8 *iface, UINT width,
        UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, BOOL lockable,
        IDirect3DSurface8 **surface)
985
{
986
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
987
    DWORD flags = 0;
Henri Verbeet's avatar
Henri Verbeet committed
988 989

    TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, lockable %#x, surface %p.\n",
990
            iface, width, height, format, multisample_type, lockable, surface);
991

992
    *surface = NULL;
993
    if (lockable)
994
        flags |= WINED3D_TEXTURE_CREATE_MAPPABLE;
995 996 997

    return d3d8_device_create_surface(device, width, height, format, flags, surface,
            D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT, multisample_type, 0);
998
}
999

1000 1001 1002
static HRESULT WINAPI d3d8_device_CreateDepthStencilSurface(IDirect3DDevice8 *iface,
        UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type,
        IDirect3DSurface8 **surface)
1003
{
1004
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1005 1006

    TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, surface %p.\n",
1007
            iface, width, height, format, multisample_type, surface);
1008

1009 1010
    *surface = NULL;

1011
    /* TODO: Verify that Discard is false */
1012
    return d3d8_device_create_surface(device, width, height, format, WINED3D_TEXTURE_CREATE_MAPPABLE,
1013
            surface, D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT, multisample_type, 0);
1014
}
1015

1016
/*  IDirect3DDevice8Impl::CreateImageSurface returns surface with pool type SYSTEMMEM */
1017 1018
static HRESULT WINAPI d3d8_device_CreateImageSurface(IDirect3DDevice8 *iface, UINT width,
        UINT height, D3DFORMAT format, IDirect3DSurface8 **surface)
1019
{
1020
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1021 1022

    TRACE("iface %p, width %u, height %u, format %#x, surface %p.\n",
1023
            iface, width, height, format, surface);
1024

1025 1026
    *surface = NULL;

1027
    return d3d8_device_create_surface(device, width, height, format, WINED3D_TEXTURE_CREATE_MAPPABLE,
1028
            surface, 0, D3DPOOL_SYSTEMMEM, D3DMULTISAMPLE_NONE, 0);
1029
}
1030

1031 1032 1033
static HRESULT WINAPI d3d8_device_CopyRects(IDirect3DDevice8 *iface,
        IDirect3DSurface8 *src_surface, const RECT *src_rects, UINT rect_count,
        IDirect3DSurface8 *dst_surface, const POINT *dst_points)
1034
{
1035 1036
    struct d3d8_surface *src = unsafe_impl_from_IDirect3DSurface8(src_surface);
    struct d3d8_surface *dst = unsafe_impl_from_IDirect3DSurface8(dst_surface);
1037
    enum wined3d_format_id src_format, dst_format;
1038
    struct wined3d_resource_desc wined3d_desc;
1039
    struct wined3d_resource *wined3d_resource;
1040
    UINT src_w, src_h;
1041

Henri Verbeet's avatar
Henri Verbeet committed
1042
    TRACE("iface %p, src_surface %p, src_rects %p, rect_count %u, dst_surface %p, dst_points %p.\n",
1043
            iface, src_surface, src_rects, rect_count, dst_surface, dst_points);
1044

1045 1046
    /* Check that the source texture is in WINED3D_POOL_SYSTEM_MEM and the
     * destination texture is in WINED3D_POOL_DEFAULT. */
1047

1048
    wined3d_mutex_lock();
1049
    wined3d_resource = wined3d_texture_get_sub_resource(src->wined3d_texture, src->sub_resource_idx);
1050
    wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
1051 1052
    if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
    {
1053
        WARN("Source %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", src_surface);
1054 1055 1056
        wined3d_mutex_unlock();
        return D3DERR_INVALIDCALL;
    }
1057
    src_format = wined3d_desc.format;
1058 1059
    src_w = wined3d_desc.width;
    src_h = wined3d_desc.height;
1060

1061
    wined3d_resource = wined3d_texture_get_sub_resource(dst->wined3d_texture, dst->sub_resource_idx);
1062
    wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
1063 1064
    if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
    {
1065
        WARN("Destination %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", dst_surface);
1066 1067 1068
        wined3d_mutex_unlock();
        return D3DERR_INVALIDCALL;
    }
1069
    dst_format = wined3d_desc.format;
1070 1071

    /* Check that the source and destination formats match */
1072
    if (src_format != dst_format)
1073
    {
1074 1075
        WARN("Source %p format must match the destination %p format, returning D3DERR_INVALIDCALL.\n",
                src_surface, dst_surface);
1076
        wined3d_mutex_unlock();
1077 1078
        return D3DERR_INVALIDCALL;
    }
1079

1080
    /* Quick if complete copy ... */
1081
    if (!rect_count && !src_rects && !dst_points)
1082
    {
1083
        RECT rect = {0, 0, src_w, src_h};
1084 1085
        wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &rect,
                src->wined3d_texture, src->sub_resource_idx, &rect, 0, NULL, WINED3D_TEXF_POINT);
1086 1087 1088
    }
    else
    {
1089 1090
        unsigned int i;
        /* Copy rect by rect */
1091
        if (src_rects && dst_points)
1092
        {
1093
            for (i = 0; i < rect_count; ++i)
1094
            {
1095 1096 1097 1098
                UINT w = src_rects[i].right - src_rects[i].left;
                UINT h = src_rects[i].bottom - src_rects[i].top;
                RECT dst_rect = {dst_points[i].x, dst_points[i].y,
                        dst_points[i].x + w, dst_points[i].y + h};
1099

1100 1101
                wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &dst_rect,
                        src->wined3d_texture, src->sub_resource_idx, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
1102
            }
1103 1104 1105
        }
        else
        {
1106
            for (i = 0; i < rect_count; ++i)
1107
            {
1108 1109
                UINT w = src_rects[i].right - src_rects[i].left;
                UINT h = src_rects[i].bottom - src_rects[i].top;
1110 1111
                RECT dst_rect = {0, 0, w, h};

1112 1113
                wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &dst_rect,
                        src->wined3d_texture, src->sub_resource_idx, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
1114 1115 1116
            }
        }
    }
1117
    wined3d_mutex_unlock();
1118

1119
    return WINED3D_OK;
1120
}
1121

1122
static HRESULT WINAPI d3d8_device_UpdateTexture(IDirect3DDevice8 *iface,
1123
        IDirect3DBaseTexture8 *src_texture, IDirect3DBaseTexture8 *dst_texture)
1124
{
1125
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1126
    struct d3d8_texture *src_impl, *dst_impl;
1127
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1128

1129
    TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
1130

1131 1132 1133
    src_impl = unsafe_impl_from_IDirect3DBaseTexture8(src_texture);
    dst_impl = unsafe_impl_from_IDirect3DBaseTexture8(dst_texture);

1134
    wined3d_mutex_lock();
1135
    hr = wined3d_device_update_texture(device->wined3d_device,
1136
            src_impl->wined3d_texture, dst_impl->wined3d_texture);
1137 1138
    wined3d_mutex_unlock();

1139
    return hr;
1140
}
1141

1142
static HRESULT WINAPI d3d8_device_GetFrontBuffer(IDirect3DDevice8 *iface, IDirect3DSurface8 *dst_surface)
1143
{
1144
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1145
    struct d3d8_surface *dst_impl = unsafe_impl_from_IDirect3DSurface8(dst_surface);
1146
    HRESULT hr;
1147

1148
    TRACE("iface %p, dst_surface %p.\n", iface, dst_surface);
1149

1150 1151 1152
    if (!dst_surface)
    {
        WARN("Invalid destination surface passed.\n");
1153
        return D3DERR_INVALIDCALL;
1154
    }
1155

1156
    wined3d_mutex_lock();
1157 1158
    hr = wined3d_swapchain_get_front_buffer_data(device->implicit_swapchain->wined3d_swapchain,
            dst_impl->wined3d_texture, dst_impl->sub_resource_idx);
1159 1160
    wined3d_mutex_unlock();

1161
    return hr;
1162
}
1163

1164 1165
static HRESULT WINAPI d3d8_device_SetRenderTarget(IDirect3DDevice8 *iface,
        IDirect3DSurface8 *render_target, IDirect3DSurface8 *depth_stencil)
1166
{
1167
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1168 1169
    struct d3d8_surface *rt_impl = unsafe_impl_from_IDirect3DSurface8(render_target);
    struct d3d8_surface *ds_impl = unsafe_impl_from_IDirect3DSurface8(depth_stencil);
1170
    struct wined3d_rendertarget_view *original_dsv;
1171
    HRESULT hr = D3D_OK;
Henri Verbeet's avatar
Henri Verbeet committed
1172

1173
    TRACE("iface %p, render_target %p, depth_stencil %p.\n", iface, render_target, depth_stencil);
1174

1175
    wined3d_mutex_lock();
1176

1177
    if (ds_impl)
1178
    {
1179
        struct wined3d_rendertarget_view *original_rtv;
1180 1181
        struct wined3d_resource_desc ds_desc, rt_desc;
        struct wined3d_resource *wined3d_resource;
1182
        struct d3d8_surface *original_surface;
1183 1184

        /* If no render target is passed in check the size against the current RT */
1185
        if (!render_target)
1186
        {
1187 1188

            if (!(original_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
1189 1190
            {
                wined3d_mutex_unlock();
1191
                return D3DERR_NOTFOUND;
1192
            }
1193
            original_surface = wined3d_rendertarget_view_get_sub_resource_parent(original_rtv);
1194
            wined3d_resource = wined3d_texture_get_sub_resource(original_surface->wined3d_texture, original_surface->sub_resource_idx);
1195
        }
1196
        else
1197
            wined3d_resource = wined3d_texture_get_sub_resource(rt_impl->wined3d_texture, rt_impl->sub_resource_idx);
1198
        wined3d_resource_get_desc(wined3d_resource, &rt_desc);
1199

1200
        wined3d_resource = wined3d_texture_get_sub_resource(ds_impl->wined3d_texture, ds_impl->sub_resource_idx);
1201 1202 1203 1204 1205 1206 1207 1208
        wined3d_resource_get_desc(wined3d_resource, &ds_desc);

        if (ds_desc.width < rt_desc.width || ds_desc.height < rt_desc.height)
        {
            WARN("Depth stencil is smaller than the render target, returning D3DERR_INVALIDCALL\n");
            wined3d_mutex_unlock();
            return D3DERR_INVALIDCALL;
        }
1209 1210 1211
        if (ds_desc.multisample_type != rt_desc.multisample_type
                || ds_desc.multisample_quality != rt_desc.multisample_quality)
        {
1212
            WARN("Multisample settings do not match, returning D3DERR_INVALIDCALL\n");
1213 1214 1215 1216
            wined3d_mutex_unlock();
            return D3DERR_INVALIDCALL;

        }
1217 1218
    }

1219 1220 1221
    original_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device);
    wined3d_device_set_depth_stencil_view(device->wined3d_device,
            ds_impl ? d3d8_surface_get_rendertarget_view(ds_impl) : NULL);
1222 1223
    if (render_target && FAILED(hr = wined3d_device_set_rendertarget_view(device->wined3d_device, 0,
            d3d8_surface_get_rendertarget_view(rt_impl), TRUE)))
1224
        wined3d_device_set_depth_stencil_view(device->wined3d_device, original_dsv);
1225

1226 1227
    wined3d_mutex_unlock();

1228
    return hr;
1229
}
1230

1231
static HRESULT WINAPI d3d8_device_GetRenderTarget(IDirect3DDevice8 *iface, IDirect3DSurface8 **render_target)
1232
{
1233
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1234
    struct wined3d_rendertarget_view *wined3d_rtv;
1235
    struct d3d8_surface *surface_impl;
1236
    HRESULT hr;
1237

1238
    TRACE("iface %p, render_target %p.\n", iface, render_target);
1239

1240
    if (!render_target)
1241
        return D3DERR_INVALIDCALL;
1242 1243

    wined3d_mutex_lock();
1244
    if ((wined3d_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
1245
    {
1246 1247 1248
        /* We want the sub resource parent here, since the view itself may be
         * internal to wined3d and may not have a parent. */
        surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_rtv);
1249 1250
        *render_target = &surface_impl->IDirect3DSurface8_iface;
        IDirect3DSurface8_AddRef(*render_target);
1251
        hr = D3D_OK;
1252 1253 1254
    }
    else
    {
1255
        ERR("Failed to get wined3d render target.\n");
1256
        *render_target = NULL;
1257
        hr = D3DERR_NOTFOUND;
1258
    }
1259
    wined3d_mutex_unlock();
1260 1261

    return hr;
1262
}
1263

1264
static HRESULT WINAPI d3d8_device_GetDepthStencilSurface(IDirect3DDevice8 *iface, IDirect3DSurface8 **depth_stencil)
1265
{
1266
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1267
    struct wined3d_rendertarget_view *wined3d_dsv;
1268
    struct d3d8_surface *surface_impl;
1269
    HRESULT hr = D3D_OK;
1270

1271
    TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
Henri Verbeet's avatar
Henri Verbeet committed
1272

1273
    if (!depth_stencil)
1274
        return D3DERR_INVALIDCALL;
1275

1276
    wined3d_mutex_lock();
1277
    if ((wined3d_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device)))
1278
    {
1279 1280 1281
        /* We want the sub resource parent here, since the view itself may be
         * internal to wined3d and may not have a parent. */
        surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_dsv);
1282 1283
        *depth_stencil = &surface_impl->IDirect3DSurface8_iface;
        IDirect3DSurface8_AddRef(*depth_stencil);
1284 1285 1286
    }
    else
    {
1287
        hr = D3DERR_NOTFOUND;
1288
        *depth_stencil = NULL;
1289
    }
1290
    wined3d_mutex_unlock();
1291

1292
    return hr;
1293 1294
}

1295
static HRESULT WINAPI d3d8_device_BeginScene(IDirect3DDevice8 *iface)
1296
{
1297
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1298
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1299 1300

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

1302
    wined3d_mutex_lock();
1303
    hr = wined3d_device_begin_scene(device->wined3d_device);
1304 1305
    wined3d_mutex_unlock();

1306
    return hr;
1307
}
1308

1309
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d8_device_EndScene(IDirect3DDevice8 *iface)
1310
{
1311
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1312
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1313 1314

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

1316
    wined3d_mutex_lock();
1317
    hr = wined3d_device_end_scene(device->wined3d_device);
1318 1319
    wined3d_mutex_unlock();

1320
    return hr;
1321 1322
}

1323
static HRESULT WINAPI d3d8_device_Clear(IDirect3DDevice8 *iface, DWORD rect_count,
1324
        const D3DRECT *rects, DWORD flags, D3DCOLOR color, float z, DWORD stencil)
1325
{
1326 1327 1328 1329 1330 1331 1332
    const struct wined3d_color c =
    {
        ((color >> 16) & 0xff) / 255.0f,
        ((color >>  8) & 0xff) / 255.0f,
        (color & 0xff) / 255.0f,
        ((color >> 24) & 0xff) / 255.0f,
    };
1333
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1334
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1335 1336

    TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %u.\n",
1337
            iface, rect_count, rects, flags, color, z, stencil);
1338

1339
    wined3d_mutex_lock();
1340
    hr = wined3d_device_clear(device->wined3d_device, rect_count, (const RECT *)rects, flags, &c, z, stencil);
1341 1342
    wined3d_mutex_unlock();

1343
    return hr;
1344
}
1345

1346 1347
static HRESULT WINAPI d3d8_device_SetTransform(IDirect3DDevice8 *iface,
        D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1348
{
1349
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1350

1351
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1352

1353
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1354
    wined3d_mutex_lock();
1355
    wined3d_device_set_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1356 1357
    wined3d_mutex_unlock();

1358
    return D3D_OK;
1359
}
1360

1361 1362
static HRESULT WINAPI d3d8_device_GetTransform(IDirect3DDevice8 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
1363
{
1364
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1365

1366
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1367

1368
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1369
    wined3d_mutex_lock();
1370
    wined3d_device_get_transform(device->wined3d_device, state, (struct wined3d_matrix *)matrix);
1371 1372
    wined3d_mutex_unlock();

1373
    return D3D_OK;
1374
}
1375

1376 1377
static HRESULT WINAPI d3d8_device_MultiplyTransform(IDirect3DDevice8 *iface,
        D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1378
{
1379
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1380

1381
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1382

1383
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1384
    wined3d_mutex_lock();
1385
    wined3d_device_multiply_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1386 1387
    wined3d_mutex_unlock();

1388
    return D3D_OK;
1389
}
1390

1391
static HRESULT WINAPI d3d8_device_SetViewport(IDirect3DDevice8 *iface, const D3DVIEWPORT8 *viewport)
1392
{
1393
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1394

1395
    TRACE("iface %p, viewport %p.\n", iface, viewport);
1396

1397
    /* Note: D3DVIEWPORT8 is compatible with struct wined3d_viewport. */
1398
    wined3d_mutex_lock();
1399
    wined3d_device_set_viewport(device->wined3d_device, (const struct wined3d_viewport *)viewport);
1400 1401
    wined3d_mutex_unlock();

1402
    return D3D_OK;
1403 1404
}

1405
static HRESULT WINAPI d3d8_device_GetViewport(IDirect3DDevice8 *iface, D3DVIEWPORT8 *viewport)
1406
{
1407
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1408

1409
    TRACE("iface %p, viewport %p.\n", iface, viewport);
1410

1411
    /* Note: D3DVIEWPORT8 is compatible with struct wined3d_viewport. */
1412
    wined3d_mutex_lock();
1413
    wined3d_device_get_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
1414 1415
    wined3d_mutex_unlock();

1416
    return D3D_OK;
1417
}
1418

1419
static HRESULT WINAPI d3d8_device_SetMaterial(IDirect3DDevice8 *iface, const D3DMATERIAL8 *material)
1420
{
1421
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1422

1423
    TRACE("iface %p, material %p.\n", iface, material);
1424

1425
    /* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
1426
    wined3d_mutex_lock();
1427
    wined3d_device_set_material(device->wined3d_device, (const struct wined3d_material *)material);
1428 1429
    wined3d_mutex_unlock();

1430
    return D3D_OK;
1431 1432
}

1433
static HRESULT WINAPI d3d8_device_GetMaterial(IDirect3DDevice8 *iface, D3DMATERIAL8 *material)
1434
{
1435
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1436

1437
    TRACE("iface %p, material %p.\n", iface, material);
1438

1439
    /* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
1440
    wined3d_mutex_lock();
1441
    wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
1442 1443
    wined3d_mutex_unlock();

1444
    return D3D_OK;
1445 1446
}

1447
static HRESULT WINAPI d3d8_device_SetLight(IDirect3DDevice8 *iface, DWORD index, const D3DLIGHT8 *light)
1448
{
1449
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1450
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1451

1452
    TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1453

1454
    /* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
1455
    wined3d_mutex_lock();
1456
    hr = wined3d_device_set_light(device->wined3d_device, index, (const struct wined3d_light *)light);
1457 1458
    wined3d_mutex_unlock();

1459
    return hr;
1460
}
1461

1462
static HRESULT WINAPI d3d8_device_GetLight(IDirect3DDevice8 *iface, DWORD index, D3DLIGHT8 *light)
1463
{
1464
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1465
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1466

1467
    TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1468

1469
    /* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
1470
    wined3d_mutex_lock();
1471
    hr = wined3d_device_get_light(device->wined3d_device, index, (struct wined3d_light *)light);
1472 1473
    wined3d_mutex_unlock();

1474
    return hr;
1475 1476
}

1477
static HRESULT WINAPI d3d8_device_LightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL enable)
1478
{
1479
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1480
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1481

1482
    TRACE("iface %p, index %u, enable %#x.\n", iface, index, enable);
1483

1484
    wined3d_mutex_lock();
1485
    hr = wined3d_device_set_light_enable(device->wined3d_device, index, enable);
1486 1487
    wined3d_mutex_unlock();

1488
    return hr;
1489
}
1490

1491
static HRESULT WINAPI d3d8_device_GetLightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL *enable)
1492
{
1493
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1494
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1495

1496
    TRACE("iface %p, index %u, enable %p.\n", iface, index, enable);
1497

1498
    wined3d_mutex_lock();
1499
    hr = wined3d_device_get_light_enable(device->wined3d_device, index, enable);
1500 1501
    wined3d_mutex_unlock();

1502
    return hr;
1503
}
1504

1505
static HRESULT WINAPI d3d8_device_SetClipPlane(IDirect3DDevice8 *iface, DWORD index, const float *plane)
1506
{
1507
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1508
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1509

1510
    TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
1511

1512
    wined3d_mutex_lock();
1513
    hr = wined3d_device_set_clip_plane(device->wined3d_device, index, (const struct wined3d_vec4 *)plane);
1514 1515
    wined3d_mutex_unlock();

1516
    return hr;
1517
}
1518

1519
static HRESULT WINAPI d3d8_device_GetClipPlane(IDirect3DDevice8 *iface, DWORD index, float *plane)
1520
{
1521
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1522
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1523

1524
    TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
Jason Edmeades's avatar
Jason Edmeades committed
1525

1526
    wined3d_mutex_lock();
1527
    hr = wined3d_device_get_clip_plane(device->wined3d_device, index, (struct wined3d_vec4 *)plane);
1528 1529
    wined3d_mutex_unlock();

1530
    return hr;
1531
}
1532

1533 1534
static HRESULT WINAPI d3d8_device_SetRenderState(IDirect3DDevice8 *iface,
        D3DRENDERSTATETYPE state, DWORD value)
1535
{
1536
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1537

1538
    TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
1539

1540
    wined3d_mutex_lock();
1541
    switch (state)
1542 1543
    {
        case D3DRS_ZBIAS:
1544
            wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
1545 1546 1547
            break;

        default:
1548
            wined3d_device_set_render_state(device->wined3d_device, state, value);
1549
    }
1550 1551
    wined3d_mutex_unlock();

1552
    return D3D_OK;
1553
}
1554

1555 1556
static HRESULT WINAPI d3d8_device_GetRenderState(IDirect3DDevice8 *iface,
        D3DRENDERSTATETYPE state, DWORD *value)
1557
{
1558
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
Henri Verbeet's avatar
Henri Verbeet committed
1559

1560
    TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
1561

1562
    wined3d_mutex_lock();
1563
    switch (state)
1564 1565
    {
        case D3DRS_ZBIAS:
1566
            *value = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS);
1567 1568 1569
            break;

        default:
1570
            *value = wined3d_device_get_render_state(device->wined3d_device, state);
1571
    }
1572 1573
    wined3d_mutex_unlock();

1574
    return D3D_OK;
1575
}
1576

1577
static HRESULT WINAPI d3d8_device_BeginStateBlock(IDirect3DDevice8 *iface)
1578
{
1579
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1580
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1581 1582

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

1584
    wined3d_mutex_lock();
1585
    hr = wined3d_device_begin_stateblock(device->wined3d_device);
1586 1587
    wined3d_mutex_unlock();

1588
    return hr;
1589
}
1590

1591
static HRESULT WINAPI d3d8_device_EndStateBlock(IDirect3DDevice8 *iface, DWORD *token)
1592
{
1593
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1594
    struct wined3d_stateblock *stateblock;
1595
    HRESULT hr;
1596

1597
    TRACE("iface %p, token %p.\n", iface, token);
1598

Austin English's avatar
Austin English committed
1599
    /* Tell wineD3D to endstateblock before anything else (in case we run out
1600 1601
     * of memory later and cause locking problems)
     */
1602
    wined3d_mutex_lock();
1603
    hr = wined3d_device_end_stateblock(device->wined3d_device, &stateblock);
1604 1605
    if (FAILED(hr))
    {
1606
        WARN("IWineD3DDevice_EndStateBlock returned an error\n");
1607
        wined3d_mutex_unlock();
1608
        return hr;
1609
    }
1610

1611
    *token = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
1612
    wined3d_mutex_unlock();
1613

1614
    if (*token == D3D8_INVALID_HANDLE)
1615 1616
    {
        ERR("Failed to create a handle\n");
1617
        wined3d_mutex_lock();
1618
        wined3d_stateblock_decref(stateblock);
1619
        wined3d_mutex_unlock();
1620 1621
        return E_FAIL;
    }
1622
    ++*token;
1623

1624
    TRACE("Returning %#x (%p).\n", *token, stateblock);
1625

1626
    return hr;
1627 1628
}

1629
static HRESULT WINAPI d3d8_device_ApplyStateBlock(IDirect3DDevice8 *iface, DWORD token)
1630
{
1631
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1632
    struct wined3d_stateblock *stateblock;
1633

1634
    TRACE("iface %p, token %#x.\n", iface, token);
1635

1636 1637
    if (!token)
        return D3D_OK;
1638

1639
    wined3d_mutex_lock();
1640
    stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1641
    if (!stateblock)
1642
    {
1643
        WARN("Invalid handle (%#x) passed.\n", token);
1644
        wined3d_mutex_unlock();
1645 1646
        return D3DERR_INVALIDCALL;
    }
1647
    wined3d_stateblock_apply(stateblock);
1648 1649
    wined3d_mutex_unlock();

1650
    return D3D_OK;
1651
}
1652

1653
static HRESULT WINAPI d3d8_device_CaptureStateBlock(IDirect3DDevice8 *iface, DWORD token)
1654
{
1655
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1656
    struct wined3d_stateblock *stateblock;
1657

1658
    TRACE("iface %p, token %#x.\n", iface, token);
1659

1660
    wined3d_mutex_lock();
1661
    stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1662
    if (!stateblock)
1663
    {
1664
        WARN("Invalid handle (%#x) passed.\n", token);
1665
        wined3d_mutex_unlock();
1666 1667
        return D3DERR_INVALIDCALL;
    }
1668
    wined3d_stateblock_capture(stateblock);
1669 1670
    wined3d_mutex_unlock();

1671
    return D3D_OK;
1672 1673
}

1674
static HRESULT WINAPI d3d8_device_DeleteStateBlock(IDirect3DDevice8 *iface, DWORD token)
1675
{
1676
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1677
    struct wined3d_stateblock *stateblock;
1678

1679
    TRACE("iface %p, token %#x.\n", iface, token);
1680

1681
    wined3d_mutex_lock();
1682
    stateblock = d3d8_free_handle(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1683

1684
    if (!stateblock)
1685
    {
1686
        WARN("Invalid handle (%#x) passed.\n", token);
1687
        wined3d_mutex_unlock();
1688 1689
        return D3DERR_INVALIDCALL;
    }
1690

1691
    if (wined3d_stateblock_decref(stateblock))
1692
    {
1693
        ERR("Stateblock %p has references left, this shouldn't happen.\n", stateblock);
1694
    }
1695
    wined3d_mutex_unlock();
1696

1697
    return D3D_OK;
1698
}
1699

1700 1701
static HRESULT WINAPI d3d8_device_CreateStateBlock(IDirect3DDevice8 *iface,
        D3DSTATEBLOCKTYPE type, DWORD *handle)
1702
{
1703
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1704
    struct wined3d_stateblock *stateblock;
1705
    HRESULT hr;
1706

1707
    TRACE("iface %p, type %#x, handle %p.\n", iface, type, handle);
1708

1709 1710 1711
    if (type != D3DSBT_ALL
            && type != D3DSBT_PIXELSTATE
            && type != D3DSBT_VERTEXSTATE)
1712 1713 1714 1715
    {
        WARN("Unexpected stateblock type, returning D3DERR_INVALIDCALL\n");
        return D3DERR_INVALIDCALL;
    }
1716

1717
    wined3d_mutex_lock();
1718
    hr = wined3d_stateblock_create(device->wined3d_device, (enum wined3d_stateblock_type)type, &stateblock);
1719 1720
    if (FAILED(hr))
    {
1721
        wined3d_mutex_unlock();
1722 1723 1724 1725
        ERR("IWineD3DDevice_CreateStateBlock failed, hr %#x\n", hr);
        return hr;
    }

1726
    *handle = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
1727
    wined3d_mutex_unlock();
1728 1729 1730 1731

    if (*handle == D3D8_INVALID_HANDLE)
    {
        ERR("Failed to allocate a handle.\n");
1732
        wined3d_mutex_lock();
1733
        wined3d_stateblock_decref(stateblock);
1734
        wined3d_mutex_unlock();
1735 1736 1737 1738
        return E_FAIL;
    }
    ++*handle;

1739
    TRACE("Returning %#x (%p).\n", *handle, stateblock);
1740 1741

    return hr;
1742
}
1743

1744
static HRESULT WINAPI d3d8_device_SetClipStatus(IDirect3DDevice8 *iface, const D3DCLIPSTATUS8 *clip_status)
1745
{
1746
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1747
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1748

1749
    TRACE("iface %p, clip_status %p.\n", iface, clip_status);
1750
    /* FIXME: Verify that D3DCLIPSTATUS8 ~= struct wined3d_clip_status. */
1751 1752

    wined3d_mutex_lock();
1753
    hr = wined3d_device_set_clip_status(device->wined3d_device, (const struct wined3d_clip_status *)clip_status);
1754 1755
    wined3d_mutex_unlock();

1756
    return hr;
1757
}
1758

1759
static HRESULT WINAPI d3d8_device_GetClipStatus(IDirect3DDevice8 *iface, D3DCLIPSTATUS8 *clip_status)
1760
{
1761
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1762
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1763

1764
    TRACE("iface %p, clip_status %p.\n", iface, clip_status);
1765

1766
    wined3d_mutex_lock();
1767
    hr = wined3d_device_get_clip_status(device->wined3d_device, (struct wined3d_clip_status *)clip_status);
1768 1769
    wined3d_mutex_unlock();

1770
    return hr;
1771
}
1772

1773
static HRESULT WINAPI d3d8_device_GetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 **texture)
1774
{
1775
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1776
    struct wined3d_texture *wined3d_texture;
1777
    struct d3d8_texture *texture_impl;
1778

1779
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
1780

1781
    if (!texture)
1782 1783
        return D3DERR_INVALIDCALL;

1784
    wined3d_mutex_lock();
1785
    if ((wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
1786
    {
1787
        texture_impl = wined3d_texture_get_parent(wined3d_texture);
1788 1789
        *texture = &texture_impl->IDirect3DBaseTexture8_iface;
        IDirect3DBaseTexture8_AddRef(*texture);
1790 1791 1792
    }
    else
    {
1793
        *texture = NULL;
1794
    }
1795
    wined3d_mutex_unlock();
1796

1797
    return D3D_OK;
1798 1799
}

1800
static HRESULT WINAPI d3d8_device_SetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 *texture)
1801
{
1802
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1803
    struct d3d8_texture *texture_impl;
1804
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1805

1806 1807 1808
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);

    texture_impl = unsafe_impl_from_IDirect3DBaseTexture8(texture);
1809

1810
    wined3d_mutex_lock();
1811
    hr = wined3d_device_set_texture(device->wined3d_device, stage,
1812
            texture_impl ? texture_impl->wined3d_texture : NULL);
1813 1814
    wined3d_mutex_unlock();

1815
    return hr;
1816 1817
}

1818 1819 1820
static const struct tss_lookup
{
    BOOL sampler_state;
1821
    enum wined3d_texture_stage_state state;
1822 1823 1824
}
tss_lookup[] =
{
1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853
    {FALSE, WINED3D_TSS_INVALID},                   /*  0, unused */
    {FALSE, WINED3D_TSS_COLOR_OP},                  /*  1, D3DTSS_COLOROP */
    {FALSE, WINED3D_TSS_COLOR_ARG1},                /*  2, D3DTSS_COLORARG1 */
    {FALSE, WINED3D_TSS_COLOR_ARG2},                /*  3, D3DTSS_COLORARG2 */
    {FALSE, WINED3D_TSS_ALPHA_OP},                  /*  4, D3DTSS_ALPHAOP */
    {FALSE, WINED3D_TSS_ALPHA_ARG1},                /*  5, D3DTSS_ALPHAARG1 */
    {FALSE, WINED3D_TSS_ALPHA_ARG2},                /*  6, D3DTSS_ALPHAARG2 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT00},             /*  7, D3DTSS_BUMPENVMAT00 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT01},             /*  8, D3DTSS_BUMPENVMAT01 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT10},             /*  9, D3DTSS_BUMPENVMAT10 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT11},             /* 10, D3DTSS_BUMPENVMAT11 */
    {FALSE, WINED3D_TSS_TEXCOORD_INDEX},            /* 11, D3DTSS_TEXCOORDINDEX */
    {FALSE, WINED3D_TSS_INVALID},                   /* 12, unused */
    {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 13, D3DTSS_ADDRESSU */
    {TRUE,  WINED3D_SAMP_ADDRESS_V},                /* 14, D3DTSS_ADDRESSV */
    {TRUE,  WINED3D_SAMP_BORDER_COLOR},             /* 15, D3DTSS_BORDERCOLOR */
    {TRUE,  WINED3D_SAMP_MAG_FILTER},               /* 16, D3DTSS_MAGFILTER */
    {TRUE,  WINED3D_SAMP_MIN_FILTER},               /* 17, D3DTSS_MINFILTER */
    {TRUE,  WINED3D_SAMP_MIP_FILTER},               /* 18, D3DTSS_MIPFILTER */
    {TRUE,  WINED3D_SAMP_MIPMAP_LOD_BIAS},          /* 19, D3DTSS_MIPMAPLODBIAS */
    {TRUE,  WINED3D_SAMP_MAX_MIP_LEVEL},            /* 20, D3DTSS_MAXMIPLEVEL */
    {TRUE,  WINED3D_SAMP_MAX_ANISOTROPY},           /* 21, D3DTSS_MAXANISOTROPY */
    {FALSE, WINED3D_TSS_BUMPENV_LSCALE},            /* 22, D3DTSS_BUMPENVLSCALE */
    {FALSE, WINED3D_TSS_BUMPENV_LOFFSET},           /* 23, D3DTSS_BUMPENVLOFFSET */
    {FALSE, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
    {TRUE,  WINED3D_SAMP_ADDRESS_W},                /* 25, D3DTSS_ADDRESSW */
    {FALSE, WINED3D_TSS_COLOR_ARG0},                /* 26, D3DTSS_COLORARG0 */
    {FALSE, WINED3D_TSS_ALPHA_ARG0},                /* 27, D3DTSS_ALPHAARG0 */
    {FALSE, WINED3D_TSS_RESULT_ARG},                /* 28, D3DTSS_RESULTARG */
1854 1855
};

1856 1857
static HRESULT WINAPI d3d8_device_GetTextureStageState(IDirect3DDevice8 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *value)
1858
{
1859
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1860
    const struct tss_lookup *l;
Henri Verbeet's avatar
Henri Verbeet committed
1861

1862
    TRACE("iface %p, stage %u, state %#x, value %p.\n", iface, stage, Type, value);
1863

1864 1865 1866 1867 1868 1869 1870 1871
    if (Type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
    {
        WARN("Invalid Type %#x passed.\n", Type);
        return D3D_OK;
    }

    l = &tss_lookup[Type];

1872
    wined3d_mutex_lock();
1873
    if (l->sampler_state)
1874
        *value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->state);
1875
    else
1876
        *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->state);
1877
    wined3d_mutex_unlock();
1878

1879
    return D3D_OK;
1880
}
1881

1882 1883
static HRESULT WINAPI d3d8_device_SetTextureStageState(IDirect3DDevice8 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
1884
{
1885
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1886
    const struct tss_lookup *l;
Henri Verbeet's avatar
Henri Verbeet committed
1887

1888
    TRACE("iface %p, stage %u, state %#x, value %#x.\n", iface, stage, type, value);
1889

1890
    if (type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
1891
    {
1892
        WARN("Invalid type %#x passed.\n", type);
1893 1894 1895
        return D3D_OK;
    }

1896
    l = &tss_lookup[type];
1897

1898
    wined3d_mutex_lock();
1899
    if (l->sampler_state)
1900
        wined3d_device_set_sampler_state(device->wined3d_device, stage, l->state, value);
1901
    else
1902
        wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->state, value);
1903
    wined3d_mutex_unlock();
1904

1905
    return D3D_OK;
1906
}
1907

1908
static HRESULT WINAPI d3d8_device_ValidateDevice(IDirect3DDevice8 *iface, DWORD *pass_count)
1909
{
1910
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1911
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1912

1913
    TRACE("iface %p, pass_count %p.\n", iface, pass_count);
1914

1915
    wined3d_mutex_lock();
1916
    hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
1917 1918
    wined3d_mutex_unlock();

1919
    return hr;
1920
}
1921

1922
static HRESULT WINAPI d3d8_device_GetInfo(IDirect3DDevice8 *iface,
Henri Verbeet's avatar
Henri Verbeet committed
1923 1924 1925 1926
        DWORD info_id, void *info, DWORD info_size)
{
    FIXME("iface %p, info_id %#x, info %p, info_size %u stub!\n", iface, info_id, info, info_size);

1927
    return D3D_OK;
1928
}
1929

1930 1931
static HRESULT WINAPI d3d8_device_SetPaletteEntries(IDirect3DDevice8 *iface,
        UINT palette_idx, const PALETTEENTRY *entries)
1932
{
1933
    WARN("iface %p, palette_idx %u, entries %p unimplemented\n", iface, palette_idx, entries);
Henri Verbeet's avatar
Henri Verbeet committed
1934

1935 1936
    /* GPUs stopped supporting palettized textures with the Shader Model 1 generation. Wined3d
     * does not have a d3d8/9-style palette API */
1937

1938
    return D3D_OK;
1939
}
1940

1941 1942
static HRESULT WINAPI d3d8_device_GetPaletteEntries(IDirect3DDevice8 *iface,
        UINT palette_idx, PALETTEENTRY *entries)
1943
{
1944
    FIXME("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
1945

1946
    return D3DERR_INVALIDCALL;
1947
}
1948

1949
static HRESULT WINAPI d3d8_device_SetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT palette_idx)
1950
{
1951
    WARN("iface %p, palette_idx %u unimplemented.\n", iface, palette_idx);
1952

1953
    return D3D_OK;
1954
}
1955

1956
static HRESULT WINAPI d3d8_device_GetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT *palette_idx)
1957
{
1958
    FIXME("iface %p, palette_idx %p unimplemented.\n", iface, palette_idx);
1959

1960
    return D3DERR_INVALIDCALL;
1961
}
1962

1963 1964
static HRESULT WINAPI d3d8_device_DrawPrimitive(IDirect3DDevice8 *iface,
        D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
1965
{
1966
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1967
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1968 1969

    TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n",
1970
            iface, primitive_type, start_vertex, primitive_count);
1971

1972
    wined3d_mutex_lock();
1973 1974 1975
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
    hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex,
            vertex_count_from_primitive_count(primitive_type, primitive_count));
1976 1977
    wined3d_mutex_unlock();

1978
    return hr;
1979
}
1980

1981 1982 1983
static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface,
        D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
        UINT start_idx, UINT primitive_count)
1984
{
1985
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1986
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
1987 1988

    TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, start_idx %u, primitive_count %u.\n",
1989
            iface, primitive_type, min_vertex_idx, vertex_count, start_idx, primitive_count);
1990

1991
    wined3d_mutex_lock();
1992 1993 1994
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
    hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, start_idx,
            vertex_count_from_primitive_count(primitive_type, primitive_count));
1995 1996
    wined3d_mutex_unlock();

1997
    return hr;
1998 1999
}

2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029
/* The caller is responsible for wined3d locking */
static HRESULT d3d8_device_prepare_vertex_buffer(struct d3d8_device *device, UINT min_size)
{
    HRESULT hr;

    if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
    {
        UINT size = max(device->vertex_buffer_size * 2, min_size);
        struct wined3d_buffer *buffer;

        TRACE("Growing vertex buffer to %u bytes\n", size);

        hr = wined3d_buffer_create_vb(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
                WINED3D_POOL_DEFAULT, NULL, &d3d8_null_wined3d_parent_ops, &buffer);
        if (FAILED(hr))
        {
            ERR("(%p) wined3d_buffer_create_vb failed with hr = %08x\n", device, hr);
            return hr;
        }

        if (device->vertex_buffer)
            wined3d_buffer_decref(device->vertex_buffer);

        device->vertex_buffer = buffer;
        device->vertex_buffer_size = size;
        device->vertex_buffer_pos = 0;
    }
    return D3D_OK;
}

2030 2031 2032
static HRESULT WINAPI d3d8_device_DrawPrimitiveUP(IDirect3DDevice8 *iface,
        D3DPRIMITIVETYPE primitive_type, UINT primitive_count, const void *data,
        UINT stride)
2033
{
2034
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2035
    HRESULT hr;
2036 2037 2038 2039
    UINT vtx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
    UINT size = vtx_count * stride;
    UINT vb_pos, align;
    BYTE *buffer_data;
Henri Verbeet's avatar
Henri Verbeet committed
2040 2041

    TRACE("iface %p, primitive_type %#x, primitive_count %u, data %p, stride %u.\n",
2042
            iface, primitive_type, primitive_count, data, stride);
2043

2044 2045 2046 2047 2048 2049
    if (!primitive_count)
    {
        WARN("primitive_count is 0, returning D3D_OK\n");
        return D3D_OK;
    }

2050
    wined3d_mutex_lock();
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
    hr = d3d8_device_prepare_vertex_buffer(device, size);
    if (FAILED(hr))
        goto done;

    vb_pos = device->vertex_buffer_pos;
    align = vb_pos % stride;
    if (align) align = stride - align;
    if (vb_pos + size + align > device->vertex_buffer_size)
        vb_pos = 0;
    else
        vb_pos += align;

    hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, size, &buffer_data,
            vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
    if (FAILED(hr))
        goto done;
    memcpy(buffer_data, data, size);
    wined3d_buffer_unmap(device->vertex_buffer);
    device->vertex_buffer_pos = vb_pos + size;

    hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
    if (FAILED(hr))
        goto done;

2075
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
2076 2077
    hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vtx_count);
    wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
2078

2079 2080
done:
    wined3d_mutex_unlock();
2081
    return hr;
2082 2083
}

2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113
/* The caller is responsible for wined3d locking */
static HRESULT d3d8_device_prepare_index_buffer(struct d3d8_device *device, UINT min_size)
{
    HRESULT hr;

    if (device->index_buffer_size < min_size || !device->index_buffer)
    {
        UINT size = max(device->index_buffer_size * 2, min_size);
        struct wined3d_buffer *buffer;

        TRACE("Growing index buffer to %u bytes\n", size);

        hr = wined3d_buffer_create_ib(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
                WINED3D_POOL_DEFAULT, NULL, &d3d8_null_wined3d_parent_ops, &buffer);
        if (FAILED(hr))
        {
            ERR("(%p) wined3d_buffer_create_ib failed with hr = %08x\n", device, hr);
            return hr;
        }

        if (device->index_buffer)
            wined3d_buffer_decref(device->index_buffer);

        device->index_buffer = buffer;
        device->index_buffer_size = size;
        device->index_buffer_pos = 0;
    }
    return D3D_OK;
}

2114
static HRESULT WINAPI d3d8_device_DrawIndexedPrimitiveUP(IDirect3DDevice8 *iface,
2115
        D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
2116 2117
        UINT primitive_count, const void *index_data, D3DFORMAT index_format,
        const void *vertex_data, UINT vertex_stride)
2118
{
2119
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2120
    HRESULT hr;
2121 2122 2123 2124 2125 2126
    BYTE *buffer_data;

    UINT idx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
    UINT idx_fmt_size = index_format == D3DFMT_INDEX16 ? 2 : 4;
    UINT idx_size = idx_count * idx_fmt_size;
    UINT ib_pos;
Henri Verbeet's avatar
Henri Verbeet committed
2127

2128 2129 2130 2131
    UINT vtx_size = vertex_count * vertex_stride;
    UINT vb_pos, align;

    TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, primitive_count %u,\n"
Henri Verbeet's avatar
Henri Verbeet committed
2132
            "index_data %p, index_format %#x, vertex_data %p, vertex_stride %u.\n",
2133
            iface, primitive_type, min_vertex_idx, vertex_count, primitive_count,
2134
            index_data, index_format, vertex_data, vertex_stride);
2135

2136 2137 2138 2139 2140 2141
    if (!primitive_count)
    {
        WARN("primitive_count is 0, returning D3D_OK\n");
        return D3D_OK;
    }

2142
    wined3d_mutex_lock();
2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191

    hr = d3d8_device_prepare_vertex_buffer(device, vtx_size);
    if (FAILED(hr))
        goto done;

    vb_pos = device->vertex_buffer_pos;
    align = vb_pos % vertex_stride;
    if (align) align = vertex_stride - align;
    if (vb_pos + vtx_size + align > device->vertex_buffer_size)
        vb_pos = 0;
    else
        vb_pos += align;

    hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, vtx_size, &buffer_data,
            vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
    if (FAILED(hr))
        goto done;
    memcpy(buffer_data, vertex_data, vtx_size);
    wined3d_buffer_unmap(device->vertex_buffer);
    device->vertex_buffer_pos = vb_pos + vtx_size;

    hr = d3d8_device_prepare_index_buffer(device, idx_size);
    if (FAILED(hr))
        goto done;

    ib_pos = device->index_buffer_pos;
    align = ib_pos % idx_fmt_size;
    if (align) align = idx_fmt_size - align;
    if (ib_pos + idx_size + align > device->index_buffer_size)
        ib_pos = 0;
    else
        ib_pos += align;

    hr = wined3d_buffer_map(device->index_buffer, ib_pos, idx_size, &buffer_data,
            ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
    if (FAILED(hr))
        goto done;
    memcpy(buffer_data, index_data, idx_size);
    wined3d_buffer_unmap(device->index_buffer);
    device->index_buffer_pos = ib_pos + idx_size;

    hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, vertex_stride);
    if (FAILED(hr))
        goto done;

    wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer,
            wined3dformat_from_d3dformat(index_format));
    wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vertex_stride);

2192
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
2193
    hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / idx_fmt_size, idx_count);
2194

2195 2196 2197 2198 2199 2200
    wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
    wined3d_device_set_index_buffer(device->wined3d_device, NULL, WINED3DFMT_UNKNOWN);
    wined3d_device_set_base_vertex_index(device->wined3d_device, 0);

done:
    wined3d_mutex_unlock();
2201
    return hr;
2202
}
2203

2204 2205
static HRESULT WINAPI d3d8_device_ProcessVertices(IDirect3DDevice8 *iface, UINT src_start_idx,
        UINT dst_idx, UINT vertex_count, IDirect3DVertexBuffer8 *dst_buffer, DWORD flags)
2206
{
2207
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2208
    struct d3d8_vertexbuffer *dst = unsafe_impl_from_IDirect3DVertexBuffer8(dst_buffer);
2209
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2210 2211

    TRACE("iface %p, src_start_idx %u, dst_idx %u, vertex_count %u, dst_buffer %p, flags %#x.\n",
2212
            iface, src_start_idx, dst_idx, vertex_count, dst_buffer, flags);
2213

2214
    wined3d_mutex_lock();
2215
    hr = wined3d_device_process_vertices(device->wined3d_device, src_start_idx, dst_idx,
2216
            vertex_count, dst->wined3d_buffer, NULL, flags, dst->fvf);
2217 2218
    wined3d_mutex_unlock();

2219
    return hr;
2220
}
2221

2222
static HRESULT WINAPI d3d8_device_CreateVertexShader(IDirect3DDevice8 *iface,
2223 2224
        const DWORD *declaration, const DWORD *byte_code, DWORD *shader, DWORD usage)
{
2225
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2226
    struct d3d8_vertex_shader *object;
2227
    DWORD shader_handle;
2228
    DWORD handle;
2229
    HRESULT hr;
2230

2231 2232
    TRACE("iface %p, declaration %p, byte_code %p, shader %p, usage %#x.\n",
            iface, declaration, byte_code, shader, usage);
2233

2234
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2235 2236 2237 2238
    if (!object)
    {
        *shader = 0;
        return E_OUTOFMEMORY;
2239
    }
2240

2241
    wined3d_mutex_lock();
2242
    handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_VS);
2243
    wined3d_mutex_unlock();
2244
    if (handle == D3D8_INVALID_HANDLE)
2245
    {
2246
        ERR("Failed to allocate vertex shader handle.\n");
2247
        HeapFree(GetProcessHeap(), 0, object);
2248
        *shader = 0;
2249 2250 2251
        return E_OUTOFMEMORY;
    }

2252
    shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
2253

2254
    hr = d3d8_vertex_shader_init(object, device, declaration, byte_code, shader_handle, usage);
2255 2256 2257 2258
    if (FAILED(hr))
    {
        WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
        wined3d_mutex_lock();
2259
        d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_VS);
2260 2261 2262 2263
        wined3d_mutex_unlock();
        HeapFree(GetProcessHeap(), 0, object);
        *shader = 0;
        return hr;
2264
    }
2265

2266 2267
    TRACE("Created vertex shader %p (handle %#x).\n", object, shader_handle);
    *shader = shader_handle;
2268

2269
    return D3D_OK;
2270
}
2271

2272
static struct d3d8_vertex_declaration *d3d8_device_get_fvf_declaration(struct d3d8_device *device, DWORD fvf)
2273
{
2274
    struct d3d8_vertex_declaration *d3d8_declaration;
2275
    struct FvfToDecl *convertedDecls = device->decls;
2276
    int p, low, high; /* deliberately signed */
2277
    HRESULT hr;
2278 2279 2280 2281

    TRACE("Searching for declaration for fvf %08x... ", fvf);

    low = 0;
2282 2283 2284
    high = device->numConvertedDecls - 1;
    while (low <= high)
    {
2285 2286
        p = (low + high) >> 1;
        TRACE("%d ", p);
2287

2288 2289 2290 2291 2292
        if (convertedDecls[p].fvf == fvf)
        {
            TRACE("found %p\n", convertedDecls[p].declaration);
            return convertedDecls[p].declaration;
        }
2293 2294

        if (convertedDecls[p].fvf < fvf)
2295
            low = p + 1;
2296
        else
2297 2298 2299 2300
            high = p - 1;
    }
    TRACE("not found. Creating and inserting at position %d.\n", low);

2301
    if (!(d3d8_declaration = HeapAlloc(GetProcessHeap(), 0, sizeof(*d3d8_declaration))))
2302 2303
        return NULL;

2304
    if (FAILED(hr = d3d8_vertex_declaration_init_fvf(d3d8_declaration, device, fvf)))
2305
    {
2306
        WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
2307 2308 2309
        HeapFree(GetProcessHeap(), 0, d3d8_declaration);
        return NULL;
    }
2310

2311 2312 2313 2314
    if (device->declArraySize == device->numConvertedDecls)
    {
        UINT grow = device->declArraySize / 2;

2315
        convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls,
2316
                sizeof(*convertedDecls) * (device->numConvertedDecls + grow));
2317 2318 2319
        if (!convertedDecls)
        {
            d3d8_vertex_declaration_destroy(d3d8_declaration);
2320 2321
            return NULL;
        }
2322 2323
        device->decls = convertedDecls;
        device->declArraySize += grow;
2324 2325
    }

2326 2327
    memmove(convertedDecls + low + 1, convertedDecls + low,
            sizeof(*convertedDecls) * (device->numConvertedDecls - low));
2328
    convertedDecls[low].declaration = d3d8_declaration;
2329
    convertedDecls[low].fvf = fvf;
2330 2331 2332
    ++device->numConvertedDecls;

    TRACE("Returning %p. %u decls in array.\n", d3d8_declaration, device->numConvertedDecls);
2333

2334
    return d3d8_declaration;
2335 2336
}

2337
static HRESULT WINAPI d3d8_device_SetVertexShader(IDirect3DDevice8 *iface, DWORD shader)
2338
{
2339 2340
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    struct d3d8_vertex_shader *shader_impl;
2341

2342
    TRACE("iface %p, shader %#x.\n", iface, shader);
2343

2344 2345 2346
    if (VS_HIGHESTFIXEDFXF >= shader)
    {
        TRACE("Setting FVF, %#x\n", shader);
2347

2348
        wined3d_mutex_lock();
2349 2350 2351
        wined3d_device_set_vertex_declaration(device->wined3d_device,
                d3d8_device_get_fvf_declaration(device, shader)->wined3d_vertex_declaration);
        wined3d_device_set_vertex_shader(device->wined3d_device, NULL);
2352 2353
        wined3d_mutex_unlock();

2354 2355
        return D3D_OK;
    }
2356

2357
    TRACE("Setting shader\n");
2358

2359
    wined3d_mutex_lock();
2360
    if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2361
    {
2362
        WARN("Invalid handle (%#x) passed.\n", shader);
2363 2364
        wined3d_mutex_unlock();

2365
        return D3DERR_INVALIDCALL;
2366
    }
2367

2368
    wined3d_device_set_vertex_declaration(device->wined3d_device,
2369
            shader_impl->vertex_declaration->wined3d_vertex_declaration);
2370
    wined3d_device_set_vertex_shader(device->wined3d_device, shader_impl->wined3d_shader);
2371
    wined3d_mutex_unlock();
2372

2373
    return D3D_OK;
2374
}
Raphael Junqueira's avatar
Raphael Junqueira committed
2375

2376
static HRESULT WINAPI d3d8_device_GetVertexShader(IDirect3DDevice8 *iface, DWORD *shader)
2377
{
2378
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2379
    struct wined3d_vertex_declaration *wined3d_declaration;
2380
    struct d3d8_vertex_declaration *d3d8_declaration;
2381

2382
    TRACE("iface %p, shader %p.\n", iface, shader);
2383

2384
    wined3d_mutex_lock();
2385
    if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
2386
    {
2387 2388
        d3d8_declaration = wined3d_vertex_declaration_get_parent(wined3d_declaration);
        *shader = d3d8_declaration->shader_handle;
2389
    }
2390
    else
2391
    {
2392
        *shader = 0;
2393
    }
2394
    wined3d_mutex_unlock();
2395

2396
    TRACE("Returning %#x.\n", *shader);
Raphael Junqueira's avatar
Raphael Junqueira committed
2397

2398
    return D3D_OK;
2399 2400
}

2401
static HRESULT WINAPI d3d8_device_DeleteVertexShader(IDirect3DDevice8 *iface, DWORD shader)
2402
{
2403 2404
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    struct d3d8_vertex_shader *shader_impl;
2405

2406
    TRACE("iface %p, shader %#x.\n", iface, shader);
2407

2408
    wined3d_mutex_lock();
2409
    if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2410
    {
2411
        WARN("Invalid handle (%#x) passed.\n", shader);
2412 2413
        wined3d_mutex_unlock();

2414
        return D3DERR_INVALIDCALL;
2415
    }
2416

2417 2418 2419
    if (shader_impl->wined3d_shader
            && wined3d_device_get_vertex_shader(device->wined3d_device) == shader_impl->wined3d_shader)
        IDirect3DDevice8_SetVertexShader(iface, 0);
2420

2421
    wined3d_mutex_unlock();
2422

2423
    d3d8_vertex_shader_destroy(shader_impl);
2424

2425
    return D3D_OK;
2426 2427
}

2428 2429
static HRESULT WINAPI d3d8_device_SetVertexShaderConstant(IDirect3DDevice8 *iface,
        DWORD start_register, const void *data, DWORD count)
2430
{
2431
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2432
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2433

2434 2435
    TRACE("iface %p, start_register %u, data %p, count %u.\n",
            iface, start_register, data, count);
2436

2437 2438
    if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
    {
2439
        WARN("Trying to access %u constants, but d3d8 only supports %u\n",
2440
             start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
2441 2442 2443
        return D3DERR_INVALIDCALL;
    }

2444
    wined3d_mutex_lock();
2445
    hr = wined3d_device_set_vs_consts_f(device->wined3d_device, start_register, data, count);
2446 2447
    wined3d_mutex_unlock();

2448
    return hr;
2449
}
2450

2451 2452
static HRESULT WINAPI d3d8_device_GetVertexShaderConstant(IDirect3DDevice8 *iface,
        DWORD start_register, void *data, DWORD count)
2453
{
2454
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2455
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2456

2457 2458
    TRACE("iface %p, start_register %u, data %p, count %u.\n",
            iface, start_register, data, count);
2459

2460 2461
    if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
    {
2462
        WARN("Trying to access %u constants, but d3d8 only supports %u\n",
2463
             start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
2464 2465 2466
        return D3DERR_INVALIDCALL;
    }

2467
    wined3d_mutex_lock();
2468
    hr = wined3d_device_get_vs_consts_f(device->wined3d_device, start_register, data, count);
2469 2470
    wined3d_mutex_unlock();

2471
    return hr;
2472
}
Raphael Junqueira's avatar
Raphael Junqueira committed
2473

2474 2475
static HRESULT WINAPI d3d8_device_GetVertexShaderDeclaration(IDirect3DDevice8 *iface,
        DWORD shader, void *data, DWORD *data_size)
2476
{
2477
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2478
    struct d3d8_vertex_declaration *declaration;
2479
    struct d3d8_vertex_shader *shader_impl;
Raphael Junqueira's avatar
Raphael Junqueira committed
2480

Henri Verbeet's avatar
Henri Verbeet committed
2481
    TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2482
            iface, shader, data, data_size);
2483

2484
    wined3d_mutex_lock();
2485
    shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS);
2486 2487
    wined3d_mutex_unlock();

2488
    if (!shader_impl)
2489
    {
2490
        WARN("Invalid handle (%#x) passed.\n", shader);
2491 2492
        return D3DERR_INVALIDCALL;
    }
2493
    declaration = shader_impl->vertex_declaration;
2494

2495 2496 2497
    if (!data)
    {
        *data_size = declaration->elements_size;
2498 2499 2500
        return D3D_OK;
    }

2501
    /* MSDN claims that if *data_size is smaller than the required size
2502 2503
     * we should write the required size and return D3DERR_MOREDATA.
     * That's not actually true. */
2504
    if (*data_size < declaration->elements_size)
2505 2506
        return D3DERR_INVALIDCALL;

2507
    memcpy(data, declaration->elements, declaration->elements_size);
2508 2509

    return D3D_OK;
2510
}
2511

2512 2513
static HRESULT WINAPI d3d8_device_GetVertexShaderFunction(IDirect3DDevice8 *iface,
        DWORD shader, void *data, DWORD *data_size)
2514
{
2515 2516
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    struct d3d8_vertex_shader *shader_impl = NULL;
2517
    HRESULT hr;
Raphael Junqueira's avatar
Raphael Junqueira committed
2518

Henri Verbeet's avatar
Henri Verbeet committed
2519
    TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2520
            iface, shader, data, data_size);
2521

2522
    wined3d_mutex_lock();
2523
    if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2524
    {
2525
        WARN("Invalid handle (%#x) passed.\n", shader);
2526 2527
        wined3d_mutex_unlock();

2528 2529 2530
        return D3DERR_INVALIDCALL;
    }

2531
    if (!shader_impl->wined3d_shader)
2532
    {
2533
        wined3d_mutex_unlock();
2534
        *data_size = 0;
2535
        return D3D_OK;
2536 2537
    }

2538
    hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
2539
    wined3d_mutex_unlock();
2540

2541
    return hr;
2542 2543
}

2544 2545
static HRESULT WINAPI d3d8_device_SetIndices(IDirect3DDevice8 *iface,
        IDirect3DIndexBuffer8 *buffer, UINT base_vertex_idx)
2546
{
2547
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2548
    struct d3d8_indexbuffer *ib = unsafe_impl_from_IDirect3DIndexBuffer8(buffer);
Henri Verbeet's avatar
Henri Verbeet committed
2549

2550
    TRACE("iface %p, buffer %p, base_vertex_idx %u.\n", iface, buffer, base_vertex_idx);
2551

2552 2553 2554 2555 2556 2557
    /* WineD3D takes an INT(due to d3d9), but d3d8 uses UINTs. Do I have to add a check here that
     * the UINT doesn't cause an overflow in the INT? It seems rather unlikely because such large
     * vertex buffers can't be created to address them with an index that requires the 32nd bit
     * (4 Byte minimum vertex size * 2^31-1 -> 8 gb buffer. The index sign would be the least
     * problem)
     */
2558
    wined3d_mutex_lock();
2559
    wined3d_device_set_base_vertex_index(device->wined3d_device, base_vertex_idx);
2560
    wined3d_device_set_index_buffer(device->wined3d_device,
2561
            ib ? ib->wined3d_buffer : NULL,
2562
            ib ? ib->format : WINED3DFMT_UNKNOWN);
2563 2564
    wined3d_mutex_unlock();

2565
    return D3D_OK;
2566
}
2567

2568 2569
static HRESULT WINAPI d3d8_device_GetIndices(IDirect3DDevice8 *iface,
        IDirect3DIndexBuffer8 **buffer, UINT *base_vertex_index)
2570
{
2571
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2572
    enum wined3d_format_id wined3d_format;
2573
    struct wined3d_buffer *wined3d_buffer;
2574
    struct d3d8_indexbuffer *buffer_impl;
2575

2576
    TRACE("iface %p, buffer %p, base_vertex_index %p.\n", iface, buffer, base_vertex_index);
2577

2578
    if (!buffer)
2579
        return D3DERR_INVALIDCALL;
2580

2581
    /* The case from UINT to INT is safe because d3d8 will never set negative values */
2582
    wined3d_mutex_lock();
2583
    *base_vertex_index = wined3d_device_get_base_vertex_index(device->wined3d_device);
2584
    if ((wined3d_buffer = wined3d_device_get_index_buffer(device->wined3d_device, &wined3d_format)))
2585 2586 2587 2588 2589 2590
    {
        buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
        *buffer = &buffer_impl->IDirect3DIndexBuffer8_iface;
        IDirect3DIndexBuffer8_AddRef(*buffer);
    }
    else
2591
    {
2592
        *buffer = NULL;
2593
    }
2594
    wined3d_mutex_unlock();
2595

2596
    return D3D_OK;
2597
}
2598

2599
static HRESULT WINAPI d3d8_device_CreatePixelShader(IDirect3DDevice8 *iface,
2600 2601
        const DWORD *byte_code, DWORD *shader)
{
2602
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2603
    struct d3d8_pixel_shader *object;
2604
    DWORD shader_handle;
2605 2606
    DWORD handle;
    HRESULT hr;
2607

2608
    TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);
2609

2610
    if (!shader)
2611
        return D3DERR_INVALIDCALL;
2612

2613 2614
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
2615 2616
        return E_OUTOFMEMORY;

2617
    wined3d_mutex_lock();
2618
    handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_PS);
2619
    wined3d_mutex_unlock();
2620 2621
    if (handle == D3D8_INVALID_HANDLE)
    {
2622 2623
        ERR("Failed to allocate pixel shader handle.\n");
        HeapFree(GetProcessHeap(), 0, object);
2624 2625 2626
        return E_OUTOFMEMORY;
    }

2627
    shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
2628

2629
    hr = d3d8_pixel_shader_init(object, device, byte_code, shader_handle);
2630 2631 2632 2633
    if (FAILED(hr))
    {
        WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
        wined3d_mutex_lock();
2634
        d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_PS);
2635 2636 2637 2638 2639 2640 2641 2642 2643 2644
        wined3d_mutex_unlock();
        HeapFree(GetProcessHeap(), 0, object);
        *shader = 0;
        return hr;
    }

    TRACE("Created pixel shader %p (handle %#x).\n", object, shader_handle);
    *shader = shader_handle;

    return D3D_OK;
2645
}
2646

2647
static HRESULT WINAPI d3d8_device_SetPixelShader(IDirect3DDevice8 *iface, DWORD shader)
2648
{
2649 2650
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    struct d3d8_pixel_shader *shader_impl;
2651

2652
    TRACE("iface %p, shader %#x.\n", iface, shader);
2653

2654
    wined3d_mutex_lock();
2655

2656
    if (!shader)
2657
    {
2658
        wined3d_device_set_pixel_shader(device->wined3d_device, NULL);
2659
        wined3d_mutex_unlock();
2660
        return D3D_OK;
2661 2662
    }

2663
    if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2664
    {
2665
        WARN("Invalid handle (%#x) passed.\n", shader);
2666
        wined3d_mutex_unlock();
2667
        return D3DERR_INVALIDCALL;
2668 2669
    }

2670
    TRACE("Setting shader %p.\n", shader_impl);
2671
    wined3d_device_set_pixel_shader(device->wined3d_device, shader_impl->wined3d_shader);
2672 2673
    wined3d_mutex_unlock();

2674
    return D3D_OK;
2675
}
2676

2677
static HRESULT WINAPI d3d8_device_GetPixelShader(IDirect3DDevice8 *iface, DWORD *shader)
2678
{
2679
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2680
    struct wined3d_shader *object;
Henri Verbeet's avatar
Henri Verbeet committed
2681

2682
    TRACE("iface %p, shader %p.\n", iface, shader);
Henri Verbeet's avatar
Henri Verbeet committed
2683

2684
    if (!shader)
2685
        return D3DERR_INVALIDCALL;
2686

2687
    wined3d_mutex_lock();
2688
    if ((object = wined3d_device_get_pixel_shader(device->wined3d_device)))
2689
    {
2690
        struct d3d8_pixel_shader *d3d8_shader;
2691
        d3d8_shader = wined3d_shader_get_parent(object);
2692
        *shader = d3d8_shader->handle;
2693 2694 2695
    }
    else
    {
2696
        *shader = 0;
2697
    }
2698
    wined3d_mutex_unlock();
2699

2700
    TRACE("Returning %#x.\n", *shader);
2701

2702
    return D3D_OK;
2703 2704
}

2705
static HRESULT WINAPI d3d8_device_DeletePixelShader(IDirect3DDevice8 *iface, DWORD shader)
2706
{
2707 2708
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    struct d3d8_pixel_shader *shader_impl;
Raphael Junqueira's avatar
Raphael Junqueira committed
2709

2710
    TRACE("iface %p, shader %#x.\n", iface, shader);
2711

2712
    wined3d_mutex_lock();
2713

2714
    if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2715
    {
2716
        WARN("Invalid handle (%#x) passed.\n", shader);
2717
        wined3d_mutex_unlock();
2718
        return D3DERR_INVALIDCALL;
2719
    }
2720

2721 2722
    if (wined3d_device_get_pixel_shader(device->wined3d_device) == shader_impl->wined3d_shader)
        IDirect3DDevice8_SetPixelShader(iface, 0);
2723

2724
    wined3d_mutex_unlock();
2725

2726
    d3d8_pixel_shader_destroy(shader_impl);
2727

Raphael Junqueira's avatar
Raphael Junqueira committed
2728
    return D3D_OK;
2729
}
Raphael Junqueira's avatar
Raphael Junqueira committed
2730

2731 2732
static HRESULT WINAPI d3d8_device_SetPixelShaderConstant(IDirect3DDevice8 *iface,
        DWORD start_register, const void *data, DWORD count)
2733
{
2734
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2735
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2736

2737 2738
    TRACE("iface %p, start_register %u, data %p, count %u.\n",
            iface, start_register, data, count);
2739

2740
    wined3d_mutex_lock();
2741
    hr = wined3d_device_set_ps_consts_f(device->wined3d_device, start_register, data, count);
2742 2743
    wined3d_mutex_unlock();

2744
    return hr;
2745
}
2746

2747 2748
static HRESULT WINAPI d3d8_device_GetPixelShaderConstant(IDirect3DDevice8 *iface,
        DWORD start_register, void *data, DWORD count)
2749
{
2750
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2751
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2752

2753 2754
    TRACE("iface %p, start_register %u, data %p, count %u.\n",
            iface, start_register, data, count);
2755

2756
    wined3d_mutex_lock();
2757
    hr = wined3d_device_get_ps_consts_f(device->wined3d_device, start_register, data, count);
2758 2759
    wined3d_mutex_unlock();

2760
    return hr;
2761
}
Raphael Junqueira's avatar
Raphael Junqueira committed
2762

2763 2764
static HRESULT WINAPI d3d8_device_GetPixelShaderFunction(IDirect3DDevice8 *iface,
        DWORD shader, void *data, DWORD *data_size)
2765
{
2766 2767
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
    struct d3d8_pixel_shader *shader_impl = NULL;
2768
    HRESULT hr;
2769

Henri Verbeet's avatar
Henri Verbeet committed
2770
    TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2771
            iface, shader, data, data_size);
2772

2773
    wined3d_mutex_lock();
2774
    if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2775
    {
2776
        WARN("Invalid handle (%#x) passed.\n", shader);
2777 2778
        wined3d_mutex_unlock();

2779 2780 2781
        return D3DERR_INVALIDCALL;
    }

2782
    hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
2783 2784
    wined3d_mutex_unlock();

2785
    return hr;
2786
}
2787

2788 2789
static HRESULT WINAPI d3d8_device_DrawRectPatch(IDirect3DDevice8 *iface, UINT handle,
        const float *segment_count, const D3DRECTPATCH_INFO *patch_info)
2790
{
2791
    FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
2792
            iface, handle, segment_count, patch_info);
2793
    return D3D_OK;
2794
}
2795

2796 2797
static HRESULT WINAPI d3d8_device_DrawTriPatch(IDirect3DDevice8 *iface, UINT handle,
        const float *segment_count, const D3DTRIPATCH_INFO *patch_info)
2798
{
2799
    FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
2800
            iface, handle, segment_count, patch_info);
2801
    return D3D_OK;
2802
}
2803

2804
static HRESULT WINAPI d3d8_device_DeletePatch(IDirect3DDevice8 *iface, UINT handle)
2805
{
2806 2807
    FIXME("iface %p, handle %#x unimplemented.\n", iface, handle);
    return D3DERR_INVALIDCALL;
2808 2809
}

2810 2811
static HRESULT WINAPI d3d8_device_SetStreamSource(IDirect3DDevice8 *iface,
        UINT stream_idx, IDirect3DVertexBuffer8 *buffer, UINT stride)
2812
{
2813
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2814
    struct d3d8_vertexbuffer *buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer8(buffer);
2815
    HRESULT hr;
Henri Verbeet's avatar
Henri Verbeet committed
2816 2817

    TRACE("iface %p, stream_idx %u, buffer %p, stride %u.\n",
2818
            iface, stream_idx, buffer, stride);
2819

2820
    wined3d_mutex_lock();
2821
    hr = wined3d_device_set_stream_source(device->wined3d_device, stream_idx,
2822
            buffer_impl ? buffer_impl->wined3d_buffer : NULL, 0, stride);
2823 2824
    wined3d_mutex_unlock();

2825
    return hr;
2826
}
2827

2828 2829
static HRESULT WINAPI d3d8_device_GetStreamSource(IDirect3DDevice8 *iface,
        UINT stream_idx, IDirect3DVertexBuffer8 **buffer, UINT *stride)
2830
{
2831
    struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2832
    struct d3d8_vertexbuffer *buffer_impl;
2833
    struct wined3d_buffer *wined3d_buffer = NULL;
2834
    HRESULT hr;
2835

Henri Verbeet's avatar
Henri Verbeet committed
2836
    TRACE("iface %p, stream_idx %u, buffer %p, stride %p.\n",
2837
            iface, stream_idx, buffer, stride);
2838

2839
    if (!buffer)
2840
        return D3DERR_INVALIDCALL;
2841

2842
    wined3d_mutex_lock();
2843 2844
    hr = wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, 0, stride);
    if (SUCCEEDED(hr) && wined3d_buffer)
2845
    {
2846 2847 2848
        buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
        *buffer = &buffer_impl->IDirect3DVertexBuffer8_iface;
        IDirect3DVertexBuffer8_AddRef(*buffer);
2849 2850 2851
    }
    else
    {
2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959
        if (FAILED(hr))
            ERR("Failed to get wined3d stream source, hr %#x.\n", hr);
        *buffer = NULL;
    }
    wined3d_mutex_unlock();

    return hr;
}

static const struct IDirect3DDevice8Vtbl d3d8_device_vtbl =
{
    d3d8_device_QueryInterface,
    d3d8_device_AddRef,
    d3d8_device_Release,
    d3d8_device_TestCooperativeLevel,
    d3d8_device_GetAvailableTextureMem,
    d3d8_device_ResourceManagerDiscardBytes,
    d3d8_device_GetDirect3D,
    d3d8_device_GetDeviceCaps,
    d3d8_device_GetDisplayMode,
    d3d8_device_GetCreationParameters,
    d3d8_device_SetCursorProperties,
    d3d8_device_SetCursorPosition,
    d3d8_device_ShowCursor,
    d3d8_device_CreateAdditionalSwapChain,
    d3d8_device_Reset,
    d3d8_device_Present,
    d3d8_device_GetBackBuffer,
    d3d8_device_GetRasterStatus,
    d3d8_device_SetGammaRamp,
    d3d8_device_GetGammaRamp,
    d3d8_device_CreateTexture,
    d3d8_device_CreateVolumeTexture,
    d3d8_device_CreateCubeTexture,
    d3d8_device_CreateVertexBuffer,
    d3d8_device_CreateIndexBuffer,
    d3d8_device_CreateRenderTarget,
    d3d8_device_CreateDepthStencilSurface,
    d3d8_device_CreateImageSurface,
    d3d8_device_CopyRects,
    d3d8_device_UpdateTexture,
    d3d8_device_GetFrontBuffer,
    d3d8_device_SetRenderTarget,
    d3d8_device_GetRenderTarget,
    d3d8_device_GetDepthStencilSurface,
    d3d8_device_BeginScene,
    d3d8_device_EndScene,
    d3d8_device_Clear,
    d3d8_device_SetTransform,
    d3d8_device_GetTransform,
    d3d8_device_MultiplyTransform,
    d3d8_device_SetViewport,
    d3d8_device_GetViewport,
    d3d8_device_SetMaterial,
    d3d8_device_GetMaterial,
    d3d8_device_SetLight,
    d3d8_device_GetLight,
    d3d8_device_LightEnable,
    d3d8_device_GetLightEnable,
    d3d8_device_SetClipPlane,
    d3d8_device_GetClipPlane,
    d3d8_device_SetRenderState,
    d3d8_device_GetRenderState,
    d3d8_device_BeginStateBlock,
    d3d8_device_EndStateBlock,
    d3d8_device_ApplyStateBlock,
    d3d8_device_CaptureStateBlock,
    d3d8_device_DeleteStateBlock,
    d3d8_device_CreateStateBlock,
    d3d8_device_SetClipStatus,
    d3d8_device_GetClipStatus,
    d3d8_device_GetTexture,
    d3d8_device_SetTexture,
    d3d8_device_GetTextureStageState,
    d3d8_device_SetTextureStageState,
    d3d8_device_ValidateDevice,
    d3d8_device_GetInfo,
    d3d8_device_SetPaletteEntries,
    d3d8_device_GetPaletteEntries,
    d3d8_device_SetCurrentTexturePalette,
    d3d8_device_GetCurrentTexturePalette,
    d3d8_device_DrawPrimitive,
    d3d8_device_DrawIndexedPrimitive,
    d3d8_device_DrawPrimitiveUP,
    d3d8_device_DrawIndexedPrimitiveUP,
    d3d8_device_ProcessVertices,
    d3d8_device_CreateVertexShader,
    d3d8_device_SetVertexShader,
    d3d8_device_GetVertexShader,
    d3d8_device_DeleteVertexShader,
    d3d8_device_SetVertexShaderConstant,
    d3d8_device_GetVertexShaderConstant,
    d3d8_device_GetVertexShaderDeclaration,
    d3d8_device_GetVertexShaderFunction,
    d3d8_device_SetStreamSource,
    d3d8_device_GetStreamSource,
    d3d8_device_SetIndices,
    d3d8_device_GetIndices,
    d3d8_device_CreatePixelShader,
    d3d8_device_SetPixelShader,
    d3d8_device_GetPixelShader,
    d3d8_device_DeletePixelShader,
    d3d8_device_SetPixelShaderConstant,
    d3d8_device_GetPixelShaderConstant,
    d3d8_device_GetPixelShaderFunction,
    d3d8_device_DrawRectPatch,
    d3d8_device_DrawTriPatch,
    d3d8_device_DeletePatch,
2960
};
2961

2962
static inline struct d3d8_device *device_from_device_parent(struct wined3d_device_parent *device_parent)
2963
{
2964
    return CONTAINING_RECORD(device_parent, struct d3d8_device, device_parent);
2965 2966
}

2967
static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
2968
        struct wined3d_device *device)
2969
{
2970
    TRACE("device_parent %p, device %p\n", device_parent, device);
2971 2972
}

2973 2974 2975 2976 2977
static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
{
    TRACE("device_parent %p.\n", device_parent);
}

2978 2979
static void CDECL device_parent_activate(struct wined3d_device_parent *device_parent, BOOL activate)
{
2980 2981
    struct d3d8_device *device = device_from_device_parent(device_parent);

2982
    TRACE("device_parent %p, activate %#x.\n", device_parent, activate);
2983 2984 2985 2986 2987

    if (!activate)
        InterlockedCompareExchange(&device->device_state, D3D8_DEVICE_STATE_LOST, D3D8_DEVICE_STATE_OK);
    else
        InterlockedCompareExchange(&device->device_state, D3D8_DEVICE_STATE_NOT_RESET, D3D8_DEVICE_STATE_LOST);
2988 2989
}

2990
static HRESULT CDECL device_parent_surface_created(struct wined3d_device_parent *device_parent,
2991 2992
        struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
        void **parent, const struct wined3d_parent_ops **parent_ops)
2993
{
2994
    struct d3d8_surface *d3d_surface;
2995

2996 2997
    TRACE("device_parent %p, wined3d_texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
            device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
2998

2999
    if (!(d3d_surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d_surface))))
3000
        return E_OUTOFMEMORY;
3001

3002
    surface_init(d3d_surface, wined3d_texture, sub_resource_idx, parent_ops);
3003
    *parent = d3d_surface;
3004 3005
    TRACE("Created surface %p.\n", d3d_surface);

3006
    return D3D_OK;
3007 3008
}

3009
static HRESULT CDECL device_parent_volume_created(struct wined3d_device_parent *device_parent,
3010
        struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
3011
        void **parent, const struct wined3d_parent_ops **parent_ops)
3012 3013 3014
{
    struct d3d8_volume *d3d_volume;

3015 3016
    TRACE("device_parent %p, texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
            device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
3017 3018 3019 3020

    if (!(d3d_volume = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d_volume))))
        return E_OUTOFMEMORY;

3021
    volume_init(d3d_volume, wined3d_texture, sub_resource_idx, parent_ops);
3022 3023 3024 3025 3026 3027
    *parent = d3d_volume;
    TRACE("Created volume %p.\n", d3d_volume);

    return D3D_OK;
}

3028 3029
static HRESULT CDECL device_parent_create_swapchain_texture(struct wined3d_device_parent *device_parent,
        void *container_parent, const struct wined3d_resource_desc *desc, struct wined3d_texture **texture)
3030
{
3031
    struct d3d8_device *device = device_from_device_parent(device_parent);
3032
    struct d3d8_surface *d3d_surface;
3033 3034
    HRESULT hr;

3035 3036
    TRACE("device_parent %p, container_parent %p, desc %p, texture %p.\n",
            device_parent, container_parent, desc, texture);
3037

3038 3039
    if (FAILED(hr = wined3d_texture_create(device->wined3d_device, desc, 1, WINED3D_TEXTURE_CREATE_MAPPABLE,
            NULL, &device->IDirect3DDevice8_iface, &d3d8_null_wined3d_parent_ops, texture)))
3040
    {
3041
        WARN("Failed to create texture, hr %#x.\n", hr);
3042 3043 3044
        return hr;
    }

3045
    d3d_surface = wined3d_texture_get_sub_resource_parent(*texture, 0);
3046
    d3d_surface->parent_device = &device->IDirect3DDevice8_iface;
3047 3048 3049 3050

    return hr;
}

3051
static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
3052
        struct wined3d_swapchain_desc *desc, struct wined3d_swapchain **swapchain)
3053
{
3054
    struct d3d8_device *device = device_from_device_parent(device_parent);
3055
    struct d3d8_swapchain *d3d_swapchain;
3056 3057
    HRESULT hr;

3058
    TRACE("device_parent %p, desc %p, swapchain %p.\n", device_parent, desc, swapchain);
3059

3060
    if (FAILED(hr = d3d8_swapchain_create(device, desc, &d3d_swapchain)))
3061
    {
3062
        WARN("Failed to create swapchain, hr %#x.\n", hr);
3063 3064 3065 3066
        *swapchain = NULL;
        return hr;
    }

3067
    *swapchain = d3d_swapchain->wined3d_swapchain;
3068
    wined3d_swapchain_incref(*swapchain);
3069
    IDirect3DSwapChain8_Release(&d3d_swapchain->IDirect3DSwapChain8_iface);
3070 3071 3072 3073

    return hr;
}

3074
static const struct wined3d_device_parent_ops d3d8_wined3d_device_parent_ops =
3075
{
3076
    device_parent_wined3d_device_created,
3077
    device_parent_mode_changed,
3078
    device_parent_activate,
3079
    device_parent_surface_created,
3080
    device_parent_volume_created,
3081
    device_parent_create_swapchain_texture,
3082
    device_parent_create_swapchain,
3083
};
3084

3085 3086 3087
static void setup_fpu(void)
{
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3088
    WORD cw;
3089 3090 3091
    __asm__ volatile ("fnstcw %0" : "=m" (cw));
    cw = (cw & ~0xf3f) | 0x3f;
    __asm__ volatile ("fldcw %0" : : "m" (cw));
3092 3093 3094 3095 3096
#elif defined(__i386__) && defined(_MSC_VER)
    WORD cw;
    __asm fnstcw cw;
    cw = (cw & ~0xf3f) | 0x3f;
    __asm fldcw cw;
3097 3098 3099 3100 3101
#else
    FIXME("FPU setup not implemented for this platform.\n");
#endif
}

3102
HRESULT device_init(struct d3d8_device *device, struct d3d8 *parent, struct wined3d *wined3d, UINT adapter,
3103 3104
        D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters)
{
3105
    struct wined3d_swapchain_desc swapchain_desc;
3106
    struct wined3d_swapchain *wined3d_swapchain;
3107 3108
    HRESULT hr;

3109
    device->IDirect3DDevice8_iface.lpVtbl = &d3d8_device_vtbl;
3110
    device->device_parent.ops = &d3d8_wined3d_device_parent_ops;
3111 3112 3113 3114 3115 3116 3117 3118 3119 3120
    device->ref = 1;
    device->handle_table.entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
            D3D8_INITIAL_HANDLE_TABLE_SIZE * sizeof(*device->handle_table.entries));
    if (!device->handle_table.entries)
    {
        ERR("Failed to allocate handle table memory.\n");
        return E_OUTOFMEMORY;
    }
    device->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE;

3121 3122
    if (!(flags & D3DCREATE_FPU_PRESERVE)) setup_fpu();

3123
    wined3d_mutex_lock();
3124
    hr = wined3d_device_create(wined3d, adapter, device_type, focus_window, flags, 4,
3125
            &device->device_parent, &device->wined3d_device);
3126 3127 3128 3129 3130 3131 3132 3133
    if (FAILED(hr))
    {
        WARN("Failed to create wined3d device, hr %#x.\n", hr);
        wined3d_mutex_unlock();
        HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
        return hr;
    }

3134 3135
    if (!parameters->Windowed)
    {
3136 3137
        HWND device_window = parameters->hDeviceWindow;

3138 3139 3140
        if (!focus_window)
            focus_window = device_window;
        if (FAILED(hr = wined3d_device_acquire_focus_window(device->wined3d_device, focus_window)))
3141 3142
        {
            ERR("Failed to acquire focus window, hr %#x.\n", hr);
3143
            wined3d_device_decref(device->wined3d_device);
3144 3145 3146 3147
            wined3d_mutex_unlock();
            HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
            return hr;
        }
3148

3149 3150 3151
        if (!device_window)
            device_window = focus_window;
        wined3d_device_setup_fullscreen_window(device->wined3d_device, device_window,
3152 3153
                parameters->BackBufferWidth,
                parameters->BackBufferHeight);
3154 3155
    }

3156 3157
    if (flags & D3DCREATE_MULTITHREADED)
        wined3d_device_set_multithreaded(device->wined3d_device);
3158

3159 3160 3161 3162 3163 3164 3165 3166
    if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, parameters))
    {
        wined3d_device_release_focus_window(device->wined3d_device);
        wined3d_device_decref(device->wined3d_device);
        wined3d_mutex_unlock();
        HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
        return D3DERR_INVALIDCALL;
    }
3167 3168

    hr = wined3d_device_init_3d(device->wined3d_device, &swapchain_desc);
3169 3170 3171
    if (FAILED(hr))
    {
        WARN("Failed to initialize 3D, hr %#x.\n", hr);
3172 3173
        wined3d_device_release_focus_window(device->wined3d_device);
        wined3d_device_decref(device->wined3d_device);
3174 3175 3176 3177 3178
        wined3d_mutex_unlock();
        HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
        return hr;
    }

3179
    wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
3180 3181
    wined3d_mutex_unlock();

3182
    present_parameters_from_wined3d_swapchain_desc(parameters, &swapchain_desc);
3183 3184 3185 3186 3187

    device->declArraySize = 16;
    device->decls = HeapAlloc(GetProcessHeap(), 0, device->declArraySize * sizeof(*device->decls));
    if (!device->decls)
    {
3188
        ERR("Failed to allocate FVF vertex declaration map memory.\n");
3189 3190 3191 3192
        hr = E_OUTOFMEMORY;
        goto err;
    }

3193 3194 3195
    wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, 0);
    device->implicit_swapchain = wined3d_swapchain_get_parent(wined3d_swapchain);

3196 3197 3198
    device->d3d_parent = &parent->IDirect3D8_iface;
    IDirect3D8_AddRef(device->d3d_parent);

3199 3200 3201 3202
    return D3D_OK;

err:
    wined3d_mutex_lock();
3203 3204 3205
    wined3d_device_uninit_3d(device->wined3d_device);
    wined3d_device_release_focus_window(device->wined3d_device);
    wined3d_device_decref(device->wined3d_device);
3206 3207 3208 3209
    wined3d_mutex_unlock();
    HeapFree(GetProcessHeap(), 0, device->handle_table.entries);
    return hr;
}