device.c 278 KB
Newer Older
1 2 3
/*
 * IWineD3DDevice implementation
 *
4
 * Copyright 2002 Lionel Ulmer
5
 * Copyright 2002-2005 Jason Edmeades
6 7
 * Copyright 2003-2004 Raphael Junqueira
 * Copyright 2004 Christian Costa
8
 * Copyright 2005 Oliver Stieber
9
 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10
 * Copyright 2006-2008 Henri Verbeet
11
 * Copyright 2007 Andrew Riedi
12
 * Copyright 2009 Henri Verbeet for CodeWeavers
13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * 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
26
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 28 29
 */

#include "config.h"
30
#include <stdio.h>
31 32 33
#ifdef HAVE_FLOAT_H
# include <float.h>
#endif
34 35 36
#include "wined3d_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37
#define GLINFO_LOCATION This->adapter->gl_info
38

39 40 41
/* Define the default light parameters as specified by MSDN */
const WINED3DLIGHT WINED3D_default_light = {

42 43 44 45 46 47 48 49 50 51 52
    WINED3DLIGHT_DIRECTIONAL,   /* Type */
    { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
    { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
    { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
    { 0.0f, 0.0f, 0.0f },       /* Position x,y,z */
    { 0.0f, 0.0f, 1.0f },       /* Direction x,y,z */
    0.0f,                       /* Range */
    0.0f,                       /* Falloff */
    0.0f, 0.0f, 0.0f,           /* Attenuation 0,1,2 */
    0.0f,                       /* Theta */
    0.0f                        /* Phi */
53 54
};

55
/**********************************************************
56
 * Global variable / Constants follow
57
 **********************************************************/
58 59 60 61 62 63 64
const float identity[] =
{
    1.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 1.0f,
};  /* When needed for comparisons */
65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
/* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
 * actually have the same values in GL and D3D. */
static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
{
    switch(primitive_type)
    {
        case WINED3DPT_POINTLIST:
            return GL_POINTS;

        case WINED3DPT_LINELIST:
            return GL_LINES;

        case WINED3DPT_LINESTRIP:
            return GL_LINE_STRIP;

        case WINED3DPT_TRIANGLELIST:
            return GL_TRIANGLES;

        case WINED3DPT_TRIANGLESTRIP:
            return GL_TRIANGLE_STRIP;

        case WINED3DPT_TRIANGLEFAN:
            return GL_TRIANGLE_FAN;

        case WINED3DPT_LINELIST_ADJ:
            return GL_LINES_ADJACENCY_ARB;

        case WINED3DPT_LINESTRIP_ADJ:
            return GL_LINE_STRIP_ADJACENCY_ARB;

        case WINED3DPT_TRIANGLELIST_ADJ:
            return GL_TRIANGLES_ADJACENCY_ARB;

        case WINED3DPT_TRIANGLESTRIP_ADJ:
            return GL_TRIANGLE_STRIP_ADJACENCY_ARB;

        default:
            FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
            return GL_NONE;
    }
}

static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
{
    switch(primitive_type)
    {
        case GL_POINTS:
            return WINED3DPT_POINTLIST;

        case GL_LINES:
            return WINED3DPT_LINELIST;

        case GL_LINE_STRIP:
            return WINED3DPT_LINESTRIP;

        case GL_TRIANGLES:
            return WINED3DPT_TRIANGLELIST;

        case GL_TRIANGLE_STRIP:
            return WINED3DPT_TRIANGLESTRIP;

        case GL_TRIANGLE_FAN:
            return WINED3DPT_TRIANGLEFAN;

        case GL_LINES_ADJACENCY_ARB:
            return WINED3DPT_LINELIST_ADJ;

        case GL_LINE_STRIP_ADJACENCY_ARB:
            return WINED3DPT_LINESTRIP_ADJ;

        case GL_TRIANGLES_ADJACENCY_ARB:
            return WINED3DPT_TRIANGLELIST_ADJ;

        case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
            return WINED3DPT_TRIANGLESTRIP_ADJ;

        default:
            FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
            return WINED3DPT_UNDEFINED;
    }
}

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
{
    if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
        *regnum = WINED3D_FFP_POSITION;
    else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
        *regnum = WINED3D_FFP_BLENDWEIGHT;
    else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
        *regnum = WINED3D_FFP_BLENDINDICES;
    else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
        *regnum = WINED3D_FFP_NORMAL;
    else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
        *regnum = WINED3D_FFP_PSIZE;
    else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
        *regnum = WINED3D_FFP_DIFFUSE;
    else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
        *regnum = WINED3D_FFP_SPECULAR;
    else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
        *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
    else
    {
        FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
        *regnum = ~0U;
        return FALSE;
    }

    return TRUE;
}

176
/* Context activation is done by the caller. */
177 178 179 180 181 182 183 184 185
void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
        BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
{
    /* We need to deal with frequency data! */
    IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
    UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
    const DWORD *streams = declaration->streams;
    unsigned int i;

186 187
    stream_info->use_map = 0;
    stream_info->swizzle_map = 0;
188 189 190 191 192 193

    /* Check for transformed vertices, disable vertex shader if present. */
    stream_info->position_transformed = declaration->position_transformed;
    if (declaration->position_transformed) use_vshader = FALSE;

    /* Translate the declaration into strided data. */
194
    for (i = 0; i < declaration->element_count; ++i)
195
    {
196
        const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 198 199 200 201 202
        GLuint buffer_object = 0;
        const BYTE *data = NULL;
        BOOL stride_used;
        unsigned int idx;
        DWORD stride;

203 204
        TRACE("%p Element %p (%u of %u)\n", declaration->elements,
                element, i + 1, declaration->element_count);
205

206
        if (!This->stateBlock->streamSource[element->input_slot]) continue;
207

208
        stride = This->stateBlock->streamStride[element->input_slot];
209 210
        if (This->stateBlock->streamIsUP)
        {
211
            TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212
            buffer_object = 0;
213
            data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
214 215 216
        }
        else
        {
217 218
            TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
            data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
219 220 221 222 223 224 225 226 227 228

            /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
             * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
             * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
             * around to some big value. Hope that with the indices, the driver wraps it back internally. If
             * not, drawStridedSlow is needed, including a vertex buffer path. */
            if (This->stateBlock->loadBaseVertexIndex < 0)
            {
                WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
                buffer_object = 0;
229
                data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 231 232 233 234 235 236 237 238 239
                if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
                {
                    FIXME("System memory vertex data load offset is negative!\n");
                }
            }

            if (fixup)
            {
                if (buffer_object) *fixup = TRUE;
                else if (*fixup && !use_vshader
240 241
                        && (element->usage == WINED3DDECLUSAGE_COLOR
                        || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 243 244 245 246 247 248 249 250 251 252
                {
                    static BOOL warned = FALSE;
                    if (!warned)
                    {
                        /* This may be bad with the fixed function pipeline. */
                        FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
                        warned = TRUE;
                    }
                }
            }
        }
253
        data += element->offset;
254

255
        TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256 257 258

        if (use_vshader)
        {
259 260 261 262 263 264 265 266 267 268 269 270 271
            if (element->output_slot == ~0U)
            {
                /* TODO: Assuming vertexdeclarations are usually used with the
                 * same or a similar shader, it might be worth it to store the
                 * last used output slot and try that one first. */
                stride_used = vshader_get_input(This->stateBlock->vertexShader,
                        element->usage, element->usage_idx, &idx);
            }
            else
            {
                idx = element->output_slot;
                stride_used = TRUE;
            }
272 273 274
        }
        else
        {
275
            if (!element->ffp_valid)
276
            {
277 278
                WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
                        debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 280 281 282
                stride_used = FALSE;
            }
            else
            {
283
                stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
284 285 286 287 288 289
            }
        }

        if (stride_used)
        {
            TRACE("Load %s array %u [usage %s, usage_idx %u, "
290
                    "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291
                    use_vshader ? "shader": "fixed function", idx,
292 293 294
                    debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
                    element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);

295
            stream_info->elements[idx].format_desc = element->format_desc;
296 297
            stream_info->elements[idx].stride = stride;
            stream_info->elements[idx].data = data;
298
            stream_info->elements[idx].stream_idx = element->input_slot;
299 300
            stream_info->elements[idx].buffer_object = buffer_object;

301
            if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
            {
                stream_info->swizzle_map |= 1 << idx;
            }
            stream_info->use_map |= 1 << idx;
        }
    }

    /* Now call PreLoad on all the vertex buffers. In the very rare case
     * that the buffers stopps converting PreLoad will dirtify the VDECL again.
     * The vertex buffer can now use the strided structure in the device instead of finding its
     * own again.
     *
     * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
     * once in there. */
    for (i = 0; i < stream_count; ++i)
    {
        IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
        if (vb) IWineD3DBuffer_PreLoad(vb);
    }
}

static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
        const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
{
326
    const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327
    e->format_desc = format_desc;
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
    e->stride = strided->dwStride;
    e->data = strided->lpData;
    e->stream_idx = 0;
    e->buffer_object = 0;
}

void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
        const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
{
    unsigned int i;

    memset(stream_info, 0, sizeof(*stream_info));

    if (strided->position.lpData)
        stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
    if (strided->normal.lpData)
        stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
    if (strided->diffuse.lpData)
        stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
    if (strided->specular.lpData)
        stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);

    for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
    {
        if (strided->texCoords[i].lpData)
            stream_info_element_from_strided(This, &strided->texCoords[i],
                    &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
    }

    stream_info->position_transformed = strided->position_transformed;

    for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
    {
361 362
        if (!stream_info->elements[i].format_desc) continue;

363 364
        if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA)
                && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
365 366 367 368 369 370
        {
            stream_info->swizzle_map |= 1 << i;
        }
        stream_info->use_map |= 1 << i;
    }
}
371

372 373 374 375
/**********************************************************
 * IUnknown parts follows
 **********************************************************/

376
static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
377
{
378
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
379

380
    TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
381
    if (IsEqualGUID(riid, &IID_IUnknown)
382
        || IsEqualGUID(riid, &IID_IWineD3DBase)
383 384 385
        || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
        IUnknown_AddRef(iface);
        *ppobj = This;
386
        return S_OK;
387
    }
388
    *ppobj = NULL;
389 390 391
    return E_NOINTERFACE;
}

392
static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
393 394 395
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    ULONG refCount = InterlockedIncrement(&This->ref);

396
    TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
397 398 399
    return refCount;
}

400
static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
401 402 403
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    ULONG refCount = InterlockedDecrement(&This->ref);

404
    TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
405 406

    if (!refCount) {
407 408 409 410 411 412 413
        UINT i;

        for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
            HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
            This->multistate_funcs[i] = NULL;
        }

414
        /* TODO: Clean up all the surfaces and textures! */
415 416
        /* NOTE: You must release the parent if the object was created via a callback
        ** ***************************/
417

418
        if (!list_empty(&This->resources)) {
419
            FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
420
            dumpResources(&This->resources);
421
        }
Oliver Stieber's avatar
Oliver Stieber committed
422

423
        if(This->contexts) ERR("Context array not freed!\n");
424 425
        if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
        This->haveHardwareCursor = FALSE;
426

427
        IWineD3D_Release(This->wineD3D);
428
        This->wineD3D = NULL;
429
        HeapFree(GetProcessHeap(), 0, This);
430
        TRACE("Freed device  %p\n", This);
431
        This = NULL;
432 433
    }
    return refCount;
434 435
}

436 437 438
/**********************************************************
 * IWineD3DDevice implementation follows
 **********************************************************/
439
static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
440 441 442
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    *pParent = This->parent;
    IUnknown_AddRef(This->parent);
443
    return WINED3D_OK;
444 445
}

446 447
static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
        const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
448 449 450 451 452
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    struct wined3d_buffer *object;
    HRESULT hr;

453
    TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
454 455 456 457 458 459 460 461 462 463

    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Failed to allocate memory\n");
        return E_OUTOFMEMORY;
    }

    FIXME("Ignoring access flags (pool)\n");

464 465
    hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
            WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
466 467
    if (FAILED(hr))
    {
468
        WARN("Failed to initialize buffer, hr %#x.\n", hr);
469 470 471
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
    }
472
    object->desc = *desc;
473

474
    TRACE("Created buffer %p.\n", object);
475

476 477 478 479 480
    *buffer = (IWineD3DBuffer *)object;

    return WINED3D_OK;
}

481 482 483
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
        DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
        IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
484
{
485
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
486
    struct wined3d_buffer *object;
487
    int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
488
    HRESULT hr;
489
    BOOL conv;
490

491 492
    if (Pool == WINED3DPOOL_SCRATCH)
    {
493
        /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
494
         * anyway, SCRATCH vertex buffers aren't usable anywhere
495 496
         */
        WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
497 498 499 500
        *ppVertexBuffer = NULL;
        return WINED3DERR_INVALIDCALL;
    }

501 502 503 504 505 506 507 508
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Out of memory\n");
        *ppVertexBuffer = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

509 510
    hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
            Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
511 512
    if (FAILED(hr))
    {
513
        WARN("Failed to initialize buffer, hr %#x.\n", hr);
514 515 516 517
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
    }

518 519
    TRACE("Created buffer %p.\n", object);
    TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
520
    *ppVertexBuffer = (IWineD3DBuffer *)object;
521 522 523 524 525 526 527 528 529

    /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
     * drawStridedFast (half-life 2).
     *
     * Basically converting the vertices in the buffer is quite expensive, and observations
     * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
     * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
     *
     * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
530
     * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
531 532 533 534 535 536
     * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
     * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
     * dx7 apps.
     * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
     * more. In this call we can convert dx7 buffers too.
     */
537
    conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
538 539 540 541 542 543 544 545 546
    if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
        TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
    } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
        TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
    } else if(Usage & WINED3DUSAGE_DYNAMIC) {
        TRACE("Not creating a vbo because the buffer has dynamic usage\n");
    } else if(dxVersion <= 7 && conv) {
        TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
    } else {
547
        object->flags |= WINED3D_BUFFER_CREATEBO;
548
    }
549
    return WINED3D_OK;
550
}
551

552
static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
553 554
        UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
        IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
555
{
556
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557
    struct wined3d_buffer *object;
558 559
    HRESULT hr;

560
    TRACE("(%p) Creating index buffer\n", This);
561

562
    /* Allocate the storage for the device */
563 564 565 566 567 568 569 570
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Out of memory\n");
        *ppIndexBuffer = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

571 572
    hr = buffer_init(object, This, Length, Usage, WINED3DFMT_UNKNOWN,
            Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
573 574
    if (FAILED(hr))
    {
575
        WARN("Failed to initialize buffer, hr %#x\n", hr);
576 577 578 579
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
    }

580
    TRACE("Created buffer %p.\n", object);
581

582
    if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
583
        object->flags |= WINED3D_BUFFER_CREATEBO;
584 585
    }

586
    *ppIndexBuffer = (IWineD3DBuffer *) object;
587

588
    return WINED3D_OK;
589 590
}

591 592 593 594
static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
        WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
595
    IWineD3DStateBlockImpl *object;
596
    HRESULT hr;
597

598 599 600
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if(!object)
    {
601 602
        ERR("Failed to allocate stateblock memory.\n");
        return E_OUTOFMEMORY;
603 604
    }

605 606
    hr = stateblock_init(object, This, type, parent);
    if (FAILED(hr))
607
    {
608
        WARN("Failed to initialize stateblock, hr %#x.\n", hr);
609
        HeapFree(GetProcessHeap(), 0, object);
610
        return hr;
611 612
    }

613 614
    TRACE("Created stateblock %p.\n", object);
    *stateblock = (IWineD3DStateBlock *)object;
615

616
    return WINED3D_OK;
617 618
}

619 620 621
static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
        WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
        DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
622
        WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
623 624
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625
    IWineD3DSurfaceImpl *object;
626 627
    HRESULT hr;

628
    TRACE("(%p) Create surface\n",This);
629

630
    if (Impl == SURFACE_OPENGL && !This->adapter)
631
    {
632 633
        ERR("OpenGL surfaces are not available without OpenGL.\n");
        return WINED3DERR_NOTAVAILABLE;
634
    }
635

636 637 638
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
639
        ERR("Failed to allocate surface memory.\n");
640 641 642 643
        *ppSurface = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

644
    hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
645
            Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
646 647
    if (FAILED(hr))
    {
648
        WARN("Failed to initialize surface, returning %#x.\n", hr);
649 650 651 652 653
        HeapFree(GetProcessHeap(), 0, object);
        *ppSurface = NULL;
        return hr;
    }

654
    TRACE("(%p) : Created surface %p\n", This, object);
655 656 657

    *ppSurface = (IWineD3DSurface *)object;

658
    return hr;
659 660
}

661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
        IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
{
    struct wined3d_rendertarget_view *object;

    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Failed to allocate memory\n");
        return E_OUTOFMEMORY;
    }

    object->vtbl = &wined3d_rendertarget_view_vtbl;
    object->refcount = 1;
    IWineD3DResource_AddRef(resource);
    object->resource = resource;
    object->parent = parent;

    *rendertarget_view = (IWineD3DRendertargetView *)object;

    return WINED3D_OK;
}

684
static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
685 686
        UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
        IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
687
{
688
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
689
    IWineD3DTextureImpl *object;
690
    HRESULT hr;
691

692
    TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
693 694
    TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
            Format, debug_d3dformat(Format), Pool, ppTexture, parent);
695

696 697 698 699 700 701 702 703
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Out of memory\n");
        *ppTexture = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

704
    hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
705 706
    if (FAILED(hr))
    {
707
        WARN("Failed to initialize texture, returning %#x\n", hr);
708 709 710 711 712 713 714
        HeapFree(GetProcessHeap(), 0, object);
        *ppTexture = NULL;
        return hr;
    }

    *ppTexture = (IWineD3DTexture *)object;

715
    TRACE("(%p) : Created texture %p\n", This, object);
716

717
    return WINED3D_OK;
718 719
}

720
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
721 722
        UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
        IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
723
{
724 725
    IWineD3DDeviceImpl        *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DVolumeTextureImpl *object;
726
    HRESULT hr;
727

728 729
    TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
          Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
730

731 732 733 734 735 736 737 738
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Out of memory\n");
        *ppVolumeTexture = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

739
    hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
740 741
    if (FAILED(hr))
    {
742
        WARN("Failed to initialize volumetexture, returning %#x\n", hr);
743 744 745 746 747
        HeapFree(GetProcessHeap(), 0, object);
        *ppVolumeTexture = NULL;
        return hr;
    }

748 749
    TRACE("(%p) : Created volume texture %p.\n", This, object);
    *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
750

751
    return WINED3D_OK;
752 753
}

754 755 756
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
        UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
        IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
757
{
758 759
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DVolumeImpl *object;
760
    HRESULT hr;
761

762 763
    TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
          Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
764

765 766 767 768 769 770 771 772
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Out of memory\n");
        *ppVolume = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

773
    hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
774 775
    if (FAILED(hr))
    {
776
        WARN("Failed to initialize volume, returning %#x.\n", hr);
777 778 779 780
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
    }

781
    TRACE("(%p) : Created volume %p.\n", This, object);
782
    *ppVolume = (IWineD3DVolume *)object;
783

784
    return WINED3D_OK;
785 786
}

787 788 789
static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
        DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
        IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
790
{
791 792 793
    IWineD3DDeviceImpl      *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
    HRESULT                  hr;
794

795 796 797 798 799 800 801 802
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Out of memory\n");
        *ppCubeTexture = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

803
    hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
804 805
    if (FAILED(hr))
    {
806
        WARN("Failed to initialize cubetexture, returning %#x\n", hr);
807 808 809 810 811
        HeapFree(GetProcessHeap(), 0, object);
        *ppCubeTexture = NULL;
        return hr;
    }

812
    TRACE("(%p) : Created Cube Texture %p\n", This, object);
813 814
    *ppCubeTexture = (IWineD3DCubeTexture *)object;

815
    return WINED3D_OK;
816 817
}

818
static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
819
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
820
    IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
821
    HRESULT hr = WINED3DERR_NOTAVAILABLE;
822
    const IWineD3DQueryVtbl *vtable;
823

824 825 826 827 828 829 830 831
    /* Just a check to see if we support this type of query */
    switch(Type) {
    case WINED3DQUERYTYPE_OCCLUSION:
        TRACE("(%p) occlusion query\n", This);
        if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
            hr = WINED3D_OK;
        else
            WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
832 833

        vtable = &IWineD3DOcclusionQuery_Vtbl;
834
        break;
835 836

    case WINED3DQUERYTYPE_EVENT:
837
        if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
838 839 840 841 842
            /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
             * Pretend to support it, faking this query does not do much harm except potentially lowering performance
             */
            FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
        }
843
        vtable = &IWineD3DEventQuery_Vtbl;
844 845 846
        hr = WINED3D_OK;
        break;

847 848 849 850 851 852 853 854 855 856 857 858 859
    case WINED3DQUERYTYPE_VCACHE:
    case WINED3DQUERYTYPE_RESOURCEMANAGER:
    case WINED3DQUERYTYPE_VERTEXSTATS:
    case WINED3DQUERYTYPE_TIMESTAMP:
    case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
    case WINED3DQUERYTYPE_TIMESTAMPFREQ:
    case WINED3DQUERYTYPE_PIPELINETIMINGS:
    case WINED3DQUERYTYPE_INTERFACETIMINGS:
    case WINED3DQUERYTYPE_VERTEXTIMINGS:
    case WINED3DQUERYTYPE_PIXELTIMINGS:
    case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
    case WINED3DQUERYTYPE_CACHEUTILIZATION:
    default:
860 861
        /* Use the base Query vtable until we have a special one for each query */
        vtable = &IWineD3DQuery_Vtbl;
862 863 864
        FIXME("(%p) Unhandled query type %d\n", This, Type);
    }
    if(NULL == ppQuery || hr != WINED3D_OK) {
865 866 867
        return hr;
    }

868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if(!object)
    {
        ERR("Out of memory\n");
        *ppQuery = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

    object->lpVtbl = vtable;
    object->type = Type;
    object->state = QUERY_CREATED;
    object->wineD3DDevice = This;
    object->parent = parent;
    object->ref = 1;

    *ppQuery = (IWineD3DQuery *)object;

885 886
    /* allocated the 'extended' data based on the type of query requested */
    switch(Type){
887
    case WINED3DQUERYTYPE_OCCLUSION:
888 889 890
        object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
        ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
        break;
891

892
    case WINED3DQUERYTYPE_EVENT:
893 894
        object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
        ((struct wined3d_event_query *)object->extendedData)->context = NULL;
895 896
        break;

897 898 899 900 901 902 903 904 905 906 907 908
    case WINED3DQUERYTYPE_VCACHE:
    case WINED3DQUERYTYPE_RESOURCEMANAGER:
    case WINED3DQUERYTYPE_VERTEXSTATS:
    case WINED3DQUERYTYPE_TIMESTAMP:
    case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
    case WINED3DQUERYTYPE_TIMESTAMPFREQ:
    case WINED3DQUERYTYPE_PIPELINETIMINGS:
    case WINED3DQUERYTYPE_INTERFACETIMINGS:
    case WINED3DQUERYTYPE_VERTEXTIMINGS:
    case WINED3DQUERYTYPE_PIXELTIMINGS:
    case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
    case WINED3DQUERYTYPE_CACHEUTILIZATION:
909 910 911 912
    default:
        object->extendedData = 0;
        FIXME("(%p) Unhandled query type %d\n",This , Type);
    }
913
    TRACE("(%p) : Created Query %p\n", This, object);
914
    return WINED3D_OK;
915 916
}

917 918 919 920 921 922 923 924 925 926 927
/*****************************************************************************
 * IWineD3DDeviceImpl_SetupFullscreenWindow
 *
 * Helper function that modifies a HWND's Style and ExStyle for proper
 * fullscreen use.
 *
 * Params:
 *  iface: Pointer to the IWineD3DDevice interface
 *  window: Window to setup
 *
 *****************************************************************************/
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
static LONG fullscreen_style(LONG orig_style) {
    LONG style = orig_style;
    style &= ~WS_CAPTION;
    style &= ~WS_THICKFRAME;

    /* Make sure the window is managed, otherwise we won't get keyboard input */
    style |= WS_POPUP | WS_SYSMENU;

    return style;
}

static LONG fullscreen_exStyle(LONG orig_exStyle) {
    LONG exStyle = orig_exStyle;

    /* Filter out window decorations */
    exStyle &= ~WS_EX_WINDOWEDGE;
    exStyle &= ~WS_EX_CLIENTEDGE;

    return exStyle;
}

949
static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
950 951 952 953 954 955 956
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    LONG style, exStyle;
    /* Don't do anything if an original style is stored.
     * That shouldn't happen
     */
    TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
957
    if (This->style || This->exStyle) {
958 959 960 961 962 963 964 965 966 967
        ERR("(%p): Want to change the window parameters of HWND %p, but "
            "another style is stored for restoration afterwards\n", This, window);
    }

    /* Get the parameters and save them */
    style = GetWindowLongW(window, GWL_STYLE);
    exStyle = GetWindowLongW(window, GWL_EXSTYLE);
    This->style = style;
    This->exStyle = exStyle;

968 969
    style = fullscreen_style(style);
    exStyle = fullscreen_exStyle(exStyle);
970 971 972 973 974 975 976 977 978

    TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
          This->style, This->exStyle, style, exStyle);

    SetWindowLongW(window, GWL_STYLE, style);
    SetWindowLongW(window, GWL_EXSTYLE, exStyle);

    /* Inform the window about the update. */
    SetWindowPos(window, HWND_TOP, 0, 0,
979
                 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
980 981 982 983 984 985 986 987 988 989 990 991 992
}

/*****************************************************************************
 * IWineD3DDeviceImpl_RestoreWindow
 *
 * Helper function that restores a windows' properties when taking it out
 * of fullscreen mode
 *
 * Params:
 *  iface: Pointer to the IWineD3DDevice interface
 *  window: Window to setup
 *
 *****************************************************************************/
993
static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
994
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
995
    LONG style, exStyle;
996 997 998 999 1000 1001 1002 1003 1004

    /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
     * switch, do nothing
     */
    if (!This->style && !This->exStyle) return;

    TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
          This, window, This->style, This->exStyle);

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    style = GetWindowLongW(window, GWL_STYLE);
    exStyle = GetWindowLongW(window, GWL_EXSTYLE);

    /* Only restore the style if the application didn't modify it during the fullscreen phase.
     * Some applications change it before calling Reset() when switching between windowed and
     * fullscreen modes(HL2), some depend on the original style(Eve Online)
     */
    if(style == fullscreen_style(This->style) &&
       exStyle == fullscreen_style(This->exStyle)) {
        SetWindowLongW(window, GWL_STYLE, This->style);
        SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
    }
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

    /* Delete the old values */
    This->style = 0;
    This->exStyle = 0;

    /* Inform the window about the update */
    SetWindowPos(window, 0 /* InsertAfter, ignored */,
                 0, 0, 0, 0, /* Pos, Size, ignored */
                 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
}

1028
/* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1029 1030 1031
static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
        WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
        IUnknown *parent, WINED3DSURFTYPE surface_type)
1032
{
1033
    IWineD3DDeviceImpl      *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
1034 1035 1036

    HDC                     hDc;
    IWineD3DSwapChainImpl  *object; /** NOTE: impl ref allowed since this is a create function **/
1037
    HRESULT                 hr;
1038
    BOOL                    displaymode_set = FALSE;
1039
    WINED3DDISPLAYMODE      Mode;
1040
    const struct GlPixelFormatDesc *format_desc;
Oliver Stieber's avatar
Oliver Stieber committed
1041

1042
    TRACE("(%p) : Created Additional Swap Chain\n", This);
Oliver Stieber's avatar
Oliver Stieber committed
1043 1044 1045

   /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
   * does a device hold a reference to a swap chain giving them a lifetime of the device
1046
   * or does the swap chain notify the device of its destruction.
Oliver Stieber's avatar
Oliver Stieber committed
1047 1048
    *******************************/

1049
    /* Check the params */
1050 1051
    if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
        ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1052
        return WINED3DERR_INVALIDCALL;
1053
    } else if (pPresentationParameters->BackBufferCount > 1) {
1054
        FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1055 1056
    }

1057 1058 1059 1060 1061 1062 1063 1064
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if(!object)
    {
        ERR("Out of memory\n");
        *ppSwapChain = NULL;
        return WINED3DERR_OUTOFVIDEOMEMORY;
    }

1065 1066 1067 1068 1069 1070 1071 1072 1073
    switch(surface_type) {
        case SURFACE_GDI:
            object->lpVtbl = &IWineGDISwapChain_Vtbl;
            break;
        case SURFACE_OPENGL:
            object->lpVtbl = &IWineD3DSwapChain_Vtbl;
            break;
        case SURFACE_UNKNOWN:
            FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1074
            HeapFree(GetProcessHeap(), 0, object);
1075 1076
            return WINED3DERR_INVALIDCALL;
    }
1077 1078 1079 1080 1081
    object->wineD3DDevice = This;
    object->parent = parent;
    object->ref = 1;

    *ppSwapChain = (IWineD3DSwapChain *)object;
Oliver Stieber's avatar
Oliver Stieber committed
1082 1083 1084 1085 1086 1087

    /*********************
    * Lookup the window Handle and the relating X window handle
    ********************/

    /* Setup hwnd we are using, plus which display this equates to */
1088
    object->win_handle = pPresentationParameters->hDeviceWindow;
Oliver Stieber's avatar
Oliver Stieber committed
1089 1090 1091
    if (!object->win_handle) {
        object->win_handle = This->createParms.hFocusWindow;
    }
1092 1093 1094 1095
    if(!pPresentationParameters->Windowed && object->win_handle) {
        IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
                                                 pPresentationParameters->BackBufferWidth,
                                                 pPresentationParameters->BackBufferHeight);
1096
    }
Oliver Stieber's avatar
Oliver Stieber committed
1097 1098

    hDc                = GetDC(object->win_handle);
1099
    TRACE("Using hDc %p\n", hDc);
Oliver Stieber's avatar
Oliver Stieber committed
1100

1101 1102
    if (NULL == hDc) {
        WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1103
        return WINED3DERR_NOTAVAILABLE;
Oliver Stieber's avatar
Oliver Stieber committed
1104
    }
1105

1106 1107 1108 1109 1110
    /* Get info on the current display setup */
    IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
    object->orig_width = Mode.Width;
    object->orig_height = Mode.Height;
    object->orig_fmt = Mode.Format;
1111
    format_desc = getFormatDescEntry(Mode.Format, &This->adapter->gl_info);
1112

1113 1114
    if (pPresentationParameters->Windowed &&
        ((pPresentationParameters->BackBufferWidth == 0) ||
1115 1116
         (pPresentationParameters->BackBufferHeight == 0) ||
         (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
Oliver Stieber's avatar
Oliver Stieber committed
1117

1118 1119
        RECT Rect;
        GetClientRect(object->win_handle, &Rect);
Oliver Stieber's avatar
Oliver Stieber committed
1120

1121 1122 1123
        if (pPresentationParameters->BackBufferWidth == 0) {
           pPresentationParameters->BackBufferWidth = Rect.right;
           TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1124
        }
1125 1126 1127
        if (pPresentationParameters->BackBufferHeight == 0) {
           pPresentationParameters->BackBufferHeight = Rect.bottom;
           TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
Oliver Stieber's avatar
Oliver Stieber committed
1128
        }
1129 1130 1131 1132
        if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
           pPresentationParameters->BackBufferFormat = object->orig_fmt;
           TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
        }
Oliver Stieber's avatar
Oliver Stieber committed
1133 1134
    }

1135 1136
    /* Put the correct figures in the presentation parameters */
    TRACE("Copying across presentation parameters\n");
1137
    object->presentParms = *pPresentationParameters;
Oliver Stieber's avatar
Oliver Stieber committed
1138

1139
    TRACE("calling rendertarget CB\n");
1140 1141 1142 1143
    hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
            object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
            object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
            object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1144
    if (SUCCEEDED(hr)) {
1145
        IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1146
        ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1147 1148 1149
        if(surface_type == SURFACE_OPENGL) {
            IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
        }
1150 1151 1152
    } else {
        ERR("Failed to create the front buffer\n");
        goto error;
Oliver Stieber's avatar
Oliver Stieber committed
1153 1154 1155 1156 1157 1158 1159
    }

   /*********************
   * Windowed / Fullscreen
   *******************/

   /**
1160
   * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1161
   * so we should really check to see if there is a fullscreen swapchain already
1162
   * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
Oliver Stieber's avatar
Oliver Stieber committed
1163 1164
    **************************************/

1165
   if (!pPresentationParameters->Windowed) {
1166
        WINED3DDISPLAYMODE mode;
Oliver Stieber's avatar
Oliver Stieber committed
1167 1168 1169


        /* Change the display settings */
1170 1171 1172 1173
        mode.Width = pPresentationParameters->BackBufferWidth;
        mode.Height = pPresentationParameters->BackBufferHeight;
        mode.Format = pPresentationParameters->BackBufferFormat;
        mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1174

1175 1176
        IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
        displaymode_set = TRUE;
Oliver Stieber's avatar
Oliver Stieber committed
1177 1178
    }

1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
        /**
     * Create an opengl context for the display visual
     *  NOTE: the visual is chosen as the window is created and the glcontext cannot
     *     use different properties after that point in time. FIXME: How to handle when requested format
     *     doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
     *     it chooses is identical to the one already being used!
         **********************************/
    /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/

    object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1189 1190 1191 1192 1193
    if(!object->context) {
        ERR("Failed to create the context array\n");
        hr = E_OUTOFMEMORY;
        goto error;
    }
1194 1195
    object->num_contexts = 1;

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
    if(surface_type == SURFACE_OPENGL) {
        object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
        if (!object->context[0]) {
            ERR("Failed to create a new context\n");
            hr = WINED3DERR_NOTAVAILABLE;
            goto error;
        } else {
            TRACE("Context created (HWND=%p, glContext=%p)\n",
                object->win_handle, object->context[0]->glCtx);
        }
1206 1207
    }

Oliver Stieber's avatar
Oliver Stieber committed
1208 1209 1210
   /*********************
   * Create the back, front and stencil buffers
   *******************/
1211
    if(object->presentParms.BackBufferCount > 0) {
1212
        UINT i;
1213 1214 1215 1216

        object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
        if(!object->backBuffer) {
            ERR("Out of memory\n");
1217 1218
            hr = E_OUTOFMEMORY;
            goto error;
1219 1220 1221 1222
        }

        for(i = 0; i < object->presentParms.BackBufferCount; i++) {
            TRACE("calling rendertarget CB\n");
1223 1224 1225 1226
            hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
                    object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
                    object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
                    object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1227
            if(SUCCEEDED(hr)) {
1228
                IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1229
                ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1230
            } else {
1231 1232
                ERR("Cannot create new back buffer\n");
                goto error;
1233
            }
1234 1235 1236 1237 1238 1239
            if(surface_type == SURFACE_OPENGL) {
                ENTER_GL();
                glDrawBuffer(GL_BACK);
                checkGLcall("glDrawBuffer(GL_BACK)");
                LEAVE_GL();
            }
1240
        }
1241 1242 1243 1244
    } else {
        object->backBuffer = NULL;

        /* Single buffering - draw to front buffer */
1245 1246 1247 1248 1249 1250
        if(surface_type == SURFACE_OPENGL) {
            ENTER_GL();
            glDrawBuffer(GL_FRONT);
            checkGLcall("glDrawBuffer(GL_FRONT)");
            LEAVE_GL();
        }
1251
    }
Oliver Stieber's avatar
Oliver Stieber committed
1252 1253

    /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1254
    if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
Oliver Stieber's avatar
Oliver Stieber committed
1255
        TRACE("Creating depth stencil buffer\n");
1256
        if (This->auto_depth_stencil_buffer == NULL ) {
1257 1258 1259 1260 1261
            hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
                    object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
                    object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
                    object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
                    &This->auto_depth_stencil_buffer);
1262
            if (SUCCEEDED(hr)) {
1263
                IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1264 1265 1266 1267
            } else {
                ERR("Failed to create the auto depth stencil\n");
                goto error;
            }
Oliver Stieber's avatar
Oliver Stieber committed
1268 1269 1270
        }
    }

1271 1272
    IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);

1273
    TRACE("Created swapchain %p\n", object);
1274
    TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1275
    return WINED3D_OK;
Oliver Stieber's avatar
Oliver Stieber committed
1276

1277
error:
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
    if (displaymode_set) {
        DEVMODEW devmode;
        RECT     clip_rc;

        SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
        ClipCursor(NULL);

        /* Change the display settings */
        memset(&devmode, 0, sizeof(devmode));
        devmode.dmSize       = sizeof(devmode);
        devmode.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1289
        devmode.dmBitsPerPel = format_desc->byte_count * 8;
1290 1291 1292 1293 1294
        devmode.dmPelsWidth  = object->orig_width;
        devmode.dmPelsHeight = object->orig_height;
        ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
    }

1295
    if (object->backBuffer) {
1296
        UINT i;
1297
        for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1298
            if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
Oliver Stieber's avatar
Oliver Stieber committed
1299
        }
1300 1301 1302
        HeapFree(GetProcessHeap(), 0, object->backBuffer);
        object->backBuffer = NULL;
    }
1303
    if(object->context && object->context[0])
1304
        DestroyContext(This, object->context[0]);
1305
    if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1306
    HeapFree(GetProcessHeap(), 0, object);
Oliver Stieber's avatar
Oliver Stieber committed
1307
    return hr;
1308 1309
}

1310
/** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1311
static UINT     WINAPI  IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1312
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313
    TRACE("(%p)\n", This);
Oliver Stieber's avatar
Oliver Stieber committed
1314

1315
    return This->NumberOfSwapChains;
1316 1317
}

1318
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1319
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320
    TRACE("(%p) : swapchain %d\n", This, iSwapChain);
Oliver Stieber's avatar
Oliver Stieber committed
1321

1322 1323
    if(iSwapChain < This->NumberOfSwapChains) {
        *pSwapChain = This->swapchains[iSwapChain];
1324
        IWineD3DSwapChain_AddRef(*pSwapChain);
1325 1326 1327 1328 1329 1330
        TRACE("(%p) returning %p\n", This, *pSwapChain);
        return WINED3D_OK;
    } else {
        TRACE("Swapchain out of range\n");
        *pSwapChain = NULL;
        return WINED3DERR_INVALIDCALL;
1331
    }
1332 1333
}

1334
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1335
        IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1336 1337 1338
        const WINED3DVERTEXELEMENT *elements, UINT element_count)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339
    IWineD3DVertexDeclarationImpl *object = NULL;
1340
    HRESULT hr;
1341

1342 1343
    TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
            iface, declaration, parent, elements, element_count);
1344

1345 1346 1347
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if(!object)
    {
1348 1349
        ERR("Failed to allocate vertex declaration memory.\n");
        return E_OUTOFMEMORY;
1350 1351
    }

1352
    hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1353 1354 1355 1356 1357
    if (FAILED(hr))
    {
        WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
1358
    }
1359

Henri Verbeet's avatar
Henri Verbeet committed
1360
    TRACE("Created vertex declaration %p.\n", object);
1361 1362 1363
    *declaration = (IWineD3DVertexDeclaration *)object;

    return WINED3D_OK;
1364 1365
}

1366 1367
static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
                                            DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382

    unsigned int idx, idx2;
    unsigned int offset;
    BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
    BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
    BOOL has_blend_idx = has_blend &&
       (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
        (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
        (fvf & WINED3DFVF_LASTBETA_UBYTE4));
    BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
    BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
    BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
    BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;

    DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1383
    DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1384 1385 1386 1387 1388 1389 1390 1391
    WINED3DVERTEXELEMENT *elements = NULL;

    unsigned int size;
    DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
    if (has_blend_idx) num_blends--;

    /* Compute declaration size */
    size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1392
           has_psize + has_diffuse + has_specular + num_textures;
1393 1394 1395

    /* convert the declaration */
    elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1396
    if (!elements) return ~0U;
1397 1398 1399 1400

    idx = 0;
    if (has_pos) {
        if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1401 1402
            elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
            elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1403
        }
1404
        else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1405 1406
            elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
            elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1407
        }
1408
        else {
1409 1410
            elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
            elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1411
        }
1412
        elements[idx].usage_idx = 0;
1413 1414 1415 1416
        idx++;
    }
    if (has_blend && (num_blends > 0)) {
        if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1417
            elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1418 1419
        else {
            switch(num_blends) {
1420 1421 1422 1423
                case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
                case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
                case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
                case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1424 1425 1426 1427
                default:
                    ERR("Unexpected amount of blend values: %u\n", num_blends);
            }
        }
1428 1429
        elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
        elements[idx].usage_idx = 0;
1430 1431 1432 1433 1434
        idx++;
    }
    if (has_blend_idx) {
        if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
            (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1435
            elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1436
        else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1437
            elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1438
        else
1439 1440 1441
            elements[idx].format = WINED3DFMT_R32_FLOAT;
        elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
        elements[idx].usage_idx = 0;
1442 1443 1444
        idx++;
    }
    if (has_normal) {
1445 1446 1447
        elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
        elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
        elements[idx].usage_idx = 0;
1448 1449 1450
        idx++;
    }
    if (has_psize) {
1451 1452 1453
        elements[idx].format = WINED3DFMT_R32_FLOAT;
        elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
        elements[idx].usage_idx = 0;
1454 1455 1456
        idx++;
    }
    if (has_diffuse) {
1457
        elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1458 1459
        elements[idx].usage = WINED3DDECLUSAGE_COLOR;
        elements[idx].usage_idx = 0;
1460 1461 1462
        idx++;
    }
    if (has_specular) {
1463
        elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1464 1465
        elements[idx].usage = WINED3DDECLUSAGE_COLOR;
        elements[idx].usage_idx = 1;
1466 1467 1468 1469 1470 1471
        idx++;
    }
    for (idx2 = 0; idx2 < num_textures; idx2++) {
        unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
        switch (numcoords) {
            case WINED3DFVF_TEXTUREFORMAT1:
1472
                elements[idx].format = WINED3DFMT_R32_FLOAT;
1473 1474
                break;
            case WINED3DFVF_TEXTUREFORMAT2:
1475
                elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1476 1477
                break;
            case WINED3DFVF_TEXTUREFORMAT3:
1478
                elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1479 1480
                break;
            case WINED3DFVF_TEXTUREFORMAT4:
1481
                elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1482 1483
                break;
        }
1484 1485
        elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
        elements[idx].usage_idx = idx2;
1486 1487 1488 1489
        idx++;
    }

    /* Now compute offsets, and initialize the rest of the fields */
1490 1491
    for (idx = 0, offset = 0; idx < size; ++idx)
    {
1492 1493 1494 1495 1496
        const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
        elements[idx].input_slot = 0;
        elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
        elements[idx].offset = offset;
        offset += format_desc->component_count * format_desc->component_size;
1497 1498 1499 1500 1501 1502
    }

    *ppVertexElements = elements;
    return size;
}

1503
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1504 1505
        IWineD3DVertexDeclaration **declaration, IUnknown *parent,
        const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1506
{
1507
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1508
    WINED3DVERTEXELEMENT *elements;
1509
    unsigned int size;
1510 1511
    DWORD hr;

1512
    TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1513

1514 1515
    size = ConvertFvfToDeclaration(This, fvf, &elements);
    if (size == ~0U) return E_OUTOFMEMORY;
1516

1517
    hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1518 1519
    HeapFree(GetProcessHeap(), 0, elements);
    return hr;
1520 1521
}

1522
static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1523
        const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1524 1525
        IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
        const struct wined3d_parent_ops *parent_ops)
1526
{
1527 1528 1529
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DVertexShaderImpl *object;
    HRESULT hr;
1530

1531 1532 1533
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
1534 1535
        ERR("Failed to allocate shader memory.\n");
        return E_OUTOFMEMORY;
1536 1537
    }

1538
    hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1539 1540
    if (FAILED(hr))
    {
1541 1542
        WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
        HeapFree(GetProcessHeap(), 0, object);
1543
        return hr;
1544 1545
    }

1546 1547 1548 1549
    TRACE("Created vertex shader %p.\n", object);
    *ppVertexShader = (IWineD3DVertexShader *)object;

    return WINED3D_OK;
1550 1551
}

1552 1553
static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
        const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1554 1555
        IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
        const struct wined3d_parent_ops *parent_ops)
1556
{
1557
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1558 1559
    IWineD3DPixelShaderImpl *object;
    HRESULT hr;
1560

1561 1562 1563
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
1564 1565
        ERR("Failed to allocate shader memory.\n");
        return E_OUTOFMEMORY;
1566 1567
    }

1568
    hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1569 1570
    if (FAILED(hr))
    {
1571 1572
        WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
        HeapFree(GetProcessHeap(), 0, object);
1573
        return hr;
1574
    }
1575

1576 1577 1578 1579
    TRACE("Created pixel shader %p.\n", object);
    *ppPixelShader = (IWineD3DPixelShader *)object;

    return WINED3D_OK;
1580 1581
}

1582 1583 1584
static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
        const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
{
1585 1586
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DPaletteImpl *object;
1587
    HRESULT hr;
1588
    TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1589 1590 1591 1592 1593

    /* Create the new object */
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
    if(!object) {
        ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1594
        return E_OUTOFMEMORY;
1595 1596 1597 1598
    }

    object->lpVtbl = &IWineD3DPalette_Vtbl;
    object->ref = 1;
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
    object->Flags = Flags;
    object->parent = Parent;
    object->wineD3DDevice = This;
    object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
    object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));

    if(!object->hpal) {
        HeapFree( GetProcessHeap(), 0, object);
        return E_OUTOFMEMORY;
    }

    hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
    if(FAILED(hr)) {
        IWineD3DPalette_Release((IWineD3DPalette *) object);
        return hr;
    }
1615 1616 1617

    *Palette = (IWineD3DPalette *) object;

1618
    return WINED3D_OK;
1619 1620
}

1621 1622 1623 1624 1625 1626 1627
static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
    HBITMAP hbm;
    BITMAP bm;
    HRESULT hr;
    HDC dcb = NULL, dcs = NULL;
    WINEDDCOLORKEY colorkey;

1628
    hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645
    if(hbm)
    {
        GetObjectA(hbm, sizeof(BITMAP), &bm);
        dcb = CreateCompatibleDC(NULL);
        if(!dcb) goto out;
        SelectObject(dcb, hbm);
    }
    else
    {
        /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
         * couldn't be loaded
         */
        memset(&bm, 0, sizeof(bm));
        bm.bmWidth = 32;
        bm.bmHeight = 32;
    }

1646
    hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1647 1648
            FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
            NULL, &wined3d_null_parent_ops);
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677
    if(FAILED(hr)) {
        ERR("Wine logo requested, but failed to create surface\n");
        goto out;
    }

    if(dcb) {
        hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
        if(FAILED(hr)) goto out;
        BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
        IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);

        colorkey.dwColorSpaceLowValue = 0;
        colorkey.dwColorSpaceHighValue = 0;
        IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
    } else {
        /* Fill the surface with a white color to show that wined3d is there */
        IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
    }

    out:
    if(dcb) {
        DeleteDC(dcb);
    }
    if(hbm) {
        DeleteObject(hbm);
    }
    return;
}

1678
/* Context activation is done by the caller. */
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692
static void create_dummy_textures(IWineD3DDeviceImpl *This) {
    unsigned int i;
    /* Under DirectX you can have texture stage operations even if no texture is
    bound, whereas opengl will only do texture operations when a valid texture is
    bound. We emulate this by creating dummy textures and binding them to each
    texture stage, but disable all stages by default. Hence if a stage is enabled
    then the default texture will kick in until replaced by a SetTexture call     */
    ENTER_GL();

    if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
        /* The dummy texture does not have client storage backing */
        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
        checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
    }
1693 1694 1695

    for (i = 0; i < This->adapter->gl_info.max_textures; ++i)
    {
1696 1697 1698
        GLubyte white = 255;

        /* Make appropriate texture active */
1699 1700
        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
        checkGLcall("glActiveTextureARB");
1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723

        /* Generate an opengl texture name */
        glGenTextures(1, &This->dummyTextureName[i]);
        checkGLcall("glGenTextures");
        TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);

        /* Generate a dummy 2d texture (not using 1d because they cause many
        * DRI drivers fall back to sw) */
        glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
        checkGLcall("glBindTexture");

        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
        checkGLcall("glTexImage2D");
    }
    if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
        /* Reenable because if supported it is enabled by default */
        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
        checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
    }

    LEAVE_GL();
}

1724 1725 1726
static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
        WINED3DPRESENT_PARAMETERS *pPresentationParameters)
{
1727
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1728
    const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1729
    IWineD3DSwapChainImpl *swapchain = NULL;
1730
    HRESULT hr;
1731
    DWORD state;
1732
    unsigned int i;
1733

1734 1735
    TRACE("(%p)->(%p)\n", This, pPresentationParameters);

1736
    if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1737
    if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1738 1739 1740

    /* TODO: Test if OpenGL is compiled in and loaded */

1741 1742 1743 1744 1745 1746 1747 1748
    TRACE("(%p) : Creating stateblock\n", This);
    /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
    hr = IWineD3DDevice_CreateStateBlock(iface,
                                         WINED3DSBT_INIT,
                                         (IWineD3DStateBlock **)&This->stateBlock,
                                         NULL);
    if (WINED3D_OK != hr) {   /* Note: No parent needed for initial internal stateblock */
        WARN("Failed to create stateblock\n");
1749
        goto err_out;
1750 1751 1752 1753 1754
    }
    TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
    This->updateStateBlock = This->stateBlock;
    IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);

1755 1756 1757 1758
    This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
            sizeof(IWineD3DSurface *) * gl_info->max_buffers);
    This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
            sizeof(GLenum) * gl_info->max_buffers);
1759

1760 1761
    This->NumberOfPalettes = 1;
    This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1762
    if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
        ERR("Out of memory!\n");
        goto err_out;
    }
    This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
    if(!This->palettes[0]) {
        ERR("Out of memory!\n");
        goto err_out;
    }
    for (i = 0; i < 256; ++i) {
        This->palettes[0][i].peRed   = 0xFF;
        This->palettes[0][i].peGreen = 0xFF;
        This->palettes[0][i].peBlue  = 0xFF;
        This->palettes[0][i].peFlags = 0xFF;
    }
    This->currentPalette = 0;

1779
    /* Initialize the texture unit mapping to a 1:1 mapping */
1780 1781 1782 1783
    for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
    {
        if (state < gl_info->max_fragment_samplers)
        {
1784 1785 1786
            This->texUnitMap[state] = state;
            This->rev_tex_unit_map[state] = state;
        } else {
1787 1788
            This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
            This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1789
        }
1790 1791
    }

1792
    /* Setup the implicit swapchain. This also initializes a context. */
1793
    TRACE("Creating implicit swapchain\n");
1794 1795 1796 1797
    hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
            pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
    if (FAILED(hr))
    {
1798
        WARN("Failed to create implicit swapchain\n");
1799
        goto err_out;
1800 1801
    }

1802 1803 1804 1805
    This->NumberOfSwapChains = 1;
    This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
    if(!This->swapchains) {
        ERR("Out of memory!\n");
1806
        goto err_out;
1807 1808 1809
    }
    This->swapchains[0] = (IWineD3DSwapChain *) swapchain;

1810
    if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1811
        TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1812
        This->render_targets[0] = swapchain->backBuffer[0];
1813 1814 1815
    }
    else {
        TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1816
        This->render_targets[0] = swapchain->frontBuffer;
1817
    }
1818
    IWineD3DSurface_AddRef(This->render_targets[0]);
1819

1820
    /* Depth Stencil support */
1821
    This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1822 1823 1824 1825
    if (NULL != This->stencilBufferTarget) {
        IWineD3DSurface_AddRef(This->stencilBufferTarget);
    }

1826 1827 1828 1829 1830
    hr = This->shader_backend->shader_alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Shader private data couldn't be allocated\n");
        goto err_out;
    }
1831 1832 1833 1834 1835
    hr = This->frag_pipe->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Fragment pipeline private data couldn't be allocated\n");
        goto err_out;
    }
1836 1837 1838 1839 1840
    hr = This->blitter->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Blitter private data couldn't be allocated\n");
        goto err_out;
    }
1841

1842 1843 1844 1845
    /* Set up some starting GL setup */

    /* Setup all the devices defaults */
    IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1846
    create_dummy_textures(This);
1847 1848 1849

    ENTER_GL();

1850 1851
    /* Initialize the current view state */
    This->view_ident = 1;
1852
    This->contexts[0]->last_was_rhw = 0;
1853
    glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1854
    checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1855 1856 1857 1858 1859 1860 1861 1862 1863

    switch(wined3d_settings.offscreen_rendering_mode) {
        case ORM_FBO:
        case ORM_PBUFFER:
            This->offscreenBuffer = GL_BACK;
            break;

        case ORM_BACKBUFFER:
        {
1864 1865
            if (context_get_current()->aux_buffers > 0)
            {
1866 1867 1868 1869 1870 1871 1872 1873 1874
                TRACE("Using auxilliary buffer for offscreen rendering\n");
                This->offscreenBuffer = GL_AUX0;
            } else {
                TRACE("Using back buffer for offscreen rendering\n");
                This->offscreenBuffer = GL_BACK;
            }
        }
    }

1875
    TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1876
    LEAVE_GL();
1877 1878

    /* Clear the screen */
1879 1880
    IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
                          WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1881
                          0x00, 1.0f, 0);
1882 1883

    This->d3d_initialized = TRUE;
1884 1885 1886 1887

    if(wined3d_settings.logo) {
        IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
    }
1888 1889
    This->highest_dirty_ps_const = 0;
    This->highest_dirty_vs_const = 0;
1890
    return WINED3D_OK;
1891

1892
err_out:
1893 1894 1895 1896
    HeapFree(GetProcessHeap(), 0, This->render_targets);
    HeapFree(GetProcessHeap(), 0, This->draw_buffers);
    HeapFree(GetProcessHeap(), 0, This->swapchains);
    This->NumberOfSwapChains = 0;
1897 1898 1899 1900 1901
    if(This->palettes) {
        HeapFree(GetProcessHeap(), 0, This->palettes[0]);
        HeapFree(GetProcessHeap(), 0, This->palettes);
    }
    This->NumberOfPalettes = 0;
1902 1903 1904 1905 1906 1907 1908
    if(swapchain) {
        IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
    }
    if(This->stateBlock) {
        IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
        This->stateBlock = NULL;
    }
1909 1910 1911 1912 1913 1914 1915 1916 1917
    if (This->blit_priv) {
        This->blitter->free_private(iface);
    }
    if (This->fragment_priv) {
        This->frag_pipe->free_private(iface);
    }
    if (This->shader_priv) {
        This->shader_backend->shader_free_private(iface);
    }
1918
    return hr;
1919 1920
}

1921 1922 1923
static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
        WINED3DPRESENT_PARAMETERS *pPresentationParameters)
{
1924 1925 1926 1927 1928 1929
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSwapChainImpl *swapchain = NULL;
    HRESULT hr;

    /* Setup the implicit swapchain */
    TRACE("Creating implicit swapchain\n");
1930 1931 1932 1933
    hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
            pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
    if (FAILED(hr))
    {
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951
        WARN("Failed to create implicit swapchain\n");
        goto err_out;
    }

    This->NumberOfSwapChains = 1;
    This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
    if(!This->swapchains) {
        ERR("Out of memory!\n");
        goto err_out;
    }
    This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
    return WINED3D_OK;

err_out:
    IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
    return hr;
}

1952 1953 1954 1955 1956 1957 1958
static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
{
    IWineD3DResource_UnLoad(resource);
    IWineD3DResource_Release(resource);
    return WINED3D_OK;
}

1959 1960 1961
static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
        D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
{
1962
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1963 1964
    const struct wined3d_context *context;
    const struct wined3d_gl_info *gl_info;
1965
    int sampler;
1966
    UINT i;
1967 1968 1969 1970
    TRACE("(%p)\n", This);

    if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;

1971
    /* I don't think that the interface guarantees that the device is destroyed from the same thread
1972 1973
     * it was created. Thus make sure a context is active for the glDelete* calls
     */
1974 1975
    context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
    gl_info = context->gl_info;
1976

1977 1978
    if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);

1979 1980 1981
    /* Unload resources */
    IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);

1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
    TRACE("Deleting high order patches\n");
    for(i = 0; i < PATCHMAP_SIZE; i++) {
        struct list *e1, *e2;
        struct WineD3DRectPatch *patch;
        LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
            patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
            IWineD3DDevice_DeletePatch(iface, patch->Handle);
        }
    }

1992 1993
    /* Delete the palette conversion shader if it is around */
    if(This->paletteConversionShader) {
1994
        ENTER_GL();
1995
        GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1996
        LEAVE_GL();
1997
        This->paletteConversionShader = 0;
1998 1999
    }

2000 2001 2002
    /* Delete the pbuffer context if there is any */
    if(This->pbufferContext) DestroyContext(This, This->pbufferContext);

2003 2004 2005 2006 2007 2008 2009 2010
    /* Delete the mouse cursor texture */
    if(This->cursorTexture) {
        ENTER_GL();
        glDeleteTextures(1, &This->cursorTexture);
        LEAVE_GL();
        This->cursorTexture = 0;
    }

2011
    for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2012
        IWineD3DDevice_SetTexture(iface, sampler, NULL);
2013
    }
2014 2015 2016
    for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
        IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
    }
2017

2018 2019 2020
    /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
     * private data, it might contain opengl pointers
     */
2021
    if(This->depth_blt_texture) {
2022
        ENTER_GL();
2023
        glDeleteTextures(1, &This->depth_blt_texture);
2024
        LEAVE_GL();
2025 2026
        This->depth_blt_texture = 0;
    }
2027
    if (This->depth_blt_rb) {
2028
        ENTER_GL();
2029
        gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2030
        LEAVE_GL();
2031 2032 2033 2034
        This->depth_blt_rb = 0;
        This->depth_blt_rb_w = 0;
        This->depth_blt_rb_h = 0;
    }
2035

2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054
    /* Release the update stateblock */
    if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
        if(This->updateStateBlock != This->stateBlock)
            FIXME("(%p) Something's still holding the Update stateblock\n",This);
    }
    This->updateStateBlock = NULL;

    { /* because were not doing proper internal refcounts releasing the primary state block
        causes recursion with the extra checks in ResourceReleased, to avoid this we have
        to set this->stateBlock = NULL; first */
        IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
        This->stateBlock = NULL;

        /* Release the stateblock */
        if(IWineD3DStateBlock_Release(stateBlock) > 0){
            FIXME("(%p) Something's still holding the Update stateblock\n",This);
        }
    }

2055
    /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2056
    This->blitter->free_private(iface);
2057
    This->frag_pipe->free_private(iface);
2058
    This->shader_backend->shader_free_private(iface);
2059

2060
    /* Release the buffers (with sanity checks)*/
2061 2062
    TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
    if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2063 2064
        if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
            FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2065 2066 2067
    }
    This->stencilBufferTarget = NULL;

2068 2069
    TRACE("Releasing the render target at %p\n", This->render_targets[0]);
    if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2070
          /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2071 2072
    }
    TRACE("Setting rendertarget to NULL\n");
2073
    This->render_targets[0] = NULL;
2074

2075
    if (This->auto_depth_stencil_buffer) {
2076 2077
        if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
        {
2078
            FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2079
        }
2080
        This->auto_depth_stencil_buffer = NULL;
2081 2082
    }

2083 2084
    for(i=0; i < This->NumberOfSwapChains; i++) {
        TRACE("Releasing the implicit swapchain %d\n", i);
2085
        if (D3DCB_DestroySwapChain(This->swapchains[i])  > 0) {
2086 2087 2088
            FIXME("(%p) Something's still holding the implicit swapchain\n", This);
        }
    }
2089 2090

    HeapFree(GetProcessHeap(), 0, This->swapchains);
2091
    This->swapchains = NULL;
2092
    This->NumberOfSwapChains = 0;
2093

2094 2095 2096 2097 2098
    for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
    HeapFree(GetProcessHeap(), 0, This->palettes);
    This->palettes = NULL;
    This->NumberOfPalettes = 0;

2099 2100 2101 2102 2103
    HeapFree(GetProcessHeap(), 0, This->render_targets);
    HeapFree(GetProcessHeap(), 0, This->draw_buffers);
    This->render_targets = NULL;
    This->draw_buffers = NULL;

2104 2105
    This->d3d_initialized = FALSE;
    return WINED3D_OK;
2106 2107
}

2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124
static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    unsigned int i;

    for(i=0; i < This->NumberOfSwapChains; i++) {
        TRACE("Releasing the implicit swapchain %d\n", i);
        if (D3DCB_DestroySwapChain(This->swapchains[i])  > 0) {
            FIXME("(%p) Something's still holding the implicit swapchain\n", This);
        }
    }

    HeapFree(GetProcessHeap(), 0, This->swapchains);
    This->swapchains = NULL;
    This->NumberOfSwapChains = 0;
    return WINED3D_OK;
}

2125 2126
/* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2127 2128
 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
 *
2129
 * There is no way to deactivate thread safety once it is enabled.
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139
 */
static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;

    /*For now just store the flag(needed in case of ddraw) */
    This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;

    return;
}

2140 2141
static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
        const WINED3DDISPLAYMODE* pMode) {
2142 2143 2144
    DEVMODEW devmode;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    LONG ret;
2145
    const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2146
    RECT clip_rc;
2147 2148 2149 2150 2151 2152 2153 2154 2155

    TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));

    /* Resize the screen even without a window:
     * The app could have unset it with SetCooperativeLevel, but not called
     * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
     * but we don't have any hwnd
     */

2156 2157
    memset(&devmode, 0, sizeof(devmode));
    devmode.dmSize = sizeof(devmode);
2158
    devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2159
    devmode.dmBitsPerPel = format_desc->byte_count * 8;
2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172
    devmode.dmPelsWidth  = pMode->Width;
    devmode.dmPelsHeight = pMode->Height;

    devmode.dmDisplayFrequency = pMode->RefreshRate;
    if (pMode->RefreshRate != 0)  {
        devmode.dmFields |= DM_DISPLAYFREQUENCY;
    }

    /* Only change the mode if necessary */
    if( (This->ddraw_width == pMode->Width) &&
        (This->ddraw_height == pMode->Height) &&
        (This->ddraw_format == pMode->Format) &&
        (pMode->RefreshRate == 0) ) {
2173
        return WINED3D_OK;
2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184
    }

    ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
    if (ret != DISP_CHANGE_SUCCESSFUL) {
        if(devmode.dmDisplayFrequency != 0) {
            WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
            devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
            devmode.dmDisplayFrequency = 0;
            ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
        }
        if(ret != DISP_CHANGE_SUCCESSFUL) {
2185
            return WINED3DERR_NOTAVAILABLE;
2186 2187 2188 2189 2190 2191 2192 2193
        }
    }

    /* Store the new values */
    This->ddraw_width = pMode->Width;
    This->ddraw_height = pMode->Height;
    This->ddraw_format = pMode->Format;

2194 2195 2196 2197
    /* And finally clip mouse to our screen */
    SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
    ClipCursor(&clip_rc);

2198
    return WINED3D_OK;
2199 2200
}

2201
static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2202 2203 2204
   IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
   *ppD3D= This->wineD3D;
   TRACE("(%p) : wineD3D returning %p\n", This,  *ppD3D);
2205
   IWineD3D_AddRef(*ppD3D);
2206
   return WINED3D_OK;
2207
}
2208

2209
static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2210
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2211

2212
    TRACE("(%p) : simulating %dMB, returning %dMB left\n",  This,
2213 2214
         (This->adapter->TextureRam/(1024*1024)),
         ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2215
    /* return simulated texture memory left */
2216
    return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2217 2218
}

2219 2220 2221
/*****
 * Get / Set Stream Source
 *****/
2222 2223 2224 2225 2226
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
        IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DBuffer *oldSrc;
2227

2228 2229
    if (StreamNumber >= MAX_STREAMS) {
        WARN("Stream out of range %d\n", StreamNumber);
2230
        return WINED3DERR_INVALIDCALL;
2231 2232 2233
    } else if(OffsetInBytes & 0x3) {
        WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
        return WINED3DERR_INVALIDCALL;
2234 2235
    }

2236
    oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2237
    TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2238

2239
    This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2240 2241 2242

    if(oldSrc == pStreamData &&
       This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2243
       This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2244 2245 2246 2247
       TRACE("Application is setting the old values over, nothing to do\n");
       return WINED3D_OK;
    }

2248
    This->updateStateBlock->streamSource[StreamNumber]         = pStreamData;
2249 2250 2251 2252
    if (pStreamData) {
        This->updateStateBlock->streamStride[StreamNumber]     = Stride;
        This->updateStateBlock->streamOffset[StreamNumber]     = OffsetInBytes;
    }
2253 2254 2255 2256

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2257 2258
        if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
        if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2259
        return WINED3D_OK;
2260 2261
    }

2262
    if (pStreamData != NULL) {
2263 2264
        InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
        IWineD3DBuffer_AddRef(pStreamData);
2265 2266
    }
    if (oldSrc != NULL) {
2267 2268
        InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
        IWineD3DBuffer_Release(oldSrc);
2269
    }
2270

2271 2272
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);

2273
    return WINED3D_OK;
2274 2275
}

2276 2277 2278
static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
        UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
{
2279
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2280

2281 2282 2283 2284
    TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
           This->stateBlock->streamSource[StreamNumber],
           This->stateBlock->streamOffset[StreamNumber],
           This->stateBlock->streamStride[StreamNumber]);
2285

2286 2287
    if (StreamNumber >= MAX_STREAMS) {
        WARN("Stream out of range %d\n", StreamNumber);
2288
        return WINED3DERR_INVALIDCALL;
2289
    }
2290 2291
    *pStream = This->stateBlock->streamSource[StreamNumber];
    *pStride = This->stateBlock->streamStride[StreamNumber];
2292 2293 2294
    if (pOffset) {
        *pOffset = This->stateBlock->streamOffset[StreamNumber];
    }
2295

2296
    if (*pStream != NULL) {
2297
        IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2298
    }
2299
    return WINED3D_OK;
2300 2301
}

2302
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT Divider) {
2303
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2304 2305
    UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
    UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2306

2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320
    /* Verify input at least in d3d9 this is invalid*/
    if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
        WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
        return WINED3DERR_INVALIDCALL;
    }
    if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
        WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
        return WINED3DERR_INVALIDCALL;
    }
    if( Divider == 0 ){
        WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
        return WINED3DERR_INVALIDCALL;
    }

2321
    TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2322
    This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA  | WINED3DSTREAMSOURCE_INDEXEDDATA );
2323

2324
    This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2325 2326
    This->updateStateBlock->streamFreq[StreamNumber]          = Divider & 0x7FFFFF;

2327 2328 2329
    if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
       This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2330 2331
    }

2332
    return WINED3D_OK;
2333
}
2334

2335
static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT* Divider) {
2336
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2337

2338 2339 2340 2341 2342
    TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
    *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];

    TRACE("(%p) : returning %d\n", This, *Divider);

2343
    return WINED3D_OK;
2344 2345
}

2346
/*****
2347
 * Get / Set & Multiply Transform
2348
 *****/
2349
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2350 2351 2352
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    /* Most of this routine, comments included copied from ddraw tree initially: */
2353
    TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2354 2355 2356 2357

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2358
        This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2359
        This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2360
        return WINED3D_OK;
2361 2362 2363 2364 2365 2366 2367 2368 2369 2370
    }

    /*
     * If the new matrix is the same as the current one,
     * we cut off any further processing. this seems to be a reasonable
     * optimization because as was noticed, some apps (warcraft3 for example)
     * tend towards setting the same matrix repeatedly for some reason.
     *
     * From here on we assume that the new matrix is different, wherever it matters.
     */
2371
    if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2372
        TRACE("The app is setting the same matrix over again\n");
2373
        return WINED3D_OK;
2374 2375 2376 2377 2378 2379 2380 2381 2382
    } else {
        conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
    }

    /*
       ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
       where ViewMat = Camera space, WorldMat = world space.

       In OpenGL, camera and world space is combined into GL_MODELVIEW
2383
       matrix.  The Projection matrix stay projection matrix.
2384 2385 2386
     */

    /* Capture the times we can just ignore the change for now */
2387
    if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2388
        This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2389
        /* Handled by the state manager */
2390 2391
    }

2392
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2393
    return WINED3D_OK;
2394 2395

}
2396
static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2397
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2398
    TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2399
    *pMatrix = This->stateBlock->transforms[State];
2400
    return WINED3D_OK;
2401 2402
}

2403
static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2404
    const WINED3DMATRIX *mat = NULL;
2405
    WINED3DMATRIX temp;
2406

2407 2408
    /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
     * below means it will be recorded in a state block change, but it
2409
     * works regardless where it is recorded.
2410 2411
     * If this is found to be wrong, change to StateBlock.
     */
2412
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2413
    TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2414

2415
    if (State <= HIGHEST_TRANSFORMSTATE)
2416 2417 2418 2419 2420 2421
    {
        mat = &This->updateStateBlock->transforms[State];
    } else {
        FIXME("Unhandled transform state!!\n");
    }

2422
    multiply_matrix(&temp, mat, pMatrix);
2423 2424

    /* Apply change via set transform - will reapply to eg. lights this way */
2425
    return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2426 2427 2428 2429 2430 2431
}

/*****
 * Get / Set Light
 *****/
/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2432
   you can reference any indexes you want as long as that number max are enabled at any
2433 2434
   one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
   However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2435
   but when recording, just build a chain pretty much of commands to be replayed.                  */
2436

2437
static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2438
    float rho;
2439
    struct wined3d_light_info *object = NULL;
2440 2441
    UINT Hi = LIGHTMAP_HASHFUNC(Index);
    struct list *e;
2442 2443

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444
    TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2445

2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461
    /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
     * the gl driver.
     */
    if(!pLight) {
        WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
        return WINED3DERR_INVALIDCALL;
    }

    switch(pLight->Type) {
        case WINED3DLIGHT_POINT:
        case WINED3DLIGHT_SPOT:
        case WINED3DLIGHT_PARALLELPOINT:
        case WINED3DLIGHT_GLSPOT:
            /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
             * most wanted
             */
2462 2463
            if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
            {
2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477
                WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
                return WINED3DERR_INVALIDCALL;
            }
            break;

        case WINED3DLIGHT_DIRECTIONAL:
            /* Ignores attenuation */
            break;

        default:
        WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
        return WINED3DERR_INVALIDCALL;
    }

2478 2479 2480
    LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
    {
        object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2481 2482
        if(object->OriginalIndex == Index) break;
        object = NULL;
2483 2484
    }

2485 2486 2487 2488 2489 2490
    if(!object) {
        TRACE("Adding new light\n");
        object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
        if(!object) {
            ERR("Out of memory error when allocating a light\n");
            return E_OUTOFMEMORY;
2491
        }
2492
        list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2493
        object->glIndex = -1;
2494
        object->OriginalIndex = Index;
2495 2496
    }

2497
    /* Initialize the object */
2498
    TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2499 2500 2501 2502 2503 2504 2505 2506
          pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
          pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
          pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
    TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
          pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
    TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);

    /* Save away the information */
2507
    object->OriginalParms = *pLight;
2508 2509

    switch (pLight->Type) {
2510
    case WINED3DLIGHT_POINT:
2511 2512 2513 2514 2515 2516 2517 2518 2519
        /* Position */
        object->lightPosn[0] = pLight->Position.x;
        object->lightPosn[1] = pLight->Position.y;
        object->lightPosn[2] = pLight->Position.z;
        object->lightPosn[3] = 1.0f;
        object->cutoff = 180.0f;
        /* FIXME: Range */
        break;

2520
    case WINED3DLIGHT_DIRECTIONAL:
2521 2522 2523 2524
        /* Direction */
        object->lightPosn[0] = -pLight->Direction.x;
        object->lightPosn[1] = -pLight->Direction.y;
        object->lightPosn[2] = -pLight->Direction.z;
2525
        object->lightPosn[3] = 0.0f;
2526 2527 2528 2529
        object->exponent     = 0.0f;
        object->cutoff       = 180.0f;
        break;

2530
    case WINED3DLIGHT_SPOT:
2531 2532 2533 2534
        /* Position */
        object->lightPosn[0] = pLight->Position.x;
        object->lightPosn[1] = pLight->Position.y;
        object->lightPosn[2] = pLight->Position.z;
2535
        object->lightPosn[3] = 1.0f;
2536 2537 2538 2539 2540

        /* Direction */
        object->lightDirn[0] = pLight->Direction.x;
        object->lightDirn[1] = pLight->Direction.y;
        object->lightDirn[2] = pLight->Direction.z;
2541
        object->lightDirn[3] = 1.0f;
2542 2543 2544 2545 2546 2547 2548 2549 2550

        /*
         * opengl-ish and d3d-ish spot lights use too different models for the
         * light "intensity" as a function of the angle towards the main light direction,
         * so we only can approximate very roughly.
         * however spot lights are rather rarely used in games (if ever used at all).
         * furthermore if still used, probably nobody pays attention to such details.
         */
        if (pLight->Falloff == 0) {
2551 2552 2553 2554 2555
            /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
             * falloff resp. exponent parameter as an exponent, so the spot light lighting
             * will always be 1.0 for both of them, and we don't have to care for the
             * rest of the rather complex calculation
             */
2556
            object->exponent = 0.0f;
2557 2558
        } else {
            rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2559 2560
            if (rho < 0.0001f) rho = 0.0001f;
            object->exponent = -0.3f/logf(cosf(rho/2));
2561
        }
2562 2563 2564
        if (object->exponent > 128.0f)
        {
            object->exponent = 128.0f;
2565
        }
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
        object->cutoff = pLight->Phi*90/M_PI;

        /* FIXME: Range */
        break;

    default:
        FIXME("Unrecognized light type %d\n", pLight->Type);
    }

    /* Update the live definitions if the light is currently assigned a glIndex */
2576
    if (object->glIndex != -1 && !This->isRecordingState) {
2577
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2578
    }
2579
    return WINED3D_OK;
2580 2581
}

2582 2583 2584
static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
{
    struct wined3d_light_info *lightInfo = NULL;
2585
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2586 2587
    DWORD Hi = LIGHTMAP_HASHFUNC(Index);
    struct list *e;
2588
    TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2589

2590 2591 2592
    LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
    {
        lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2593 2594 2595
        if(lightInfo->OriginalIndex == Index) break;
        lightInfo = NULL;
    }
2596 2597 2598

    if (lightInfo == NULL) {
        TRACE("Light information requested but light not defined\n");
2599
        return WINED3DERR_INVALIDCALL;
2600 2601
    }

2602
    *pLight = lightInfo->OriginalParms;
2603
    return WINED3D_OK;
2604 2605 2606
}

/*****
2607
 * Get / Set Light Enable
2608 2609
 *   (Note for consistency, renamed d3dx function by adding the 'set' prefix)
 *****/
2610 2611 2612
static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
{
    struct wined3d_light_info *lightInfo = NULL;
2613
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 2615
    UINT Hi = LIGHTMAP_HASHFUNC(Index);
    struct list *e;
2616
    TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2617

2618 2619 2620
    LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
    {
        lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2621 2622
        if(lightInfo->OriginalIndex == Index) break;
        lightInfo = NULL;
2623
    }
2624
    TRACE("Found light: %p\n", lightInfo);
2625 2626 2627

    /* Special case - enabling an undefined light creates one with a strict set of parms! */
    if (lightInfo == NULL) {
2628

2629
        TRACE("Light enabled requested but light not defined, so defining one!\n");
2630
        IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2631 2632

        /* Search for it again! Should be fairly quick as near head of list */
2633 2634 2635
        LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
        {
            lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2636 2637 2638
            if(lightInfo->OriginalIndex == Index) break;
            lightInfo = NULL;
        }
2639 2640
        if (lightInfo == NULL) {
            FIXME("Adding default lights has failed dismally\n");
2641
            return WINED3DERR_INVALIDCALL;
2642 2643 2644
        }
    }

2645 2646 2647
    if(!Enable) {
        if(lightInfo->glIndex != -1) {
            if(!This->isRecordingState) {
2648
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2649
            }
2650

2651
            This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2652
            lightInfo->glIndex = -1;
2653
        } else {
2654
            TRACE("Light already disabled, nothing to do\n");
2655
        }
2656
        lightInfo->enabled = FALSE;
2657
    } else {
2658
        lightInfo->enabled = TRUE;
2659
        if (lightInfo->glIndex != -1) {
2660 2661 2662
            /* nop */
            TRACE("Nothing to do as light was enabled\n");
        } else {
2663 2664 2665
            int i;
            /* Find a free gl light */
            for(i = 0; i < This->maxConcurrentLights; i++) {
2666 2667
                if(This->updateStateBlock->activeLights[i] == NULL) {
                    This->updateStateBlock->activeLights[i] = lightInfo;
2668 2669
                    lightInfo->glIndex = i;
                    break;
2670 2671
                }
            }
2672
            if(lightInfo->glIndex == -1) {
2673 2674 2675 2676 2677 2678 2679
                /* Our tests show that Windows returns D3D_OK in this situation, even with
                 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
                 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
                 * as well for those lights.
                 *
                 * TODO: Test how this affects rendering
                 */
2680
                WARN("Too many concurrently active lights\n");
2681
                return WINED3D_OK;
2682
            }
2683

2684 2685
            /* i == lightInfo->glIndex */
            if(!This->isRecordingState) {
2686
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2687 2688 2689
            }
        }
    }
2690

2691
    return WINED3D_OK;
2692 2693
}

2694 2695 2696
static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
{
    struct wined3d_light_info *lightInfo = NULL;
2697
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2698 2699
    struct list *e;
    UINT Hi = LIGHTMAP_HASHFUNC(Index);
2700
    TRACE("(%p) : for idx(%d)\n", This, Index);
2701

2702 2703 2704
    LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
    {
        lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2705 2706 2707
        if(lightInfo->OriginalIndex == Index) break;
        lightInfo = NULL;
    }
2708 2709 2710

    if (lightInfo == NULL) {
        TRACE("Light enabled state requested but light not defined\n");
2711
        return WINED3DERR_INVALIDCALL;
2712
    }
2713
    /* true is 128 according to SetLightEnable */
2714
    *pEnable = lightInfo->enabled ? 128 : 0;
2715
    return WINED3D_OK;
2716 2717 2718 2719 2720
}

/*****
 * Get / Set Clip Planes
 *****/
2721
static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2722
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723
    TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2724 2725

    /* Validate Index */
2726 2727
    if (Index >= This->adapter->gl_info.max_clipplanes)
    {
2728
        TRACE("Application has requested clipplane this device doesn't support\n");
2729
        return WINED3DERR_INVALIDCALL;
2730 2731
    }

2732
    This->updateStateBlock->changed.clipplane |= 1 << Index;
2733 2734 2735 2736 2737 2738 2739 2740 2741

    if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
       This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
       This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
       This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
        TRACE("Application is setting old values over, nothing to do\n");
        return WINED3D_OK;
    }

2742 2743 2744 2745 2746 2747 2748 2749
    This->updateStateBlock->clipplane[Index][0] = pPlane[0];
    This->updateStateBlock->clipplane[Index][1] = pPlane[1];
    This->updateStateBlock->clipplane[Index][2] = pPlane[2];
    This->updateStateBlock->clipplane[Index][3] = pPlane[3];

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2750
        return WINED3D_OK;
2751 2752
    }

2753
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2754

2755
    return WINED3D_OK;
2756 2757
}

2758
static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2759
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2760
    TRACE("(%p) : for idx %d\n", This, Index);
2761 2762

    /* Validate Index */
2763 2764
    if (Index >= This->adapter->gl_info.max_clipplanes)
    {
2765
        TRACE("Application has requested clipplane this device doesn't support\n");
2766
        return WINED3DERR_INVALIDCALL;
2767 2768 2769 2770 2771 2772
    }

    pPlane[0] = This->stateBlock->clipplane[Index][0];
    pPlane[1] = This->stateBlock->clipplane[Index][1];
    pPlane[2] = This->stateBlock->clipplane[Index][2];
    pPlane[3] = This->stateBlock->clipplane[Index][3];
2773
    return WINED3D_OK;
2774 2775 2776 2777 2778 2779
}

/*****
 * Get / Set Clip Plane Status
 *   WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
 *****/
2780
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2781 2782 2783
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    FIXME("(%p) : stub\n", This);
    if (NULL == pClipStatus) {
2784
      return WINED3DERR_INVALIDCALL;
2785 2786 2787
    }
    This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
    This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2788
    return WINED3D_OK;
2789 2790
}

2791
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2792
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2793
    FIXME("(%p) : stub\n", This);
2794
    if (NULL == pClipStatus) {
2795
      return WINED3DERR_INVALIDCALL;
2796 2797 2798
    }
    pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
    pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2799
    return WINED3D_OK;
2800 2801 2802 2803 2804
}

/*****
 * Get / Set Material
 *****/
2805
static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2806 2807 2808
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    This->updateStateBlock->changed.material = TRUE;
2809
    This->updateStateBlock->material = *pMaterial;
2810 2811 2812 2813

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2814
        return WINED3D_OK;
2815 2816
    }

2817
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2818
    return WINED3D_OK;
2819 2820
}

2821
static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2822
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2823
    *pMaterial = This->updateStateBlock->material;
2824 2825 2826 2827 2828 2829 2830 2831
    TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
        pMaterial->Diffuse.b, pMaterial->Diffuse.a);
    TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
        pMaterial->Ambient.b, pMaterial->Ambient.a);
    TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
        pMaterial->Specular.b, pMaterial->Specular.a);
    TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
        pMaterial->Emissive.b, pMaterial->Emissive.a);
2832
    TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2833

2834
    return WINED3D_OK;
2835 2836
}

2837 2838 2839
/*****
 * Get / Set Indices
 *****/
2840 2841 2842 2843
static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
        IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2844
    IWineD3DBuffer *oldIdxs;
2845

2846
    TRACE("(%p) : Setting to %p\n", This, pIndexData);
2847 2848 2849 2850
    oldIdxs = This->updateStateBlock->pIndexData;

    This->updateStateBlock->changed.indices = TRUE;
    This->updateStateBlock->pIndexData = pIndexData;
2851
    This->updateStateBlock->IndexFmt = fmt;
2852 2853 2854 2855

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2856 2857
        if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
        if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2858
        return WINED3D_OK;
2859 2860
    }

2861 2862
    if(oldIdxs != pIndexData) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2863 2864
        if(pIndexData) {
            InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2865
            IWineD3DBuffer_AddRef(pIndexData);
2866 2867 2868
        }
        if(oldIdxs) {
            InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2869
            IWineD3DBuffer_Release(oldIdxs);
2870
        }
2871
    }
2872

2873
    return WINED3D_OK;
2874 2875
}

2876 2877
static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
{
2878 2879 2880
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    *ppIndexData = This->stateBlock->pIndexData;
2881

2882
    /* up ref count on ppindexdata */
2883
    if (*ppIndexData) {
2884
        IWineD3DBuffer_AddRef(*ppIndexData);
2885
        TRACE("(%p) index data set to %p\n", This, ppIndexData);
2886 2887 2888
    }else{
        TRACE("(%p) No index data set\n", This);
    }
2889
    TRACE("Returning %p\n", *ppIndexData);
2890

2891
    return WINED3D_OK;
2892 2893
}

2894
/* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2895
static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)->(%d)\n", This, BaseIndex);

    if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
        TRACE("Application is setting the old value over, nothing to do\n");
        return WINED3D_OK;
    }

    This->updateStateBlock->baseVertexIndex = BaseIndex;

    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
        return WINED3D_OK;
    }
2910
    /* The base vertex index affects the stream sources */
2911 2912 2913 2914
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
    return WINED3D_OK;
}

2915
static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2916 2917 2918 2919 2920 2921 2922 2923 2924 2925
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p) : base_index %p\n", This, base_index);

    *base_index = This->stateBlock->baseVertexIndex;

    TRACE("Returning %u\n", *base_index);

    return WINED3D_OK;
}

2926 2927 2928
/*****
 * Get / Set Viewports
 *****/
2929
static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2930 2931 2932 2933
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("(%p)\n", This);
    This->updateStateBlock->changed.viewport = TRUE;
2934
    This->updateStateBlock->viewport = *pViewport;
2935 2936 2937 2938

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2939
        return WINED3D_OK;
2940 2941
    }

2942
    TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2943 2944
          pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);

2945
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2946
    return WINED3D_OK;
2947 2948 2949

}

2950
static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2951 2952
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)\n", This);
2953
    *pViewport = This->stateBlock->viewport;
2954
    return WINED3D_OK;
2955 2956
}

2957 2958 2959 2960
/*****
 * Get / Set Render States
 * TODO: Verify against dx9 definitions
 *****/
2961
static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2962 2963

    IWineD3DDeviceImpl  *This     = (IWineD3DDeviceImpl *)iface;
2964
    DWORD oldValue = This->stateBlock->renderState[State];
2965

2966
    TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2967

2968
    This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2969 2970 2971 2972 2973
    This->updateStateBlock->renderState[State] = Value;

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2974
        return WINED3D_OK;
2975 2976
    }

2977 2978 2979 2980 2981 2982
    /* Compared here and not before the assignment to allow proper stateblock recording */
    if(Value == oldValue) {
        TRACE("Application is setting the old value over, nothing to do\n");
    } else {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
    }
2983

2984
    return WINED3D_OK;
2985 2986
}

2987
static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2988
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989
    TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2990
    *pValue = This->stateBlock->renderState[State];
2991
    return WINED3D_OK;
2992 2993
}

2994
/*****
2995
 * Get / Set Sampler States
2996 2997 2998
 * TODO: Verify against dx9 definitions
 *****/

2999
static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3000
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 3002 3003 3004 3005 3006 3007 3008
    DWORD oldValue;

    TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
            This, Sampler, debug_d3dsamplerstate(Type), Type, Value);

    if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
        Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
    }
3009

3010
    if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3011
        ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3012 3013
        return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
    }
3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027
    /**
    * SetSampler is designed to allow for more than the standard up to 8 textures
    *  and Geforce has stopped supporting more than 6 standard textures in openGL.
    * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
    *
    * http://developer.nvidia.com/object/General_FAQ.html#t6
    *
    * There are two new settings for GForce
    * the sampler one:
    * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
    * and the texture one:
    * GL_MAX_TEXTURE_COORDS_ARB.
    * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
     ******************/
3028

3029
    oldValue = This->stateBlock->samplerState[Sampler][Type];
3030
    This->updateStateBlock->samplerState[Sampler][Type]         = Value;
3031
    This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3032 3033 3034 3035

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3036
        return WINED3D_OK;
3037 3038
    }

3039 3040 3041 3042 3043
    if(oldValue == Value) {
        TRACE("Application is setting the old value over, nothing to do\n");
        return WINED3D_OK;
    }

3044 3045
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));

3046
    return WINED3D_OK;
3047 3048
}

3049
static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3050
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 3052 3053 3054 3055 3056 3057 3058

    TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
            This, Sampler, debug_d3dsamplerstate(Type), Type);

    if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
        Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
    }

3059
    if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3060
        ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3061 3062
        return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
    }
3063
    *Value = This->stateBlock->samplerState[Sampler][Type];
3064
    TRACE("(%p) : Returning %#x\n", This, *Value);
3065

3066
    return WINED3D_OK;
3067 3068
}

3069
static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3070
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071

3072
    This->updateStateBlock->changed.scissorRect = TRUE;
3073
    if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3074 3075 3076
        TRACE("App is setting the old scissor rectangle over, nothing to do\n");
        return WINED3D_OK;
    }
3077
    CopyRect(&This->updateStateBlock->scissorRect, pRect);
3078 3079 3080 3081 3082 3083

    if(This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
        return WINED3D_OK;
    }

3084
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3085

3086
    return WINED3D_OK;
3087 3088
}

3089
static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3090 3091
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

3092
    *pRect = This->updateStateBlock->scissorRect;
3093
    TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3094
    return WINED3D_OK;
3095 3096
}

3097
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3098
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3099
    IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3100

3101 3102
    TRACE("(%p) : pDecl=%p\n", This, pDecl);

3103 3104 3105
    if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
    if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);

3106 3107 3108 3109 3110
    This->updateStateBlock->vertexDecl = pDecl;
    This->updateStateBlock->changed.vertexDecl = TRUE;

    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3111 3112 3113 3114 3115
        return WINED3D_OK;
    } else if(pDecl == oldDecl) {
        /* Checked after the assignment to allow proper stateblock recording */
        TRACE("Application is setting the old declaration over, nothing to do\n");
        return WINED3D_OK;
3116 3117
    }

3118
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3119
    return WINED3D_OK;
3120 3121
}

3122
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3123 3124 3125
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3126

3127
    *ppDecl = This->stateBlock->vertexDecl;
3128
    if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3129
    return WINED3D_OK;
3130 3131
}

3132
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3133 3134
    IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
    IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3135

3136
    This->updateStateBlock->vertexShader         = pShader;
3137
    This->updateStateBlock->changed.vertexShader = TRUE;
3138

3139
    if (This->isRecordingState) {
3140 3141
        if(pShader) IWineD3DVertexShader_AddRef(pShader);
        if(oldShader) IWineD3DVertexShader_Release(oldShader);
3142
        TRACE("Recording... not performing anything\n");
3143 3144 3145 3146 3147
        return WINED3D_OK;
    } else if(oldShader == pShader) {
        /* Checked here to allow proper stateblock recording */
        TRACE("App is setting the old shader over, nothing to do\n");
        return WINED3D_OK;
3148 3149
    }

3150
    TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3151 3152
    if(pShader) IWineD3DVertexShader_AddRef(pShader);
    if(oldShader) IWineD3DVertexShader_Release(oldShader);
3153 3154 3155

    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);

3156
    return WINED3D_OK;
3157 3158
}

3159
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3160
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161 3162

    if (NULL == ppShader) {
3163
        return WINED3DERR_INVALIDCALL;
3164 3165 3166
    }
    *ppShader = This->stateBlock->vertexShader;
    if( NULL != *ppShader)
3167
        IWineD3DVertexShader_AddRef(*ppShader);
3168

3169
    TRACE("(%p) : returning %p\n", This, *ppShader);
3170
    return WINED3D_OK;
3171 3172
}

3173
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3174 3175 3176 3177
    IWineD3DDevice *iface,
    UINT start,
    CONST BOOL *srcData,
    UINT count) {
3178

3179
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180
    unsigned int i, cnt = min(count, MAX_CONST_B - start);
3181

3182 3183
    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);
3184

3185
    if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3186

3187
    memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3188
    for (i = 0; i < cnt; i++)
3189
        TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3190

3191
    for (i = start; i < cnt + start; ++i) {
3192
        This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3193
    }
3194

3195
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3196

3197
    return WINED3D_OK;
3198 3199
}

3200
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3201 3202 3203 3204
    IWineD3DDevice *iface,
    UINT start,
    BOOL *dstData,
    UINT count) {
3205

3206
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3207
    int cnt = min(count, MAX_CONST_B - start);
3208

3209 3210
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3211

3212
    if (dstData == NULL || cnt < 0)
3213
        return WINED3DERR_INVALIDCALL;
3214

3215
    memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3216
    return WINED3D_OK;
3217 3218
}

3219
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3220 3221 3222 3223
    IWineD3DDevice *iface,
    UINT start,
    CONST int *srcData,
    UINT count) {
3224

3225
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3226
    unsigned int i, cnt = min(count, MAX_CONST_I - start);
3227

3228 3229 3230
    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);

3231
    if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3232

3233
    memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3234
    for (i = 0; i < cnt; i++)
3235
        TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3236
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3237 3238

    for (i = start; i < cnt + start; ++i) {
3239
        This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3240 3241
    }

3242
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3243

3244
    return WINED3D_OK;
3245
}
3246

3247
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3248 3249 3250 3251 3252
    IWineD3DDevice *iface,
    UINT start,
    int *dstData,
    UINT count) {

3253
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3254
    int cnt = min(count, MAX_CONST_I - start);
3255 3256 3257 3258

    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);

3259
    if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3260 3261
        return WINED3DERR_INVALIDCALL;

3262
    memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3263
    return WINED3D_OK;
3264
}
3265

3266
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3267 3268 3269 3270
    IWineD3DDevice *iface,
    UINT start,
    CONST float *srcData,
    UINT count) {
3271

3272
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273
    UINT i;
3274 3275 3276

    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);
3277

3278
    /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3279
    if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3280 3281
        return WINED3DERR_INVALIDCALL;

3282 3283 3284 3285 3286 3287
    memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
    if(TRACE_ON(d3d)) {
        for (i = 0; i < count; i++)
            TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
                srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
    }
3288

3289 3290
    if (!This->isRecordingState)
    {
3291
        This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3292 3293
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
    }
3294

3295 3296
    memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
            sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3297 3298 3299 3300

    return WINED3D_OK;
}

3301
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3302 3303 3304 3305 3306
    IWineD3DDevice *iface,
    UINT start,
    float *dstData,
    UINT count) {

3307
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3308
    int cnt = min(count, This->d3d_vshader_constantF - start);
3309

3310 3311
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3312

3313 3314 3315
    if (dstData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3316
    memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3317
    return WINED3D_OK;
3318 3319
}

3320 3321
static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
    DWORD i;
3322 3323
    for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
    {
3324 3325 3326 3327
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
    }
}

3328 3329 3330 3331
static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
{
    DWORD i = This->rev_tex_unit_map[unit];
    DWORD j = This->texUnitMap[stage];
3332 3333

    This->texUnitMap[stage] = unit;
3334 3335 3336
    if (i != WINED3D_UNMAPPED_STAGE && i != stage)
    {
        This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3337 3338 3339
    }

    This->rev_tex_unit_map[unit] = stage;
3340 3341 3342
    if (j != WINED3D_UNMAPPED_STAGE && j != unit)
    {
        This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3343 3344 3345
    }
}

3346 3347 3348
static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
    int i;

3349
    This->fixed_function_usage_map = 0;
3350
    for (i = 0; i < MAX_TEXTURES; ++i) {
3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
        WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
        WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
        DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
        DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
        DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
        DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
        DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
        DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;

        if (color_op == WINED3DTOP_DISABLE) {
            /* Not used, and disable higher stages */
            break;
        }

        if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
                || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
                || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
                || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
                || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
                || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3371
            This->fixed_function_usage_map |= (1 << i);
3372 3373 3374
        }

        if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3375
            This->fixed_function_usage_map |= (1 << (i + 1));
3376
        }
3377 3378 3379
    }
}

3380
static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3381
    unsigned int i, tex;
3382
    WORD ffu_map;
3383 3384

    device_update_fixed_function_usage_map(This);
3385
    ffu_map = This->fixed_function_usage_map;
3386

3387
    if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3388 3389 3390 3391
            This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
        for (i = 0; ffu_map; ffu_map >>= 1, ++i)
        {
            if (!(ffu_map & 1)) continue;
3392

3393 3394 3395
            if (This->texUnitMap[i] != i) {
                device_map_stage(This, i, i);
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3396
                markTextureStagesDirty(This, i);
3397 3398 3399 3400 3401
            }
        }
        return;
    }

3402 3403
    /* Now work out the mapping */
    tex = 0;
3404 3405 3406
    for (i = 0; ffu_map; ffu_map >>= 1, ++i)
    {
        if (!(ffu_map & 1)) continue;
3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417

        if (This->texUnitMap[i] != tex) {
            device_map_stage(This, i, tex);
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
            markTextureStagesDirty(This, i);
        }

        ++tex;
    }
}

3418
static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3419 3420
    const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
            ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3421
    unsigned int i;
3422

3423
    for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3424 3425
        if (sampler_type[i] && This->texUnitMap[i] != i)
        {
3426 3427 3428 3429 3430 3431 3432 3433 3434
            device_map_stage(This, i, i);
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
            if (i < MAX_TEXTURES) {
                markTextureStagesDirty(This, i);
            }
        }
    }
}

3435
static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3436
        const DWORD *vshader_sampler_tokens, DWORD unit)
3437
{
3438
    DWORD current_mapping = This->rev_tex_unit_map[unit];
3439

3440 3441
    /* Not currently used */
    if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3442 3443 3444 3445 3446 3447

    if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
        /* Used by a fragment sampler */

        if (!pshader_sampler_tokens) {
            /* No pixel shader, check fixed function */
3448
            return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3449 3450 3451 3452 3453 3454 3455
        }

        /* Pixel shader, check the shader's sampler map */
        return !pshader_sampler_tokens[current_mapping];
    }

    /* Used by a vertex sampler */
3456
    return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3457 3458 3459
}

static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3460 3461 3462
    const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
            ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
    const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3463
    int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.max_combined_samplers) - 1;
3464 3465 3466 3467 3468
    int i;

    if (ps) {
        IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;

3469 3470
        /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
         * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3471
        pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3472 3473 3474
    }

    for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3475
        DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3476 3477
        if (vshader_sampler_type[i])
        {
3478 3479
            if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
            {
3480 3481 3482 3483 3484
                /* Already mapped somewhere */
                continue;
            }

            while (start >= 0) {
3485 3486
                if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
                {
3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499
                    device_map_stage(This, vsampler_idx, start);
                    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));

                    --start;
                    break;
                }

                --start;
            }
        }
    }
}

3500
void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3501 3502
    BOOL vs = use_vs(This->stateBlock);
    BOOL ps = use_ps(This->stateBlock);
3503
    /*
3504 3505 3506 3507 3508 3509
     * Rules are:
     * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
     * that would be really messy and require shader recompilation
     * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
     * to be reset. Because of that try to work with a 1:1 mapping as much as possible
     */
3510 3511
    if (ps) {
        device_map_psamplers(This);
3512
    } else {
3513
        device_map_fixed_function_samplers(This);
3514
    }
3515 3516 3517 3518

    if (vs) {
        device_map_vsamplers(This, ps);
    }
3519 3520
}

3521
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3522
    IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
3523
    IWineD3DPixelShader *oldShader  = This->updateStateBlock->pixelShader;
3524 3525 3526 3527 3528
    This->updateStateBlock->pixelShader         = pShader;
    This->updateStateBlock->changed.pixelShader = TRUE;

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
3529
        TRACE("Recording... not performing anything\n");
3530
    }
3531

3532 3533
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3534 3535
        if(pShader) IWineD3DPixelShader_AddRef(pShader);
        if(oldShader) IWineD3DPixelShader_Release(oldShader);
3536
        return WINED3D_OK;
3537 3538
    }

3539 3540 3541 3542 3543
    if(pShader == oldShader) {
        TRACE("App is setting the old pixel shader over, nothing to do\n");
        return WINED3D_OK;
    }

3544 3545 3546
    if(pShader) IWineD3DPixelShader_AddRef(pShader);
    if(oldShader) IWineD3DPixelShader_Release(oldShader);

3547
    TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3548
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3549

3550
    return WINED3D_OK;
3551 3552
}

3553
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3554
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3555

3556
    if (NULL == ppShader) {
3557
        WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3558
        return WINED3DERR_INVALIDCALL;
3559 3560
    }

3561
    *ppShader =  This->stateBlock->pixelShader;
3562
    if (NULL != *ppShader) {
3563 3564 3565
        IWineD3DPixelShader_AddRef(*ppShader);
    }
    TRACE("(%p) : returning %p\n", This, *ppShader);
3566
    return WINED3D_OK;
3567 3568
}

3569
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3570 3571 3572 3573
    IWineD3DDevice *iface,
    UINT start,
    CONST BOOL *srcData,
    UINT count) {
3574

3575
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3576
    unsigned int i, cnt = min(count, MAX_CONST_B - start);
3577

3578
    TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3579
            iface, srcData, start, count);
3580

3581
    if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3582

3583
    memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3584
    for (i = 0; i < cnt; i++)
3585
        TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3586

3587
    for (i = start; i < cnt + start; ++i) {
3588
        This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3589
    }
3590

3591
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3592

3593
    return WINED3D_OK;
3594 3595
}

3596
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3597 3598 3599 3600
    IWineD3DDevice *iface,
    UINT start,
    BOOL *dstData,
    UINT count) {
3601

3602
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3603
    int cnt = min(count, MAX_CONST_B - start);
3604

3605 3606
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3607

3608
    if (dstData == NULL || cnt < 0)
3609
        return WINED3DERR_INVALIDCALL;
3610

3611
    memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3612
    return WINED3D_OK;
3613 3614
}

3615
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3616 3617 3618 3619
    IWineD3DDevice *iface,
    UINT start,
    CONST int *srcData,
    UINT count) {
3620 3621

    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3622
    unsigned int i, cnt = min(count, MAX_CONST_I - start);
3623

3624
    TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3625
            iface, srcData, start, count);
3626

3627
    if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3628

3629
    memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3630
    for (i = 0; i < cnt; i++)
3631
        TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3632
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3633 3634

    for (i = start; i < cnt + start; ++i) {
3635
        This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3636
    }
3637

3638
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3639

3640
    return WINED3D_OK;
3641
}
3642

3643
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3644 3645 3646 3647 3648
    IWineD3DDevice *iface,
    UINT start,
    int *dstData,
    UINT count) {

3649
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3650
    int cnt = min(count, MAX_CONST_I - start);
3651 3652 3653 3654 3655 3656 3657

    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);

    if (dstData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3658
    memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3659
    return WINED3D_OK;
3660 3661
}

3662
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3663 3664 3665 3666 3667
    IWineD3DDevice *iface,
    UINT start,
    CONST float *srcData,
    UINT count) {

3668
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3669
    UINT i;
3670 3671 3672 3673

    TRACE("(iface %p, srcData %p, start %d, count %d)\n",
            iface, srcData, start, count);

3674
    /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3675
    if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3676 3677
        return WINED3DERR_INVALIDCALL;

3678 3679 3680 3681 3682 3683
    memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
    if(TRACE_ON(d3d)) {
        for (i = 0; i < count; i++)
            TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
                srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
    }
3684

3685 3686
    if (!This->isRecordingState)
    {
3687
        This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3688 3689
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
    }
3690

3691 3692
    memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
            sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3693 3694 3695 3696

    return WINED3D_OK;
}

3697
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3698 3699 3700 3701 3702
    IWineD3DDevice *iface,
    UINT start,
    float *dstData,
    UINT count) {

3703
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704
    int cnt = min(count, This->d3d_pshader_constantF - start);
3705

3706 3707
    TRACE("(iface %p, dstData %p, start %d, count %d)\n",
            iface, dstData, start, count);
3708

3709 3710 3711
    if (dstData == NULL || cnt < 0)
        return WINED3DERR_INVALIDCALL;

3712
    memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3713
    return WINED3D_OK;
3714 3715
}

3716
/* Context activation is done by the caller. */
3717
#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3718
static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3719 3720
        const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
        DWORD DestFVF)
3721
{
3722
    char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3723
    unsigned int i;
3724
    WINED3DVIEWPORT vp;
3725
    WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3726
    BOOL doClip;
3727
    DWORD numTextures;
3728

3729
    if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3730
    {
3731 3732 3733
        WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
    }

3734
    if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3735
    {
3736 3737 3738 3739
        ERR("Source has no position mask\n");
        return WINED3DERR_INVALIDCALL;
    }

3740 3741 3742
    /* We might access VBOs from this code, so hold the lock */
    ENTER_GL();

3743
    if (dest->resource.allocatedMemory == NULL) {
3744
        buffer_get_sysmem(dest);
3745 3746 3747 3748 3749
    }

    /* Get a pointer into the destination vbo(create one if none exists) and
     * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
     */
3750 3751 3752 3753
    if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
    {
        dest->flags |= WINED3D_BUFFER_CREATEBO;
        IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3754 3755
    }

3756 3757
    if (dest->buffer_object)
    {
3758 3759 3760 3761 3762 3763 3764
        unsigned char extrabytes = 0;
        /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
         * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
         * this may write 4 extra bytes beyond the area that should be written
         */
        if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
        dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3765 3766
        if(!dest_conv_addr) {
            ERR("Out of memory\n");
3767 3768
            /* Continue without storing converted vertices */
        }
3769
        dest_conv = dest_conv_addr;
3770 3771 3772
    }

    /* Should I clip?
3773
     * a) WINED3DRS_CLIPPING is enabled
3774 3775
     * b) WINED3DVOP_CLIP is passed
     */
3776
    if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791
        static BOOL warned = FALSE;
        /*
         * The clipping code is not quite correct. Some things need
         * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
         * so disable clipping for now.
         * (The graphics in Half-Life are broken, and my processvertices
         *  test crashes with IDirect3DDevice3)
        doClip = TRUE;
         */
        doClip = FALSE;
        if(!warned) {
           warned = TRUE;
           FIXME("Clipping is broken and disabled for now\n");
        }
    } else doClip = FALSE;
3792
    dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3793 3794

    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3795
                                 WINED3DTS_VIEW,
3796 3797
                                 &view_mat);
    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3798
                                 WINED3DTS_PROJECTION,
3799 3800
                                 &proj_mat);
    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3801
                                 WINED3DTS_WORLDMATRIX(0),
3802 3803
                                 &world_mat);

3804
    TRACE("View mat:\n");
3805 3806 3807 3808
    TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
    TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
    TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
    TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3809

3810
    TRACE("Proj mat:\n");
3811 3812 3813 3814
    TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
    TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
    TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
    TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3815

3816
    TRACE("World mat:\n");
3817 3818 3819 3820
    TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
    TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
    TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
    TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3821 3822 3823

    /* Get the viewport */
    IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3824
    TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3825 3826 3827 3828 3829
          vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);

    multiply_matrix(&mat,&view_mat,&world_mat);
    multiply_matrix(&mat,&proj_mat,&mat);

3830
    numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3831 3832 3833 3834

    for (i = 0; i < dwCount; i+= 1) {
        unsigned int tex_index;

3835 3836
        if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
             ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3837
            /* The position first */
3838 3839
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
            const float *p = (const float *)(element->data + i * element->stride);
3840 3841 3842 3843
            float x, y, z, rhw;
            TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);

            /* Multiplication with world, view and projection matrix */
3844 3845 3846 3847
            x =   (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
            y =   (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
            z =   (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
            rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
3848 3849 3850 3851 3852 3853 3854

            TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);

            /* WARNING: The following things are taken from d3d7 and were not yet checked
             * against d3d8 or d3d9!
             */

3855
            /* Clipping conditions: From msdn
3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867
             *
             * A vertex is clipped if it does not match the following requirements
             * -rhw < x <= rhw
             * -rhw < y <= rhw
             *    0 < z <= rhw
             *    0 < rhw ( Not in d3d7, but tested in d3d7)
             *
             * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
             * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
             *
             */

3868
            if( !doClip ||
3869
                ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3870
                  (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3871 3872 3873
                  ( rhw > eps ) ) ) {

                /* "Normal" viewport transformation (not clipped)
3874
                 * 1) The values are divided by rhw
3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914
                 * 2) The y axis is negative, so multiply it with -1
                 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
                 *    -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
                 * 4) Multiply x with Width/2 and add Width/2
                 * 5) The same for the height
                 * 6) Add the viewpoint X and Y to the 2D coordinates and
                 *    The minimum Z value to z
                 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
                 *
                 * Well, basically it's simply a linear transformation into viewport
                 * coordinates
                 */

                x /= rhw;
                y /= rhw;
                z /= rhw;

                y *= -1;

                x *= vp.Width / 2;
                y *= vp.Height / 2;
                z *= vp.MaxZ - vp.MinZ;

                x += vp.Width / 2 + vp.X;
                y += vp.Height / 2 + vp.Y;
                z += vp.MinZ;

                rhw = 1 / rhw;
            } else {
                /* That vertex got clipped
                 * Contrary to OpenGL it is not dropped completely, it just
                 * undergoes a different calculation.
                 */
                TRACE("Vertex got clipped\n");
                x += rhw;
                y += rhw;

                x  /= 2;
                y  /= 2;

3915
                /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930
                 * outside of the main vertex buffer memory. That needs some more
                 * investigation...
                 */
            }

            TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);


            ( (float *) dest_ptr)[0] = x;
            ( (float *) dest_ptr)[1] = y;
            ( (float *) dest_ptr)[2] = z;
            ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */

            dest_ptr += 3 * sizeof(float);

3931
            if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3932 3933
                dest_ptr += sizeof(float);
            }
3934 3935 3936 3937 3938 3939 3940 3941 3942 3943

            if(dest_conv) {
                float w = 1 / rhw;
                ( (float *) dest_conv)[0] = x * w;
                ( (float *) dest_conv)[1] = y * w;
                ( (float *) dest_conv)[2] = z * w;
                ( (float *) dest_conv)[3] = w;

                dest_conv += 3 * sizeof(float);

3944
                if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3945 3946 3947
                    dest_conv += sizeof(float);
                }
            }
3948
        }
3949
        if (DestFVF & WINED3DFVF_PSIZE) {
3950
            dest_ptr += sizeof(DWORD);
3951
            if(dest_conv) dest_conv += sizeof(DWORD);
3952
        }
3953
        if (DestFVF & WINED3DFVF_NORMAL) {
3954 3955
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
            const float *normal = (const float *)(element->data + i * element->stride);
3956 3957 3958
            /* AFAIK this should go into the lighting information */
            FIXME("Didn't expect the destination to have a normal\n");
            copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3959 3960 3961
            if(dest_conv) {
                copy_and_next(dest_conv, normal, 3 * sizeof(float));
            }
3962 3963
        }

3964
        if (DestFVF & WINED3DFVF_DIFFUSE) {
3965 3966
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
            const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3967 3968
            if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
            {
3969 3970
                static BOOL warned = FALSE;

3971
                if(!warned) {
3972 3973 3974 3975 3976 3977
                    ERR("No diffuse color in source, but destination has one\n");
                    warned = TRUE;
                }

                *( (DWORD *) dest_ptr) = 0xffffffff;
                dest_ptr += sizeof(DWORD);
3978 3979 3980 3981 3982

                if(dest_conv) {
                    *( (DWORD *) dest_conv) = 0xffffffff;
                    dest_conv += sizeof(DWORD);
                }
3983
            }
3984
            else {
3985
                copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3986 3987 3988 3989 3990 3991 3992
                if(dest_conv) {
                    *( (DWORD *) dest_conv)  = (*color_d & 0xff00ff00)      ; /* Alpha + green */
                    *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
                    *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
                    dest_conv += sizeof(DWORD);
                }
            }
3993 3994
        }

3995 3996
        if (DestFVF & WINED3DFVF_SPECULAR)
        {
3997
            /* What's the color value in the feedback buffer? */
3998 3999
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
            const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4000 4001
            if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
            {
4002 4003
                static BOOL warned = FALSE;

4004
                if(!warned) {
4005 4006 4007 4008 4009 4010
                    ERR("No specular color in source, but destination has one\n");
                    warned = TRUE;
                }

                *( (DWORD *) dest_ptr) = 0xFF000000;
                dest_ptr += sizeof(DWORD);
4011 4012 4013 4014 4015

                if(dest_conv) {
                    *( (DWORD *) dest_conv) = 0xFF000000;
                    dest_conv += sizeof(DWORD);
                }
4016 4017 4018
            }
            else {
                copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4019 4020 4021 4022 4023 4024
                if(dest_conv) {
                    *( (DWORD *) dest_conv)  = (*color_s & 0xff00ff00)      ; /* Alpha + green */
                    *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
                    *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
                    dest_conv += sizeof(DWORD);
                }
4025 4026 4027 4028
            }
        }

        for (tex_index = 0; tex_index < numTextures; tex_index++) {
4029 4030
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
            const float *tex_coord = (const float *)(element->data + i * element->stride);
4031 4032
            if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
            {
4033 4034
                ERR("No source texture, but destination requests one\n");
                dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4035
                if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4036 4037 4038
            }
            else {
                copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4039 4040 4041
                if(dest_conv) {
                    copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
                }
4042 4043 4044 4045
            }
        }
    }

4046
    if(dest_conv) {
4047
        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4048 4049 4050 4051 4052 4053
        checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
        GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
                                      dwCount * get_flexible_vertex_size(DestFVF),
                                      dest_conv_addr));
        checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
        HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4054 4055 4056 4057
    }

    LEAVE_GL();

4058 4059 4060 4061
    return WINED3D_OK;
}
#undef copy_and_next

4062
static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4063 4064
        UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
        DWORD DestFVF)
4065
{
4066
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4067
    struct wined3d_stream_info stream_info;
4068
    BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4069
    TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4070

4071 4072
    if(pVertexDecl) {
        ERR("Output vertex declaration not implemented yet\n");
4073
    }
4074

4075
    /* Need any context to write to the vbo. */
4076
    ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4077

4078 4079 4080 4081
    /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
     * control the streamIsUP flag, thus restore it afterwards.
     */
    This->stateBlock->streamIsUP = FALSE;
4082
    device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4083
    This->stateBlock->streamIsUP = streamWasUP;
4084

4085 4086
    if(vbo || SrcStartIndex) {
        unsigned int i;
4087
        /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4088
         * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4089 4090 4091
         *
         * Also get the start index in, but only loop over all elements if there's something to add at all.
         */
4092
        for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4093
        {
4094 4095 4096 4097 4098
            struct wined3d_stream_info_element *e;

            if (!(stream_info.use_map & (1 << i))) continue;

            e = &stream_info.elements[i];
4099
            if (e->buffer_object)
4100
            {
4101 4102
                struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
                e->buffer_object = 0;
4103
                e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4104 4105 4106 4107 4108
                ENTER_GL();
                GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
                vb->buffer_object = 0;
                LEAVE_GL();
            }
4109
            if (e->data) e->data += e->stride * SrcStartIndex;
4110 4111 4112
        }
    }

4113
    return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4114
            (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4115
}
4116

4117 4118 4119 4120
/*****
 * Get / Set Texture Stage States
 * TODO: Verify against dx9 definitions
 *****/
4121
static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4122
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4123
    DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4124

4125
    TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4126

4127 4128 4129 4130 4131
    if (Stage >= MAX_TEXTURES) {
        WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
        return WINED3D_OK;
    }

4132
    This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4133 4134
    This->updateStateBlock->textureState[Stage][Type]         = Value;

4135 4136 4137 4138 4139
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
        return WINED3D_OK;
    }

4140 4141 4142 4143 4144 4145
    /* Checked after the assignments to allow proper stateblock recording */
    if(oldValue == Value) {
        TRACE("App is setting the old value over, nothing to do\n");
        return WINED3D_OK;
    }

4146
    if(Stage > This->stateBlock->lowest_disabled_stage &&
4147
       This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4148 4149 4150 4151 4152 4153 4154
        /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
         * Changes in other states are important on disabled stages too
         */
        return WINED3D_OK;
    }

    if(Type == WINED3DTSS_COLOROP) {
4155
        unsigned int i;
4156

4157
        if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4158 4159 4160 4161 4162 4163
            /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
             * they have to be disabled
             *
             * The current stage is dirtified below.
             */
            for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4164
                TRACE("Additionally dirtifying stage %u\n", i);
4165 4166 4167
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
            }
            This->stateBlock->lowest_disabled_stage = Stage;
4168
            TRACE("New lowest disabled: %u\n", Stage);
4169
        } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4170 4171 4172 4173 4174 4175 4176
            /* Previously disabled stage enabled. Stages above it may need enabling
             * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
             * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
             *
             * Again stage Stage doesn't need to be dirtified here, it is handled below.
             */

4177 4178
            for (i = Stage + 1; i < This->adapter->gl_info.max_texture_stages; ++i)
            {
4179 4180 4181
                if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
                    break;
                }
4182
                TRACE("Additionally dirtifying stage %u due to enable\n", i);
4183 4184 4185
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
            }
            This->stateBlock->lowest_disabled_stage = i;
4186
            TRACE("New lowest disabled: %u\n", i);
4187 4188 4189 4190 4191
        }
    }

    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));

4192
    return WINED3D_OK;
4193 4194
}

4195
static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4196
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4197
    TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4198
    *pValue = This->updateStateBlock->textureState[Stage][Type];
4199
    return WINED3D_OK;
4200 4201
}

4202
/*****
4203
 * Get / Set Texture
4204
 *****/
4205 4206 4207
static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
        DWORD stage, IWineD3DBaseTexture *texture)
{
4208
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4209
    IWineD3DBaseTexture *prev;
4210

4211
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4212

4213 4214
    if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
        stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4215

4216 4217 4218 4219 4220
    /* Windows accepts overflowing this array... we do not. */
    if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
    {
        WARN("Ignoring invalid stage %u.\n", stage);
        return WINED3D_OK;
4221 4222
    }

4223
    /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4224
    if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4225
    {
4226
        WARN("Rejecting attempt to set scratch texture.\n");
4227
        return WINED3DERR_INVALIDCALL;
4228 4229
    }

4230
    This->updateStateBlock->changed.textures |= 1 << stage;
4231

4232 4233
    prev = This->updateStateBlock->textures[stage];
    TRACE("Previous texture %p.\n", prev);
4234

4235 4236 4237
    if (texture == prev)
    {
        TRACE("App is setting the same texture again, nothing to do.\n");
4238
        return WINED3D_OK;
4239 4240
    }

4241 4242 4243 4244 4245 4246 4247 4248 4249 4250
    TRACE("Setting new texture to %p.\n", texture);
    This->updateStateBlock->textures[stage] = texture;

    if (This->isRecordingState)
    {
        TRACE("Recording... not performing anything\n");

        if (texture) IWineD3DBaseTexture_AddRef(texture);
        if (prev) IWineD3DBaseTexture_Release(prev);

4251 4252 4253
        return WINED3D_OK;
    }

4254 4255 4256 4257 4258
    if (texture)
    {
        IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
        LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
        UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4259

4260
        IWineD3DBaseTexture_AddRef(texture);
4261

4262
        if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4263 4264 4265 4266
        {
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
        }

4267 4268 4269 4270 4271 4272 4273
        if (!prev && stage < MAX_TEXTURES)
        {
            /* The source arguments for color and alpha ops have different
             * meanings when a NULL texture is bound, so the COLOROP and
             * ALPHAOP have to be dirtified. */
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4274 4275
        }

4276
        if (bind_count == 1) t->baseTexture.sampler = stage;
4277
    }
4278

4279 4280 4281 4282
    if (prev)
    {
        IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
        LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4283

4284 4285 4286 4287 4288 4289
        IWineD3DBaseTexture_Release(prev);

        if (!texture && stage < MAX_TEXTURES)
        {
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4290
        }
4291

4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304
        if (bind_count && t->baseTexture.sampler == stage)
        {
            unsigned int i;

            /* Search for other stages the texture is bound to. Shouldn't
             * happen if applications bind textures to a single stage only. */
            TRACE("Searching for other stages the texture is bound to.\n");
            for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
            {
                if (This->updateStateBlock->textures[i] == prev)
                {
                    TRACE("Texture is also bound to stage %u.\n", i);
                    t->baseTexture.sampler = i;
4305 4306 4307 4308
                    break;
                }
            }
        }
4309 4310
    }

4311
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4312

4313
    return WINED3D_OK;
4314 4315
}

4316
static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4317
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4318 4319 4320 4321 4322 4323

    TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);

    if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
        Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
    }
4324

4325
    if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4326
        ERR("Current stage overflows textures array (stage %d)\n", Stage);
4327 4328 4329
        return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
    }

4330
    *ppTexture=This->stateBlock->textures[Stage];
4331 4332
    if (*ppTexture)
        IWineD3DBaseTexture_AddRef(*ppTexture);
4333

4334 4335
    TRACE("(%p) : Returning %p\n", This, *ppTexture);

4336
    return WINED3D_OK;
4337 4338 4339 4340 4341
}

/*****
 * Get Back Buffer
 *****/
4342
static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4343
                                                IWineD3DSurface **ppBackBuffer) {
4344
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4345 4346 4347
    IWineD3DSwapChain *swapChain;
    HRESULT hr;

4348 4349
    TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);

Oliver Stieber's avatar
Oliver Stieber committed
4350
    hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, &swapChain);
4351
    if (hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
4352
        hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4353
            IWineD3DSwapChain_Release(swapChain);
4354
    } else {
Oliver Stieber's avatar
Oliver Stieber committed
4355
        *ppBackBuffer = NULL;
4356
    }
Oliver Stieber's avatar
Oliver Stieber committed
4357
    return hr;
4358 4359
}

4360
static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4361 4362
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    WARN("(%p) : stub, calling idirect3d for now\n", This);
4363
    return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4364 4365
}

4366
static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4367
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4368 4369
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
4370

4371
    if(iSwapChain > 0) {
4372
        hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4373 4374
        if (hr == WINED3D_OK) {
            hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4375
            IWineD3DSwapChain_Release(swapChain);
4376 4377 4378
        } else {
            FIXME("(%p) Error getting display mode\n", This);
        }
4379
    } else {
4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391
        /* Don't read the real display mode,
           but return the stored mode instead. X11 can't change the color
           depth, and some apps are pretty angry if they SetDisplayMode from
           24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp

           Also don't relay to the swapchain because with ddraw it's possible
           that there isn't a swapchain at all */
        pMode->Width = This->ddraw_width;
        pMode->Height = This->ddraw_height;
        pMode->Format = This->ddraw_format;
        pMode->RefreshRate = 0;
        hr = WINED3D_OK;
Oliver Stieber's avatar
Oliver Stieber committed
4392
    }
4393

Oliver Stieber's avatar
Oliver Stieber committed
4394
    return hr;
4395
}
4396

4397 4398 4399 4400
/*****
 * Stateblock related functions
 *****/

4401
static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4402
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4403 4404
    IWineD3DStateBlock *stateblock;
    HRESULT hr;
4405

4406
    TRACE("(%p)\n", This);
4407

4408
    if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4409

4410 4411
    hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
    if (FAILED(hr)) return hr;
4412

4413
    IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4414
    This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4415
    This->isRecordingState = TRUE;
4416

4417 4418
    TRACE("(%p) recording stateblock %p\n", This, stateblock);

4419
    return WINED3D_OK;
4420 4421
}

4422
static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4423
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4424
    IWineD3DStateBlockImpl *object = This->updateStateBlock;
4425 4426

    if (!This->isRecordingState) {
4427
        WARN("(%p) not recording! returning error\n", This);
4428
        *ppStateBlock = NULL;
4429
        return WINED3DERR_INVALIDCALL;
4430 4431
    }

4432
    stateblock_init_contained_states(object);
4433 4434

    *ppStateBlock = (IWineD3DStateBlock*) object;
4435
    This->isRecordingState = FALSE;
4436
    This->updateStateBlock = This->stateBlock;
4437 4438 4439
    IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
    /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
    TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4440
    return WINED3D_OK;
4441 4442
}

4443 4444 4445
/*****
 * Scene related functions
 *****/
4446
static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4447 4448 4449
    /* At the moment we have no need for any functionality at the beginning
       of a scene                                                          */
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4450 4451 4452 4453 4454 4455 4456
    TRACE("(%p)\n", This);

    if(This->inScene) {
        TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
        return WINED3DERR_INVALIDCALL;
    }
    This->inScene = TRUE;
4457
    return WINED3D_OK;
4458 4459
}

4460
static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4461 4462
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)\n", This);
4463 4464 4465 4466 4467 4468

    if(!This->inScene) {
        TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
        return WINED3DERR_INVALIDCALL;
    }

4469
    ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4470
    /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4471
    wglFlush();
4472 4473 4474
    /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
     * fails
     */
4475

4476
    This->inScene = FALSE;
4477
    return WINED3D_OK;
4478 4479
}

4480
static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4481
                                          CONST RECT* pSourceRect, CONST RECT* pDestRect,
4482
                                          HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4483
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4484 4485 4486
    IWineD3DSwapChain *swapChain = NULL;
    int i;
    int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4487

Oliver Stieber's avatar
Oliver Stieber committed
4488
    TRACE("(%p) Presenting the frame\n", This);
4489

4490
    for(i = 0 ; i < swapchains ; i ++) {
4491

4492
        IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
Oliver Stieber's avatar
Oliver Stieber committed
4493 4494
        TRACE("presentinng chain %d, %p\n", i, swapChain);
        IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4495
        IWineD3DSwapChain_Release(swapChain);
4496 4497
    }

4498
    return WINED3D_OK;
4499 4500
}

4501 4502 4503 4504 4505 4506 4507 4508
/* Not called from the VTable (internal subroutine) */
HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This,  IWineD3DSurfaceImpl *target, DWORD Count,
                                        CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
                                        float Z, DWORD Stencil) {
    GLbitfield     glMask = 0;
    unsigned int   i;
    WINED3DRECT curRect;
    RECT vp_rect;
4509
    const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4510
    UINT drawable_width, drawable_height;
4511
    IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4512
    IWineD3DSwapChainImpl *swapchain = NULL;
4513
    struct wined3d_context *context;
4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548

    /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
     * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
     * for the cleared parts, and the untouched parts.
     *
     * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
     * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
     * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
     * checking all this if the dest surface is in the drawable anyway.
     */
    if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
        while(1) {
            if(vp->X != 0 || vp->Y != 0 ||
               vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
                IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
                break;
            }
            if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
               This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
               This->stateBlock->scissorRect.right < target->currentDesc.Width ||
               This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
                IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
                break;
            }
            if(Count > 0 && pRects && (
               pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
               pRects[0].x2 < target->currentDesc.Width ||
               pRects[0].y2 < target->currentDesc.Height)) {
                IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
                break;
            }
            break;
        }
    }

4549
    context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4550

4551
    target->get_drawable_size(context, &drawable_width, &drawable_height);
4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563

    ENTER_GL();

    /* Only set the values up once, as they are not changing */
    if (Flags & WINED3DCLEAR_STENCIL) {
        glClearStencil(Stencil);
        checkGLcall("glClearStencil");
        glMask = glMask | GL_STENCIL_BUFFER_BIT;
        glStencilMask(0xFFFFFFFF);
    }

    if (Flags & WINED3DCLEAR_ZBUFFER) {
4564
        DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4565 4566 4567 4568 4569
        glDepthMask(GL_TRUE);
        glClearDepth(Z);
        checkGLcall("glClearDepth");
        glMask = glMask | GL_DEPTH_BUFFER_BIT;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4570

4571 4572
        if (vp->X != 0 || vp->Y != 0 ||
                vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4573
            surface_load_ds_location(This->stencilBufferTarget, context, location);
4574 4575 4576 4577 4578
        }
        else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
                This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
                This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
                This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4579
            surface_load_ds_location(This->stencilBufferTarget, context, location);
4580 4581 4582 4583 4584
        }
        else if (Count > 0 && pRects && (
                pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
                pRects[0].x2 < depth_stencil->currentDesc.Width ||
                pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4585
            surface_load_ds_location(This->stencilBufferTarget, context, location);
4586
        }
4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609
    }

    if (Flags & WINED3DCLEAR_TARGET) {
        TRACE("Clearing screen with glClear to color %x\n", Color);
        glClearColor(D3DCOLOR_R(Color),
                     D3DCOLOR_G(Color),
                     D3DCOLOR_B(Color),
                     D3DCOLOR_A(Color));
        checkGLcall("glClearColor");

        /* Clear ALL colors! */
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        glMask = glMask | GL_COLOR_BUFFER_BIT;
    }

    vp_rect.left = vp->X;
    vp_rect.top = vp->Y;
    vp_rect.right = vp->X + vp->Width;
    vp_rect.bottom = vp->Y + vp->Height;
    if (!(Count > 0 && pRects)) {
        if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
            IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
        }
4610 4611
        if (context->render_offscreen)
        {
4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624
            glScissor(vp_rect.left, vp_rect.top,
                        vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
        } else {
            glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
                        vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
        }
        checkGLcall("glScissor");
        glClear(glMask);
        checkGLcall("glClear");
    } else {
        /* Now process each rect in turn */
        for (i = 0; i < Count; i++) {
            /* Note gl uses lower left, width/height */
4625
            IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642
            if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
                IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
            }
            TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
                  pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
                  curRect.x1, (target->currentDesc.Height - curRect.y2),
                  curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);

            /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
             * The rectangle is not cleared, no error is returned, but further rectanlges are
             * still cleared if they are valid
             */
            if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
                TRACE("Rectangle with negative dimensions, ignoring\n");
                continue;
            }

4643 4644
            if (context->render_offscreen)
            {
4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671
                glScissor(curRect.x1, curRect.y1,
                          curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
            } else {
                glScissor(curRect.x1, drawable_height - curRect.y2,
                          curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
            }
            checkGLcall("glScissor");

            glClear(glMask);
            checkGLcall("glClear");
        }
    }

    /* Restore the old values (why..?) */
    if (Flags & WINED3DCLEAR_STENCIL) {
        glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
    }
    if (Flags & WINED3DCLEAR_TARGET) {
        DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
        glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
                    mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
                    mask & WINED3DCOLORWRITEENABLE_BLUE  ? GL_TRUE : GL_FALSE,
                    mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);

        /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
         * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
         */
4672
        IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4673
    }
4674 4675
    if (Flags & WINED3DCLEAR_ZBUFFER) {
        /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4676
        DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4677 4678 4679
        surface_modify_ds_location(This->stencilBufferTarget, location);
    }

4680 4681
    LEAVE_GL();

4682
    if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4683
        if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4684
            wglFlush();
4685 4686 4687 4688
        }
        IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
    }

4689 4690 4691
    return WINED3D_OK;
}

4692
static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4693
                                        DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4694
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695
    IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4696

4697 4698
    TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
          Count, pRects, Flags, Color, Z, Stencil);
4699

4700 4701 4702 4703 4704 4705
    if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
        WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
        /* TODO: What about depth stencil buffers without stencil bits? */
        return WINED3DERR_INVALIDCALL;
    }

4706
    return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4707 4708
}

4709 4710 4711
/*****
 * Drawing functions
 *****/
4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736

static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
        WINED3DPRIMITIVETYPE primitive_type)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));

    This->updateStateBlock->changed.primitive_type = TRUE;
    This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
}

static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
        WINED3DPRIMITIVETYPE *primitive_type)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("iface %p, primitive_type %p\n", iface, primitive_type);

    *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);

    TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
}

static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4737
{
4738 4739
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

4740
    TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4741

4742 4743 4744 4745 4746
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4747 4748 4749 4750 4751 4752
    /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
    if(This->stateBlock->streamIsUP) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
        This->stateBlock->streamIsUP = FALSE;
    }

4753 4754 4755 4756
    if(This->stateBlock->loadBaseVertexIndex != 0) {
        This->stateBlock->loadBaseVertexIndex = 0;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
    }
4757
    /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4758
    drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4759
    return WINED3D_OK;
4760 4761
}

4762
static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4763
{
4764 4765
    IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;
    UINT                 idxStride = 2;
4766
    IWineD3DBuffer *pIB;
4767
    GLuint vbo;
4768

4769 4770 4771 4772 4773 4774
    pIB = This->stateBlock->pIndexData;
    if (!pIB) {
        /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
         * without an index buffer set. (The first time at least...)
         * D3D8 simply dies, but I doubt it can do much harm to return
         * D3DERR_INVALIDCALL there as well. */
4775
        WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4776 4777 4778
        return WINED3DERR_INVALIDCALL;
    }

4779 4780 4781 4782 4783
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4784 4785 4786 4787
    if(This->stateBlock->streamIsUP) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
        This->stateBlock->streamIsUP = FALSE;
    }
4788
    vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4789

4790
    TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4791

4792
    if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4793 4794 4795 4796 4797
        idxStride = 2;
    } else {
        idxStride = 4;
    }

4798 4799 4800 4801 4802
    if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
        This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
    }

4803 4804
    drawPrimitive(iface, index_count, startIndex, idxStride,
            vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4805

4806
    return WINED3D_OK;
4807 4808
}

4809 4810
static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
        const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4811
{
4812
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4813
    IWineD3DBuffer *vb;
4814

4815 4816
    TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
            This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4817

4818 4819 4820 4821 4822
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4823
    /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4824
    vb = This->stateBlock->streamSource[0];
4825 4826
    This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
    if (vb) IWineD3DBuffer_Release(vb);
4827
    This->stateBlock->streamOffset[0] = 0;
4828
    This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4829
    This->stateBlock->streamIsUP = TRUE;
4830
    This->stateBlock->loadBaseVertexIndex = 0;
4831

4832 4833 4834
    /* TODO: Only mark dirty if drawing from a different UP address */
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);

4835
    drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4836 4837

    /* MSDN specifies stream zero settings must be set to NULL */
4838 4839
    This->stateBlock->streamStride[0] = 0;
    This->stateBlock->streamSource[0] = NULL;
4840

4841 4842 4843
    /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
     * the new stream sources or use UP drawing again
     */
4844
    return WINED3D_OK;
4845 4846
}

4847 4848
static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
        UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4849 4850
        const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
{
4851 4852
    int                 idxStride;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853
    IWineD3DBuffer *vb;
4854
    IWineD3DBuffer *ib;
4855

4856 4857
    TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
            This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4858

4859 4860 4861 4862 4863
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4864
    if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4865 4866 4867 4868 4869
        idxStride = 2;
    } else {
        idxStride = 4;
    }

4870
    /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4871
    vb = This->stateBlock->streamSource[0];
4872 4873
    This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
    if (vb) IWineD3DBuffer_Release(vb);
4874
    This->stateBlock->streamIsUP = TRUE;
4875
    This->stateBlock->streamOffset[0] = 0;
4876
    This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4877

4878 4879
    /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
    This->stateBlock->baseVertexIndex = 0;
4880 4881 4882
    This->stateBlock->loadBaseVertexIndex = 0;
    /* Mark the state dirty until we have nicer tracking of the stream source pointers */
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4883
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4884

4885
    drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4886

4887
    /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4888 4889
    This->stateBlock->streamSource[0] = NULL;
    This->stateBlock->streamStride[0] = 0;
4890 4891
    ib = This->stateBlock->pIndexData;
    if(ib) {
4892
        IWineD3DBuffer_Release(ib);
4893 4894
        This->stateBlock->pIndexData = NULL;
    }
4895 4896 4897
    /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
     * SetStreamSource to specify a vertex buffer
     */
4898

4899
    return WINED3D_OK;
4900 4901
}

4902
static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4903
        UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4904
{
4905
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4906

4907 4908 4909 4910
    /* Mark the state dirty until we have nicer tracking
     * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
     * that value.
     */
4911
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4912
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4913
    This->stateBlock->baseVertexIndex = 0;
4914
    This->up_strided = DrawPrimStrideData;
4915
    drawPrimitive(iface, vertex_count, 0, 0, NULL);
4916
    This->up_strided = NULL;
4917 4918
    return WINED3D_OK;
}
4919

4920
static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4921
        UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4922
        UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4923
{
4924
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4925
    DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4926 4927 4928 4929 4930 4931 4932 4933 4934 4935

    /* Mark the state dirty until we have nicer tracking
     * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
     * that value.
     */
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
    This->stateBlock->streamIsUP = TRUE;
    This->stateBlock->baseVertexIndex = 0;
    This->up_strided = DrawPrimStrideData;
4936
    drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4937 4938 4939 4940
    This->up_strided = NULL;
    return WINED3D_OK;
}

4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971
static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
    /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
     * not callable by the app directly no parameter validation checks are needed here.
     */
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    WINED3DLOCKED_BOX src;
    WINED3DLOCKED_BOX dst;
    HRESULT hr;
    TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);

    /* TODO: Implement direct loading into the gl volume instead of using memcpy and
     * dirtification to improve loading performance.
     */
    hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
    if(FAILED(hr)) return hr;
    hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
    if(FAILED(hr)) {
    IWineD3DVolume_UnlockBox(pSourceVolume);
            return hr;
    }

    memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);

    hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
    if(FAILED(hr)) {
        IWineD3DVolume_UnlockBox(pSourceVolume);
    } else {
        hr = IWineD3DVolume_UnlockBox(pSourceVolume);
    }
    return hr;
}
4972

4973 4974 4975 4976 4977 4978
static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
        IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
{
    unsigned int level_count, i;
    WINED3DRESOURCETYPE type;
    HRESULT hr;
4979

4980
    TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4981

4982 4983 4984 4985 4986
    /* Verify that the source and destination textures are non-NULL. */
    if (!src_texture || !dst_texture)
    {
        WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
        return WINED3DERR_INVALIDCALL;
4987
    }
4988

4989 4990 4991 4992
    if (src_texture == dst_texture)
    {
        WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
        return WINED3DERR_INVALIDCALL;
4993 4994
    }

4995 4996 4997 4998 4999 5000
    /* Verify that the source and destination textures are the same type. */
    type = IWineD3DBaseTexture_GetType(src_texture);
    if (IWineD3DBaseTexture_GetType(dst_texture) != type)
    {
        WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
        return WINED3DERR_INVALIDCALL;
5001
    }
5002

5003 5004 5005 5006 5007 5008
    /* Check that both textures have the identical numbers of levels. */
    level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
    if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
    {
        WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
        return WINED3DERR_INVALIDCALL;
5009
    }
5010

5011 5012
    /* Make sure that the destination texture is loaded. */
    ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5013

5014 5015 5016
    /* Update every surface level of the texture. */
    switch (type)
    {
5017
        case WINED3DRTYPE_TEXTURE:
5018 5019 5020 5021 5022
        {
            IWineD3DSurface *src_surface;
            IWineD3DSurface *dst_surface;

            for (i = 0; i < level_count; ++i)
5023
            {
5024 5025 5026 5027 5028 5029 5030 5031 5032
                IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
                IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
                hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
                IWineD3DSurface_Release(dst_surface);
                IWineD3DSurface_Release(src_surface);
                if (FAILED(hr))
                {
                    WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
                    return hr;
5033 5034 5035
                }
            }
            break;
5036 5037
        }

5038
        case WINED3DRTYPE_CUBETEXTURE:
5039 5040 5041 5042 5043 5044
        {
            IWineD3DSurface *src_surface;
            IWineD3DSurface *dst_surface;
            WINED3DCUBEMAP_FACES face;

            for (i = 0; i < level_count; ++i)
5045
            {
5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061
                /* Update each cube face. */
                for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
                {
                    hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
                            face, i, &src_surface);
                    if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
                    hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
                            face, i, &dst_surface);
                    if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
                    hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
                    IWineD3DSurface_Release(dst_surface);
                    IWineD3DSurface_Release(src_surface);
                    if (FAILED(hr))
                    {
                        WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
                        return hr;
5062 5063 5064 5065
                    }
                }
            }
            break;
5066
        }
5067

5068
        case WINED3DRTYPE_VOLUMETEXTURE:
5069 5070 5071 5072 5073
        {
            IWineD3DVolume *src_volume;
            IWineD3DVolume *dst_volume;

            for (i = 0; i < level_count; ++i)
5074
            {
5075 5076 5077 5078 5079 5080 5081 5082 5083
                IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
                IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
                hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
                IWineD3DVolume_Release(dst_volume);
                IWineD3DVolume_Release(src_volume);
                if (FAILED(hr))
                {
                    WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
                    return hr;
5084 5085 5086
                }
            }
            break;
5087
        }
5088

5089
        default:
5090 5091
            FIXME("Unsupported texture type %#x.\n", type);
            return WINED3DERR_INVALIDCALL;
5092 5093
    }

5094
    return WINED3D_OK;
5095
}
5096

5097
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
Oliver Stieber's avatar
Oliver Stieber committed
5098 5099
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
5100
    hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5101
    if(hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
5102
        hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5103
                IWineD3DSwapChain_Release(swapChain);
Oliver Stieber's avatar
Oliver Stieber committed
5104 5105
    }
    return hr;
5106 5107
}

5108
static HRESULT  WINAPI  IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5109
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5110 5111 5112
    IWineD3DBaseTextureImpl *texture;
    DWORD i;

5113
    TRACE("(%p) : %p\n", This, pNumPasses);
5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125

    for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
        if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
            WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
            return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
        }
        if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
            WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
            return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
        }

        texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5126
        if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142

        if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
            WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
            return E_FAIL;
        }
        if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
            WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
            return E_FAIL;
        }
        if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
           This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
            WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
            return E_FAIL;
        }
    }

5143 5144
    /* return a sensible default */
    *pNumPasses = 1;
5145 5146

    TRACE("returning D3D_OK\n");
5147
    return WINED3D_OK;
5148
}
5149

5150 5151 5152 5153
static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
{
    int i;

5154 5155 5156 5157 5158 5159 5160
    for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
    {
        IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
        if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
                || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
        {
            IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5161
        }
5162
    }
5163 5164
}

5165
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5166
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167
    int j;
5168 5169 5170
    UINT NewSize;
    PALETTEENTRY **palettes;

5171
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5172

5173
    if (PaletteNumber >= MAX_PALETTES) {
5174
        ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5175
        return WINED3DERR_INVALIDCALL;
5176
    }
5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199

    if (PaletteNumber >= This->NumberOfPalettes) {
        NewSize = This->NumberOfPalettes;
        do {
           NewSize *= 2;
        } while(PaletteNumber >= NewSize);
        palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
        if (!palettes) {
            ERR("Out of memory!\n");
            return E_OUTOFMEMORY;
        }
        This->palettes = palettes;
        This->NumberOfPalettes = NewSize;
    }

    if (!This->palettes[PaletteNumber]) {
        This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(),  0, sizeof(PALETTEENTRY) * 256);
        if (!This->palettes[PaletteNumber]) {
            ERR("Out of memory!\n");
            return E_OUTOFMEMORY;
        }
    }

5200 5201 5202 5203 5204 5205
    for (j = 0; j < 256; ++j) {
        This->palettes[PaletteNumber][j].peRed   = pEntries[j].peRed;
        This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
        This->palettes[PaletteNumber][j].peBlue  = pEntries[j].peBlue;
        This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
    }
5206
    if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5207
    TRACE("(%p) : returning\n", This);
5208
    return WINED3D_OK;
5209
}
5210

5211
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5212
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5213 5214
    int j;
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5215 5216 5217
    if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
        /* What happens in such situation isn't documented; Native seems to silently abort
           on such conditions. Return Invalid Call. */
5218
        ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5219
        return WINED3DERR_INVALIDCALL;
5220 5221 5222 5223 5224 5225 5226 5227
    }
    for (j = 0; j < 256; ++j) {
        pEntries[j].peRed   = This->palettes[PaletteNumber][j].peRed;
        pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
        pEntries[j].peBlue  = This->palettes[PaletteNumber][j].peBlue;
        pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
    }
    TRACE("(%p) : returning\n", This);
5228
    return WINED3D_OK;
5229
}
5230

5231
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5232
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5233
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5234 5235 5236
    /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
       (tested with reference rasterizer). Return Invalid Call. */
    if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5237
        ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5238
        return WINED3DERR_INVALIDCALL;
5239 5240
    }
    /*TODO: stateblocks */
5241 5242 5243 5244
    if (This->currentPalette != PaletteNumber) {
        This->currentPalette = PaletteNumber;
        dirtify_p8_texture_samplers(This);
    }
5245
    TRACE("(%p) : returning\n", This);
5246
    return WINED3D_OK;
5247
}
5248

5249
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5250
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5251 5252
    if (PaletteNumber == NULL) {
        WARN("(%p) : returning Invalid Call\n", This);
5253
        return WINED3DERR_INVALIDCALL;
5254 5255 5256 5257
    }
    /*TODO: stateblocks */
    *PaletteNumber = This->currentPalette;
    TRACE("(%p) : returning  %u\n", This, *PaletteNumber);
5258
    return WINED3D_OK;
5259
}
5260

5261
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5262
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5263 5264 5265
    static BOOL warned;
    if (!warned)
    {
5266
        FIXME("(%p) : stub\n", This);
5267
        warned = TRUE;
5268 5269
    }

5270
    This->softwareVertexProcessing = bSoftware;
5271
    return WINED3D_OK;
5272 5273 5274
}


5275
static BOOL     WINAPI  IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5276
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5277 5278 5279
    static BOOL warned;
    if (!warned)
    {
5280
        FIXME("(%p) : stub\n", This);
5281
        warned = TRUE;
5282
    }
5283
    return This->softwareVertexProcessing;
5284 5285 5286
}


5287
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5288
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 5290
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
5291

5292 5293
    TRACE("(%p) :  SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);

5294
    hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5295
    if(hr == WINED3D_OK){
5296
        hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5297
        IWineD3DSwapChain_Release(swapChain);
5298
    }else{
5299
        FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5300 5301
    }
    return hr;
5302 5303 5304
}


5305
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5306
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5307
    static BOOL warned;
5308
    if(nSegments != 0.0f) {
5309 5310
        if (!warned)
        {
5311
            FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5312
            warned = TRUE;
5313
        }
5314
    }
5315
    return WINED3D_OK;
5316
}
5317

5318
static float    WINAPI  IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5319
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5320 5321 5322
    static BOOL warned;
    if (!warned)
    {
5323
        FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5324
        warned = TRUE;
5325 5326 5327
    }
    return 0.0f;
}
5328

5329
static HRESULT  WINAPI  IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5330 5331 5332 5333 5334
    IWineD3DDeviceImpl  *This         = (IWineD3DDeviceImpl *) iface;
    /** TODO: remove casts to IWineD3DSurfaceImpl
     *       NOTE: move code to surface to accomplish this
      ****************************************/
    IWineD3DSurfaceImpl *pSrcSurface  = (IWineD3DSurfaceImpl *)pSourceSurface;
5335
    IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
Mike McCormack's avatar
Mike McCormack committed
5336
    int srcWidth, srcHeight;
5337
    unsigned int  srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5338
    WINED3DFORMAT destFormat, srcFormat;
5339
    UINT          destSize;
5340
    int srcLeft, destLeft, destTop;
5341
    WINED3DPOOL       srcPool, destPool;
5342 5343
    int offset    = 0;
    int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5344
    const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5345
    GLenum dummy;
5346
    DWORD sampler;
5347 5348
    int bpp;
    CONVERT_TYPES convert = NO_CONVERSION;
5349 5350 5351

    WINED3DSURFACE_DESC  winedesc;

5352
    TRACE("(%p) : Source (%p)  Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5353 5354

    IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5355 5356 5357 5358
    srcSurfaceWidth = winedesc.width;
    srcSurfaceHeight = winedesc.height;
    srcPool = winedesc.pool;
    srcFormat = winedesc.format;
5359 5360

    IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5361 5362 5363 5364 5365
    destSurfaceWidth = winedesc.width;
    destSurfaceHeight = winedesc.height;
    destPool = winedesc.pool;
    destFormat = winedesc.format;
    destSize = winedesc.size;
5366

5367
    if(srcPool != WINED3DPOOL_SYSTEMMEM  || destPool != WINED3DPOOL_DEFAULT){
5368 5369
        WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
        return WINED3DERR_INVALIDCALL;
5370
    }
5371

5372 5373 5374 5375
    /* This call loads the opengl surface directly, instead of copying the surface to the
     * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
     * copy in sysmem and use regular surface loading.
     */
5376
    d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5377 5378 5379 5380
    if(convert != NO_CONVERSION) {
        return IWineD3DSurface_BltFast(pDestinationSurface,
                                        pDestPoint  ? pDestPoint->x : 0,
                                        pDestPoint  ? pDestPoint->y : 0,
5381
                                        pSourceSurface, pSourceRect, 0);
5382 5383
    }

5384 5385 5386 5387 5388 5389 5390 5391
    if (destFormat == WINED3DFMT_UNKNOWN) {
        TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
        IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);

        /* Get the update surface description */
        IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
    }

5392
    ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5393

5394 5395 5396 5397
    ENTER_GL();
    GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
    checkGLcall("glActiveTextureARB");
    LEAVE_GL();
5398

5399
    /* Make sure the surface is loaded and up to date */
5400
    surface_internal_preload(pDestinationSurface, SRGB_RGB);
5401
    IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5402

5403
    src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5404
    dst_format_desc = dst_impl->resource.format_desc;
5405

5406 5407
    /* this needs to be done in lines if the sourceRect != the sourceWidth */
    srcWidth   = pSourceRect ? pSourceRect->right - pSourceRect->left   : srcSurfaceWidth;
5408
    srcHeight  = pSourceRect ? pSourceRect->bottom - pSourceRect->top   : srcSurfaceHeight;
5409
    srcLeft    = pSourceRect ? pSourceRect->left : 0;
5410 5411 5412 5413 5414 5415
    destLeft   = pDestPoint  ? pDestPoint->x : 0;
    destTop    = pDestPoint  ? pDestPoint->y : 0;


    /* This function doesn't support compressed textures
    the pitch is just bytesPerPixel * width */
5416
    if(srcWidth != srcSurfaceWidth  || srcLeft ){
5417 5418
        rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
        offset   += srcLeft * src_format_desc->byte_count;
5419 5420 5421 5422 5423
        /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
    }
    /* TODO DXT formats */

    if(pSourceRect != NULL && pSourceRect->top != 0){
5424
       offset +=  pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5425
    }
5426
    TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5427
            This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5428
            dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5429 5430 5431

    /* Sanity check */
    if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5432 5433 5434

        /* need to lock the surface to get the data */
        FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5435
    }
5436

5437 5438
    ENTER_GL();

5439 5440 5441 5442
    /* TODO: Cube and volume support */
    if(rowoffset != 0){
        /* not a whole row so we have to do it a line at a time */
        int j;
5443

5444
        /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5445
        const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5446

5447 5448
        for (j = destTop; j < (srcHeight + destTop); ++j)
        {
5449
            glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5450
                    srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5451 5452 5453 5454
            data += rowoffset;
        }

    } else { /* Full width, so just write out the whole texture */
5455
        const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5456

5457 5458
        if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
        {
5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469
            if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
            {
                /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
                FIXME("Updating part of a compressed texture is not supported.\n");
            }
            if (destFormat != srcFormat)
            {
                FIXME("Updating mixed format compressed textures is not supported.\n");
            }
            else
            {
5470
                GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5471 5472 5473 5474 5475
                        dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
            }
        }
        else
        {
5476
            glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5477
                    srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5478 5479 5480 5481 5482 5483
        }
     }
    checkGLcall("glTexSubImage2D");

    LEAVE_GL();

5484
    IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5485
    sampler = This->rev_tex_unit_map[0];
5486 5487
    if (sampler != WINED3D_UNMAPPED_STAGE)
    {
5488 5489
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
    }
5490

5491
    return WINED3D_OK;
5492 5493
}

5494
static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5495
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5496
    struct WineD3DRectPatch *patch;
5497
    GLenum old_primitive_type;
5498 5499 5500
    unsigned int i;
    struct list *e;
    BOOL found;
5501
    TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5502

5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546
    if(!(Handle || pRectPatchInfo)) {
        /* TODO: Write a test for the return value, thus the FIXME */
        FIXME("Both Handle and pRectPatchInfo are NULL\n");
        return WINED3DERR_INVALIDCALL;
    }

    if(Handle) {
        i = PATCHMAP_HASHFUNC(Handle);
        found = FALSE;
        LIST_FOR_EACH(e, &This->patches[i]) {
            patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
            if(patch->Handle == Handle) {
                found = TRUE;
                break;
            }
        }

        if(!found) {
            TRACE("Patch does not exist. Creating a new one\n");
            patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
            patch->Handle = Handle;
            list_add_head(&This->patches[i], &patch->entry);
        } else {
            TRACE("Found existing patch %p\n", patch);
        }
    } else {
        /* Since opengl does not load tesselated vertex attributes into numbered vertex
         * attributes we have to tesselate, read back, and draw. This needs a patch
         * management structure instance. Create one.
         *
         * A possible improvement is to check if a vertex shader is used, and if not directly
         * draw the patch.
         */
        FIXME("Drawing an uncached patch. This is slow\n");
        patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
    }

    if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
       pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
       (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
        HRESULT hr;
        TRACE("Tesselation density or patch info changed, retesselating\n");

        if(pRectPatchInfo) {
5547
            patch->RectPatchInfo = *pRectPatchInfo;
5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566
        }
        patch->numSegs[0] = pNumSegs[0];
        patch->numSegs[1] = pNumSegs[1];
        patch->numSegs[2] = pNumSegs[2];
        patch->numSegs[3] = pNumSegs[3];

        hr = tesselate_rectpatch(This, patch);
        if(FAILED(hr)) {
            WARN("Patch tesselation failed\n");

            /* Do not release the handle to store the params of the patch */
            if(!Handle) {
                HeapFree(GetProcessHeap(), 0, patch);
            }
            return hr;
        }
    }

    This->currentPatch = patch;
5567 5568
    old_primitive_type = This->stateBlock->gl_primitive_type;
    This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5569
    IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5570
    This->stateBlock->gl_primitive_type = old_primitive_type;
5571 5572 5573 5574 5575 5576 5577 5578
    This->currentPatch = NULL;

    /* Destroy uncached patches */
    if(!Handle) {
        HeapFree(GetProcessHeap(), 0, patch->mem);
        HeapFree(GetProcessHeap(), 0, patch);
    }
    return WINED3D_OK;
5579 5580
}

5581
static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5582
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583
    TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5584
    FIXME("(%p) : Stub\n", This);
5585
    return WINED3D_OK;
5586
}
5587

5588
static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5589
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5590 5591 5592
    int i;
    struct WineD3DRectPatch *patch;
    struct list *e;
5593
    TRACE("(%p) Handle(%d)\n", This, Handle);
5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607

    i = PATCHMAP_HASHFUNC(Handle);
    LIST_FOR_EACH(e, &This->patches[i]) {
        patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
        if(patch->Handle == Handle) {
            TRACE("Deleting patch %p\n", patch);
            list_remove(&patch->entry);
            HeapFree(GetProcessHeap(), 0, patch->mem);
            HeapFree(GetProcessHeap(), 0, patch);
            return WINED3D_OK;
        }
    }

    /* TODO: Write a test for the return value */
5608
    FIXME("Attempt to destroy nonexistent patch\n");
5609
    return WINED3DERR_INVALIDCALL;
5610
}
5611

5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624
static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
    HRESULT hr;
    IWineD3DSwapChain *swapchain;

    hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
    if (SUCCEEDED(hr)) {
        IWineD3DSwapChain_Release((IUnknown *)swapchain);
        return swapchain;
    }

    return NULL;
}

5625 5626 5627
static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
        const WINED3DRECT *rect, const float color[4])
{
5628
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5629
    struct wined3d_context *context;
5630 5631 5632 5633 5634 5635 5636 5637
    IWineD3DSwapChain *swapchain;

    swapchain = get_swapchain(surface);
    if (swapchain) {
        GLenum buffer;

        TRACE("Surface %p is onscreen\n", surface);

5638
        context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5639
        ENTER_GL();
5640
        context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5641 5642 5643 5644 5645
        buffer = surface_get_gl_buffer(surface, swapchain);
        glDrawBuffer(buffer);
        checkGLcall("glDrawBuffer()");
    } else {
        TRACE("Surface %p is offscreen\n", surface);
5646

5647
        context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5648
        ENTER_GL();
5649 5650 5651
        context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
        context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
        context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662
    }

    if (rect) {
        glEnable(GL_SCISSOR_TEST);
        if(!swapchain) {
            glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
        } else {
            glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
                    rect->x2 - rect->x1, rect->y2 - rect->y1);
        }
        checkGLcall("glScissor");
5663
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5664 5665 5666
    } else {
        glDisable(GL_SCISSOR_TEST);
    }
5667 5668 5669 5670
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));

    glDisable(GL_BLEND);
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5671 5672 5673 5674

    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));

5675
    glClearColor(color[0], color[1], color[2], color[3]);
5676 5677 5678 5679 5680 5681 5682 5683
    glClear(GL_COLOR_BUFFER_BIT);
    checkGLcall("glClear");

    if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
            && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
        glDrawBuffer(GL_BACK);
        checkGLcall("glDrawBuffer()");
    }
5684 5685

    LEAVE_GL();
5686 5687
}

5688 5689 5690 5691
static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
    unsigned int r, g, b, a;
    DWORD ret;

5692 5693 5694
    if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
            || destfmt == WINED3DFMT_B8G8R8X8_UNORM
            || destfmt == WINED3DFMT_B8G8R8_UNORM)
5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705
        return color;

    TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));

    a = (color & 0xff000000) >> 24;
    r = (color & 0x00ff0000) >> 16;
    g = (color & 0x0000ff00) >>  8;
    b = (color & 0x000000ff) >>  0;

    switch(destfmt)
    {
5706
        case WINED3DFMT_B5G6R5_UNORM:
5707 5708 5709 5710 5711 5712 5713 5714 5715 5716
            if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
            r = (r * 32) / 256;
            g = (g * 64) / 256;
            b = (b * 32) / 256;
            ret  = r << 11;
            ret |= g << 5;
            ret |= b;
            TRACE("Returning %08x\n", ret);
            return ret;

5717 5718
        case WINED3DFMT_B5G5R5X1_UNORM:
        case WINED3DFMT_B5G5R5A1_UNORM:
5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729
            a = (a *  2) / 256;
            r = (r * 32) / 256;
            g = (g * 32) / 256;
            b = (b * 32) / 256;
            ret  = a << 15;
            ret |= r << 10;
            ret |= g <<  5;
            ret |= b <<  0;
            TRACE("Returning %08x\n", ret);
            return ret;

5730
        case WINED3DFMT_A8_UNORM:
5731 5732 5733
            TRACE("Returning %08x\n", a);
            return a;

5734 5735
        case WINED3DFMT_B4G4R4X4_UNORM:
        case WINED3DFMT_B4G4R4A4_UNORM:
5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746
            a = (a * 16) / 256;
            r = (r * 16) / 256;
            g = (g * 16) / 256;
            b = (b * 16) / 256;
            ret  = a << 12;
            ret |= r <<  8;
            ret |= g <<  4;
            ret |= b <<  0;
            TRACE("Returning %08x\n", ret);
            return ret;

5747
        case WINED3DFMT_B2G3R3_UNORM:
5748 5749 5750 5751 5752 5753 5754 5755 5756
            r = (r * 8) / 256;
            g = (g * 8) / 256;
            b = (b * 4) / 256;
            ret  = r <<  5;
            ret |= g <<  2;
            ret |= b <<  0;
            TRACE("Returning %08x\n", ret);
            return ret;

5757
        case WINED3DFMT_R8G8B8X8_UNORM:
5758
        case WINED3DFMT_R8G8B8A8_UNORM:
5759 5760 5761 5762 5763 5764 5765
            ret  = a << 24;
            ret |= b << 16;
            ret |= g <<  8;
            ret |= r <<  0;
            TRACE("Returning %08x\n", ret);
            return ret;

5766
        case WINED3DFMT_B10G10R10A2_UNORM:
5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777
            a = (a *    4) / 256;
            r = (r * 1024) / 256;
            g = (g * 1024) / 256;
            b = (b * 1024) / 256;
            ret  = a << 30;
            ret |= r << 20;
            ret |= g << 10;
            ret |= b <<  0;
            TRACE("Returning %08x\n", ret);
            return ret;

5778
        case WINED3DFMT_R10G10B10A2_UNORM:
5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795
            a = (a *    4) / 256;
            r = (r * 1024) / 256;
            g = (g * 1024) / 256;
            b = (b * 1024) / 256;
            ret  = a << 30;
            ret |= b << 20;
            ret |= g << 10;
            ret |= r <<  0;
            TRACE("Returning %08x\n", ret);
            return ret;

        default:
            FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
            return 0;
    }
}

5796
static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5797 5798
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5799
    WINEDDBLTFX BltFx;
5800
    TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5801

5802 5803
    if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
        FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5804
        return WINED3DERR_INVALIDCALL;
5805
    }
5806

5807
    if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5808 5809
        const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
        color_fill_fbo(iface, pSurface, pRect, c);
5810
        return WINED3D_OK;
5811 5812 5813 5814
    } else {
        /* Just forward this to the DirectDraw blitting engine */
        memset(&BltFx, 0, sizeof(BltFx));
        BltFx.dwSize = sizeof(BltFx);
5815
        BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5816
        return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5817
                WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5818
    }
5819 5820
}

5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854
static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
        IWineD3DRendertargetView *rendertarget_view, const float color[4])
{
    IWineD3DResource *resource;
    IWineD3DSurface *surface;
    HRESULT hr;

    hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
    if (FAILED(hr))
    {
        ERR("Failed to get resource, hr %#x\n", hr);
        return;
    }

    if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
    {
        FIXME("Only supported on surface resources\n");
        IWineD3DResource_Release(resource);
        return;
    }

    surface = (IWineD3DSurface *)resource;

    if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
    {
        color_fill_fbo(iface, surface, NULL, color);
    }
    else
    {
        WINEDDBLTFX BltFx;
        WINED3DCOLOR c;

        WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");

5855 5856 5857 5858
        c = ((DWORD)(color[2] * 255.0f));
        c |= ((DWORD)(color[1] * 255.0f)) << 8;
        c |= ((DWORD)(color[0] * 255.0f)) << 16;
        c |= ((DWORD)(color[3] * 255.0f)) << 24;
5859 5860 5861 5862

        /* Just forward this to the DirectDraw blitting engine */
        memset(&BltFx, 0, sizeof(BltFx));
        BltFx.dwSize = sizeof(BltFx);
5863
        BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5864
        hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5865 5866 5867 5868 5869 5870 5871 5872 5873
        if (FAILED(hr))
        {
            ERR("Blt failed, hr %#x\n", hr);
        }
    }

    IWineD3DResource_Release(resource);
}

5874
/* rendertarget and depth stencil functions */
5875
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5876
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5877

5878 5879 5880 5881
    if (RenderTargetIndex >= This->adapter->gl_info.max_buffers)
    {
        ERR("(%p) : Only %d render targets are supported.\n",
                This, This->adapter->gl_info.max_buffers);
5882 5883
        return WINED3DERR_INVALIDCALL;
    }
5884

5885
    *ppRenderTarget = This->render_targets[RenderTargetIndex];
5886
    TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5887 5888 5889
    /* Note inc ref on returned surface */
    if(*ppRenderTarget != NULL)
        IWineD3DSurface_AddRef(*ppRenderTarget);
5890
    return WINED3D_OK;
5891
}
5892

5893
static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
    IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
    IWineD3DSwapChainImpl *Swapchain;
    HRESULT hr;

    TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);

    hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
    if(hr != WINED3D_OK) {
        ERR("Can't get the swapchain\n");
        return hr;
    }

5908 5909 5910
    /* Make sure to release the swapchain */
    IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);

5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923
    if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
        ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
        return WINED3DERR_INVALIDCALL;
    }
    else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
        ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
        return WINED3DERR_INVALIDCALL;
    }

    if(Swapchain->frontBuffer != Front) {
        TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);

        if(Swapchain->frontBuffer)
5924
        {
5925
            IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5926 5927
            ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
        }
5928 5929 5930 5931
        Swapchain->frontBuffer = Front;

        if(Swapchain->frontBuffer) {
            IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5932
            ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5933 5934
        }
    }
5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945

    if(Back && !Swapchain->backBuffer) {
        /* We need memory for the back buffer array - only one back buffer this way */
        Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
        if(!Swapchain->backBuffer) {
            ERR("Out of memory\n");
            return E_OUTOFMEMORY;
        }
    }

    if(Swapchain->backBuffer[0] != Back) {
5946
        TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5947 5948 5949 5950

        /* What to do about the context here in the case of multithreading? Not sure.
         * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
         */
5951 5952
        WARN("No active context?\n");

5953
        ENTER_GL();
5954
        if(!Swapchain->backBuffer[0]) {
5955 5956 5957 5958 5959
            /* GL was told to draw to the front buffer at creation,
             * undo that
             */
            glDrawBuffer(GL_BACK);
            checkGLcall("glDrawBuffer(GL_BACK)");
5960 5961
            /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
            Swapchain->presentParms.BackBufferCount = 1;
5962 5963 5964 5965
        } else if (!Back) {
            /* That makes problems - disable for now */
            /* glDrawBuffer(GL_FRONT); */
            checkGLcall("glDrawBuffer(GL_FRONT)");
5966 5967
            /* We have lost our back buffer, set this to 0 to avoid confusing other code */
            Swapchain->presentParms.BackBufferCount = 0;
5968 5969 5970
        }
        LEAVE_GL();

5971
        if(Swapchain->backBuffer[0])
5972
        {
5973
            IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5974 5975
            ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
        }
5976
        Swapchain->backBuffer[0] = Back;
5977

5978 5979
        if(Swapchain->backBuffer[0]) {
            IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5980
            ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5981 5982
        } else {
            HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5983
            Swapchain->backBuffer = NULL;
5984 5985 5986 5987 5988
        }

    }

    return WINED3D_OK;
5989 5990
}

5991
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5992
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5993
    *ppZStencilSurface = This->stencilBufferTarget;
5994
    TRACE("(%p) : zStencilSurface  returning %p\n", This,  *ppZStencilSurface);
5995

5996 5997 5998
    if(*ppZStencilSurface != NULL) {
        /* Note inc ref on returned surface */
        IWineD3DSurface_AddRef(*ppZStencilSurface);
5999 6000 6001
        return WINED3D_OK;
    } else {
        return WINED3DERR_NOTFOUND;
6002
    }
6003 6004
}

6005
void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6006 6007
        IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
{
6008 6009
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6010
    IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6011
    const struct wined3d_gl_info *gl_info;
6012
    struct wined3d_context *context;
6013
    GLenum gl_filter;
6014
    POINT offset = {0, 0};
6015

6016 6017 6018 6019
    TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
            This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
    TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
    TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034

    switch (filter) {
        case WINED3DTEXF_LINEAR:
            gl_filter = GL_LINEAR;
            break;

        default:
            FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
        case WINED3DTEXF_NONE:
        case WINED3DTEXF_POINT:
            gl_filter = GL_NEAREST;
            break;
    }

    /* Attach src surface to src fbo */
6035
    src_swapchain = get_swapchain(src_surface);
6036 6037
    dst_swapchain = get_swapchain(dst_surface);

6038 6039 6040
    if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
    else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
    else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6041

6042 6043
    gl_info = context->gl_info;

6044
    if (src_swapchain) {
6045
        GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6046

6047
        TRACE("Source surface %p is onscreen\n", src_surface);
6048 6049 6050
        /* Make sure the drawable is up to date. In the offscreen case
         * attach_surface_fbo() implicitly takes care of this. */
        IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6051

6052 6053 6054
        if(buffer == GL_FRONT) {
            RECT windowsize;
            UINT h;
6055 6056
            ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
            GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6057 6058 6059 6060 6061 6062 6063 6064 6065
            h = windowsize.bottom - windowsize.top;
            src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
            src_rect->y1 =  offset.y + h - src_rect->y1;
            src_rect->y2 =  offset.y + h - src_rect->y2;
        } else {
            src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
            src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
        }

6066
        ENTER_GL();
6067
        context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6068 6069
        glReadBuffer(buffer);
        checkGLcall("glReadBuffer()");
6070
    } else {
6071
        TRACE("Source surface %p is offscreen\n", src_surface);
6072
        ENTER_GL();
6073 6074 6075
        context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
        context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
        glReadBuffer(GL_COLOR_ATTACHMENT0);
6076
        checkGLcall("glReadBuffer()");
6077
        context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6078
    }
6079
    LEAVE_GL();
6080 6081

    /* Attach dst surface to dst fbo */
6082
    if (dst_swapchain) {
6083
        GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6084

6085
        TRACE("Destination surface %p is onscreen\n", dst_surface);
6086 6087 6088
        /* Make sure the drawable is up to date. In the offscreen case
         * attach_surface_fbo() implicitly takes care of this. */
        IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6089

6090 6091 6092
        if(buffer == GL_FRONT) {
            RECT windowsize;
            UINT h;
6093 6094
            ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
            GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6095 6096 6097 6098 6099 6100 6101 6102 6103 6104
            h = windowsize.bottom - windowsize.top;
            dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
            dst_rect->y1 =  offset.y + h - dst_rect->y1;
            dst_rect->y2 =  offset.y + h - dst_rect->y2;
        } else {
            /* Screen coords = window coords, surface height = window height */
            dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
            dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
        }

6105
        ENTER_GL();
6106
        context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6107 6108
        glDrawBuffer(buffer);
        checkGLcall("glDrawBuffer()");
6109
    } else {
6110
        TRACE("Destination surface %p is offscreen\n", dst_surface);
6111

6112
        ENTER_GL();
6113 6114 6115
        context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
        context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
        glDrawBuffer(GL_COLOR_ATTACHMENT0);
6116
        checkGLcall("glDrawBuffer()");
6117
        context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6118
    }
6119 6120
    glDisable(GL_SCISSOR_TEST);
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6121 6122

    if (flip) {
6123 6124
        gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
                dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6125
        checkGLcall("glBlitFramebuffer()");
6126
    } else {
6127 6128
        gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
                dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6129
        checkGLcall("glBlitFramebuffer()");
6130 6131
    }

6132 6133
    IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);

6134 6135 6136 6137 6138
    /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
    if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
            && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
        glDrawBuffer(GL_BACK);
        checkGLcall("glDrawBuffer()");
6139
    }
6140
    LEAVE_GL();
6141 6142
}

6143
static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6144
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6145
    int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
6146

6147 6148
    TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);

6149 6150
    if (RenderTargetIndex >= This->adapter->gl_info.max_buffers)
    {
6151
        WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6152
             This, RenderTargetIndex, This->adapter->gl_info.max_buffers);
6153
        return WINED3DERR_INVALIDCALL;
6154 6155 6156
    }

    /* MSDN says that null disables the render target
6157
    but a device must always be associated with a render target
6158 6159 6160 6161
    nope MSDN says that we return invalid call to a null rendertarget with an index of 0
    */
    if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
        FIXME("Trying to set render target 0 to NULL\n");
6162
        return WINED3DERR_INVALIDCALL;
6163
    }
6164
    if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6165
        FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
6166
        return WINED3DERR_INVALIDCALL;
6167
    }
6168

6169
    /* If we are trying to set what we already have, don't bother */
6170
    if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6171
        TRACE("Trying to do a NOP SetRenderTarget operation\n");
6172
        return WINED3D_OK;
6173
    }
6174 6175 6176
    if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
    if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
    This->render_targets[RenderTargetIndex] = pRenderTarget;
6177

6178
    /* Render target 0 is special */
6179
    if(RenderTargetIndex == 0 && dxVersion > 7) {
6180 6181 6182
        /* Finally, reset the viewport and scissor rect as the MSDN states.
         * Tests show that stateblock recording is ignored, the change goes
         * directly into the primary stateblock.
6183 6184 6185 6186 6187 6188 6189 6190
         */
        This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
        This->stateBlock->viewport.Width  = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
        This->stateBlock->viewport.X      = 0;
        This->stateBlock->viewport.Y      = 0;
        This->stateBlock->viewport.MaxZ   = 1.0f;
        This->stateBlock->viewport.MinZ   = 0.0f;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6191 6192 6193 6194 6195 6196

        This->stateBlock->scissorRect.top = 0;
        This->stateBlock->scissorRect.left = 0;
        This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
        This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6197
    }
6198
    return WINED3D_OK;
6199 6200
}

6201
static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6202
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6203
    HRESULT  hr = WINED3D_OK;
6204 6205
    IWineD3DSurface *tmp;

6206
    TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6207

6208
    if (pNewZStencil == This->stencilBufferTarget) {
6209
        TRACE("Trying to do a NOP SetRenderTarget operation\n");
6210
    } else {
6211
        /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6212
        * depending on the renter target implementation being used.
6213
        * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6214
        * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6215
        * stencil buffer and incur an extra memory overhead
6216 6217
         ******************************************************/

6218
        if (This->stencilBufferTarget) {
6219 6220 6221 6222
            if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
                    || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
                surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
            } else {
6223
                struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6224
                surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6225 6226
                surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
            }
6227 6228
        }

6229 6230 6231 6232 6233
        tmp = This->stencilBufferTarget;
        This->stencilBufferTarget = pNewZStencil;
        /* should we be calling the parent or the wined3d surface? */
        if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
        if (NULL != tmp) IWineD3DSurface_Release(tmp);
6234
        hr = WINED3D_OK;
6235

6236 6237 6238 6239 6240 6241
        if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
            /* Swapping NULL / non NULL depth stencil affects the depth and tests */
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
        }
6242 6243 6244 6245 6246
    }

    return hr;
}

6247
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6248
                                                        UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6249
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6250
    /* TODO: the use of Impl is deprecated. */
6251
    IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6252
    WINED3DLOCKED_RECT lockedRect;
6253 6254 6255

    TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);

6256
    /* some basic validation checks */
6257
    if(This->cursorTexture) {
6258
        ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6259
        ENTER_GL();
6260 6261 6262 6263 6264
        glDeleteTextures(1, &This->cursorTexture);
        LEAVE_GL();
        This->cursorTexture = 0;
    }

6265 6266 6267 6268 6269
    if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
        This->haveHardwareCursor = TRUE;
    else
        This->haveHardwareCursor = FALSE;

6270
    if(pCursorBitmap) {
6271 6272
        WINED3DLOCKED_RECT rect;

6273
        /* MSDN: Cursor must be A8R8G8B8 */
6274
        if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6275
        {
6276 6277 6278 6279 6280 6281 6282
            ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
            return WINED3DERR_INVALIDCALL;
        }

        /* MSDN: Cursor must be smaller than the display mode */
        if(pSur->currentDesc.Width > This->ddraw_width ||
           pSur->currentDesc.Height > This->ddraw_height) {
6283
            ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
6284 6285 6286
            return WINED3DERR_INVALIDCALL;
        }

6287 6288
        if (!This->haveHardwareCursor) {
            /* TODO: MSDN: Cursor sizes must be a power of 2 */
6289

6290 6291 6292 6293 6294 6295 6296 6297 6298 6299
            /* Do not store the surface's pointer because the application may
             * release it after setting the cursor image. Windows doesn't
             * addref the set surface, so we can't do this either without
             * creating circular refcount dependencies. Copy out the gl texture
             * instead.
             */
            This->cursorWidth = pSur->currentDesc.Width;
            This->cursorHeight = pSur->currentDesc.Height;
            if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
            {
6300
                const struct GlPixelFormatDesc *glDesc =
6301
                        getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, &This->adapter->gl_info);
6302
                char *mem, *bits = rect.pBits;
6303 6304 6305
                GLint intfmt = glDesc->glInternal;
                GLint format = glDesc->glFormat;
                GLint type = glDesc->glType;
6306 6307
                INT height = This->cursorHeight;
                INT width = This->cursorWidth;
6308
                INT bpp = glDesc->byte_count;
6309 6310
                DWORD sampler;
                INT i;
6311 6312 6313 6314 6315 6316 6317

                /* Reformat the texture memory (pitch and width can be
                 * different) */
                mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
                for(i = 0; i < height; i++)
                    memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
                IWineD3DSurface_UnlockRect(pCursorBitmap);
6318

6319
                ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6320

6321 6322 6323 6324 6325 6326
                ENTER_GL();

                if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
                    glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
                    checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
                }
6327

6328
                /* Make sure that a proper texture unit is selected */
6329 6330
                GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
                checkGLcall("glActiveTextureARB");
6331
                sampler = This->rev_tex_unit_map[0];
6332 6333
                if (sampler != WINED3D_UNMAPPED_STAGE)
                {
6334 6335
                    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
                }
6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349
                /* Create a new cursor texture */
                glGenTextures(1, &This->cursorTexture);
                checkGLcall("glGenTextures");
                glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
                checkGLcall("glBindTexture");
                /* Copy the bitmap memory into the cursor texture */
                glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
                HeapFree(GetProcessHeap(), 0, mem);
                checkGLcall("glTexImage2D");

                if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
                    glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
                    checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
                }
6350

6351
                LEAVE_GL();
6352
            }
6353 6354 6355 6356
            else
            {
                FIXME("A cursor texture was not returned.\n");
                This->cursorTexture = 0;
6357
            }
6358 6359 6360
        }
        else
        {
6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378
            /* Draw a hardware cursor */
            ICONINFO cursorInfo;
            HCURSOR cursor;
            /* Create and clear maskBits because it is not needed for
             * 32-bit cursors.  32x32 bits split into 32-bit chunks == 32
             * chunks. */
            DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
            IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
                                         WINED3DLOCK_NO_DIRTY_UPDATE |
                                         WINED3DLOCK_READONLY
            );
            TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
                  pSur->currentDesc.Height);

            cursorInfo.fIcon = FALSE;
            cursorInfo.xHotspot = XHotSpot;
            cursorInfo.yHotspot = YHotSpot;
6379 6380 6381 6382
            cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
                    1, 1, maskBits);
            cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
                    1, 32, lockedRect.pBits);
6383 6384 6385 6386 6387 6388 6389 6390 6391
            IWineD3DSurface_UnlockRect(pCursorBitmap);
            /* Create our cursor and clean up. */
            cursor = CreateIconIndirect(&cursorInfo);
            SetCursor(cursor);
            if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
            if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
            if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
            This->hardwareCursor = cursor;
            HeapFree(GetProcessHeap(), 0, maskBits);
6392
        }
6393
    }
6394

6395 6396
    This->xHotSpot = XHotSpot;
    This->yHotSpot = YHotSpot;
6397
    return WINED3D_OK;
6398 6399
}

6400
static void     WINAPI  IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6401 6402
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6403

6404 6405
    This->xScreenSpace = XScreenSpace;
    This->yScreenSpace = YScreenSpace;
6406

6407 6408 6409 6410
    return;

}

6411
static BOOL     WINAPI  IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6412
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6413
    BOOL oldVisible = This->bCursorVisible;
6414 6415
    POINT pt;

6416
    TRACE("(%p) : visible(%d)\n", This, bShow);
6417

6418 6419 6420 6421 6422 6423 6424 6425
    /*
     * When ShowCursor is first called it should make the cursor appear at the OS's last
     * known cursor position.  Because of this, some applications just repetitively call
     * ShowCursor in order to update the cursor's position.  This behavior is undocumented.
     */
    GetCursorPos(&pt);
    This->xScreenSpace = pt.x;
    This->yScreenSpace = pt.y;
6426

6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439
    if (This->haveHardwareCursor) {
        This->bCursorVisible = bShow;
        if (bShow)
            SetCursor(This->hardwareCursor);
        else
            SetCursor(NULL);
    }
    else
    {
        if (This->cursorTexture)
            This->bCursorVisible = bShow;
    }

6440
    return oldVisible;
6441 6442
}

6443
static HRESULT  WINAPI  IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6444
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6445
    IWineD3DResourceImpl *resource;
6446
    TRACE("(%p) : state (%u)\n", This, This->state);
6447

Austin English's avatar
Austin English committed
6448
    /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6449
    switch (This->state) {
6450 6451 6452
    case WINED3D_OK:
        return WINED3D_OK;
    case WINED3DERR_DEVICELOST:
6453
        {
6454 6455 6456
            LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
                if (resource->resource.pool == WINED3DPOOL_DEFAULT)
                    return WINED3DERR_DEVICENOTRESET;
6457
            }
6458
            return WINED3DERR_DEVICELOST;
6459
        }
6460 6461
    case WINED3DERR_DRIVERINTERNALERROR:
        return WINED3DERR_DRIVERINTERNALERROR;
6462 6463 6464
    }

    /* Unknown state */
6465
    return WINED3DERR_DRIVERINTERNALERROR;
6466 6467
}

6468 6469 6470 6471 6472 6473 6474 6475 6476
static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
    TRACE("checking resource %p for eviction\n", resource);
    if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
        TRACE("Evicting %p\n", resource);
        IWineD3DResource_UnLoad(resource);
    }
    IWineD3DResource_Release(resource);
    return S_OK;
}
6477

6478
static HRESULT  WINAPI  IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6479
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6480 6481 6482
    TRACE("(%p)\n", This);

    IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6483
    return WINED3D_OK;
6484 6485
}

6486 6487
static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
{
6488 6489
    IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */

6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500
    /* Reallocate proper memory for the front and back buffer and adjust their sizes */
    if(surface->Flags & SFLAG_DIBSECTION) {
        /* Release the DC */
        SelectObject(surface->hDC, surface->dib.holdbitmap);
        DeleteDC(surface->hDC);
        /* Release the DIB section */
        DeleteObject(surface->dib.DIBsection);
        surface->dib.bitmap_data = NULL;
        surface->resource.allocatedMemory = NULL;
        surface->Flags &= ~SFLAG_DIBSECTION;
    }
6501 6502
    surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
    surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6503 6504
    if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
        GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6505 6506
        surface->pow2Width = pPresentationParameters->BackBufferWidth;
        surface->pow2Height = pPresentationParameters->BackBufferHeight;
6507 6508
    } else {
        surface->pow2Width = surface->pow2Height = 1;
6509 6510
        while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
        while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6511
    }
6512 6513 6514 6515 6516
    surface->glRect.left = 0;
    surface->glRect.top = 0;
    surface->glRect.right = surface->pow2Width;
    surface->glRect.bottom = surface->pow2Height;

6517 6518
    if (surface->texture_name)
    {
6519
        ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6520
        ENTER_GL();
6521
        glDeleteTextures(1, &surface->texture_name);
6522
        LEAVE_GL();
6523
        surface->texture_name = 0;
6524
        surface->Flags &= ~SFLAG_CLIENT;
6525
    }
6526 6527
    if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
       surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6528 6529 6530 6531
        surface->Flags |= SFLAG_NONPOW2;
    } else  {
        surface->Flags &= ~SFLAG_NONPOW2;
    }
6532 6533 6534
    HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
    surface->resource.allocatedMemory = NULL;
    surface->resource.heapMemory = NULL;
6535
    surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6536 6537 6538 6539 6540 6541
    /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
    if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
        IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
    } else {
        IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
    }
6542 6543
}

6544 6545 6546 6547 6548 6549 6550
static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
    TRACE("Unloading resource %p\n", resource);
    IWineD3DResource_UnLoad(resource);
    IWineD3DResource_Release(resource);
    return S_OK;
}

6551 6552
static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
{
6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577
    UINT i, count;
    WINED3DDISPLAYMODE m;
    HRESULT hr;

    /* All Windowed modes are supported, as is leaving the current mode */
    if(pp->Windowed) return TRUE;
    if(!pp->BackBufferWidth) return TRUE;
    if(!pp->BackBufferHeight) return TRUE;

    count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
    for(i = 0; i < count; i++) {
        memset(&m, 0, sizeof(m));
        hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
        if(FAILED(hr)) {
            ERR("EnumAdapterModes failed\n");
        }
        if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
            /* Mode found, it is supported */
            return TRUE;
        }
    }
    /* Mode not found -> not supported */
    return FALSE;
}

6578 6579 6580
void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6581 6582
    const struct wined3d_context *context;
    const struct wined3d_gl_info *gl_info;
6583 6584 6585
    UINT i;
    IWineD3DBaseShaderImpl *shader;

6586 6587
    context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
    gl_info = context->gl_info;
6588

6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599
    IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
    LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
        This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
    }

    ENTER_GL();
    if(This->depth_blt_texture) {
        glDeleteTextures(1, &This->depth_blt_texture);
        This->depth_blt_texture = 0;
    }
    if (This->depth_blt_rb) {
6600
        gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6601 6602 6603 6604
        This->depth_blt_rb = 0;
        This->depth_blt_rb_w = 0;
        This->depth_blt_rb_h = 0;
    }
6605 6606
    LEAVE_GL();

6607
    This->blitter->free_private(iface);
6608 6609 6610
    This->frag_pipe->free_private(iface);
    This->shader_backend->shader_free_private(iface);

6611
    ENTER_GL();
6612 6613
    for (i = 0; i < This->adapter->gl_info.max_textures; ++i)
    {
6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650
        /* Textures are recreated below */
        glDeleteTextures(1, &This->dummyTextureName[i]);
        checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
        This->dummyTextureName[i] = 0;
    }
    LEAVE_GL();

    while(This->numContexts) {
        DestroyContext(This, This->contexts[0]);
    }
    HeapFree(GetProcessHeap(), 0, swapchain->context);
    swapchain->context = NULL;
    swapchain->num_contexts = 0;
}

HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
    HRESULT hr;
    IWineD3DSurfaceImpl *target;

    /* Recreate the primary swapchain's context */
    swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
    if(swapchain->backBuffer) {
        target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
    } else {
        target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
    }
    swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
                                          &swapchain->presentParms);
    swapchain->num_contexts = 1;

    create_dummy_textures(This);

    hr = This->shader_backend->shader_alloc_private(iface);
    if(FAILED(hr)) {
        ERR("Failed to recreate shader private data\n");
6651
        goto err_out;
6652 6653 6654 6655
    }
    hr = This->frag_pipe->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Fragment pipeline private data couldn't be allocated\n");
6656 6657 6658 6659 6660 6661
        goto err_out;
    }
    hr = This->blitter->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Blitter private data couldn't be allocated\n");
        goto err_out;
6662 6663 6664
    }

    return WINED3D_OK;
6665 6666 6667 6668 6669 6670

err_out:
    This->blitter->free_private(iface);
    This->frag_pipe->free_private(iface);
    This->shader_backend->shader_free_private(iface);
    return hr;
6671 6672
}

6673
static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6674
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686
    IWineD3DSwapChainImpl *swapchain;
    HRESULT hr;
    BOOL DisplayModeChanged = FALSE;
    WINED3DDISPLAYMODE mode;
    TRACE("(%p)\n", This);

    hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
    if(FAILED(hr)) {
        ERR("Failed to get the first implicit swapchain\n");
        return hr;
    }

6687 6688 6689 6690
    if(!is_display_mode_supported(This, pPresentationParameters)) {
        WARN("Rejecting Reset() call because the requested display mode is not supported\n");
        WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
             pPresentationParameters->BackBufferHeight);
6691
        IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6692 6693 6694
        return WINED3DERR_INVALIDCALL;
    }

6695 6696 6697 6698 6699 6700 6701 6702
    /* Is it necessary to recreate the gl context? Actually every setting can be changed
     * on an existing gl context, so there's no real need for recreation.
     *
     * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
     *
     * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
     */
    TRACE("New params:\n");
6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715
    TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
    TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
    TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
    TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
    TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
    TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
    TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
    TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
    TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
    TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
    TRACE("Flags = %08x\n", pPresentationParameters->Flags);
    TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
    TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6716 6717

    /* No special treatment of these parameters. Just store them */
6718 6719 6720 6721
    swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
    swapchain->presentParms.Flags = pPresentationParameters->Flags;
    swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
    swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6722 6723

    /* What to do about these? */
6724 6725
    if(pPresentationParameters->BackBufferCount != 0 &&
        pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6726 6727
        ERR("Cannot change the back buffer count yet\n");
    }
6728 6729
    if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
        pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6730 6731
        ERR("Cannot change the back buffer format yet\n");
    }
6732 6733
    if(pPresentationParameters->hDeviceWindow != NULL &&
        pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6734 6735
        ERR("Cannot change the device window yet\n");
    }
6736
    if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755
        HRESULT hrc;

        TRACE("Creating the depth stencil buffer\n");

        hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
                This->parent,
                pPresentationParameters->BackBufferWidth,
                pPresentationParameters->BackBufferHeight,
                pPresentationParameters->AutoDepthStencilFormat,
                pPresentationParameters->MultiSampleType,
                pPresentationParameters->MultiSampleQuality,
                FALSE,
                &This->auto_depth_stencil_buffer);

        if (FAILED(hrc)) {
            ERR("Failed to create the depth stencil buffer\n");
            IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
            return WINED3DERR_INVALIDCALL;
        }
6756
    }
6757

6758 6759 6760 6761 6762 6763
    /* Reset the depth stencil */
    if (pPresentationParameters->EnableAutoDepthStencil)
        IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
    else
        IWineD3DDevice_SetDepthStencilSurface(iface, NULL);

6764 6765 6766 6767
    TRACE("Resetting stateblock\n");
    IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
    IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);

6768
    delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6769

6770
    if(pPresentationParameters->Windowed) {
6771 6772 6773 6774 6775
        mode.Width = swapchain->orig_width;
        mode.Height = swapchain->orig_height;
        mode.RefreshRate = 0;
        mode.Format = swapchain->presentParms.BackBufferFormat;
    } else {
6776 6777 6778
        mode.Width = pPresentationParameters->BackBufferWidth;
        mode.Height = pPresentationParameters->BackBufferHeight;
        mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6779 6780 6781 6782
        mode.Format = swapchain->presentParms.BackBufferFormat;
    }

    /* Should Width == 800 && Height == 0 set 800x600? */
6783 6784 6785
    if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
       (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
        pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6786
    {
6787
        UINT i;
6788

6789
        if(!pPresentationParameters->Windowed) {
6790 6791
            DisplayModeChanged = TRUE;
        }
6792 6793
        swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
        swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6794 6795 6796 6797 6798

        updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
        for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
            updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
        }
6799 6800 6801
        if(This->auto_depth_stencil_buffer) {
            updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
        }
6802 6803
    }

6804 6805
    if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
       (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6806
        DisplayModeChanged) {
6807

6808
        IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6809

6810
        if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6811 6812
            if(swapchain->presentParms.Windowed) {
                /* switch from windowed to fs */
6813
                IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6814 6815 6816 6817
                                                         pPresentationParameters->BackBufferWidth,
                                                         pPresentationParameters->BackBufferHeight);
            } else {
                /* Fullscreen -> fullscreen mode change */
6818 6819 6820
                MoveWindow(swapchain->win_handle, 0, 0,
                           pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
                           TRUE);
6821
            }
6822
        } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6823
            /* Fullscreen -> windowed switch */
6824
            IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6825 6826
        }
        swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6827 6828 6829 6830 6831 6832 6833 6834
    } else if(!pPresentationParameters->Windowed) {
        DWORD style = This->style, exStyle = This->exStyle;
        /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
         * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
         * Reset to clear up their mess. Guild Wars also loses the device during that.
         */
        This->style = 0;
        This->exStyle = 0;
6835
        IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6836 6837
                                                 pPresentationParameters->BackBufferWidth,
                                                 pPresentationParameters->BackBufferHeight);
6838 6839
        This->style = style;
        This->exStyle = exStyle;
6840
    }
6841 6842 6843 6844 6845 6846 6847 6848

    /* Note: No parent needed for initial internal stateblock */
    hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
    if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
    else TRACE("Created stateblock %p\n", This->stateBlock);
    This->updateStateBlock = This->stateBlock;
    IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);

6849 6850 6851 6852
    hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
    if(FAILED(hr)) {
        ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
    }
6853

6854 6855
    hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
    IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6856

6857 6858 6859
    /* All done. There is no need to reload resources or shaders, this will happen automatically on the
     * first use
     */
6860
    return hr;
6861 6862
}

6863
static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6864 6865
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    /** FIXME: always true at the moment **/
6866
    if(!bEnableDialogs) {
6867 6868
        FIXME("(%p) Dialogs cannot be disabled yet\n", This);
    }
6869
    return WINED3D_OK;
6870 6871 6872
}


6873
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6874
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6875
    TRACE("(%p) : pParameters %p\n", This, pParameters);
6876

6877
    *pParameters = This->createParms;
6878
    return WINED3D_OK;
6879 6880
}

6881
static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
Oliver Stieber's avatar
Oliver Stieber committed
6882 6883 6884 6885
    IWineD3DSwapChain *swapchain;

    TRACE("Relaying  to swapchain\n");

6886
    if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6887
        IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6888
        IWineD3DSwapChain_Release(swapchain);
Oliver Stieber's avatar
Oliver Stieber committed
6889
    }
6890 6891 6892
    return;
}

6893
static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
Oliver Stieber's avatar
Oliver Stieber committed
6894
    IWineD3DSwapChain *swapchain;
6895

Oliver Stieber's avatar
Oliver Stieber committed
6896 6897
    TRACE("Relaying  to swapchain\n");

6898 6899
    if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
        IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6900
        IWineD3DSwapChain_Release(swapchain);
Oliver Stieber's avatar
Oliver Stieber committed
6901
    }
6902
    return;
6903 6904
}

6905 6906 6907 6908 6909 6910

/** ********************************************************
*   Notification functions
** ********************************************************/
/** This function must be called in the release of a resource when ref == 0,
* the contents of resource must still be correct,
6911
* any handles to other resource held by the caller must be closed
6912 6913
* (e.g. a texture should release all held surfaces because telling the device that it's been released.)
 *****************************************************/
6914 6915 6916
void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
{
    TRACE("(%p) : Adding resource %p\n", This, resource);
6917

6918
    list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6919 6920
}

6921 6922
static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
{
6923
    TRACE("(%p) : Removing resource %p\n", This, resource);
6924

6925
    list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6926 6927
}

6928 6929
void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
{
6930
    WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6931 6932 6933
    int counter;

    TRACE("(%p) : resource %p\n", This, resource);
6934

6935
    context_resource_released((IWineD3DDevice *)This, resource, type);
6936 6937

    switch (type) {
6938
        /* TODO: check front and back buffers, rendertargets etc..  possibly swapchains? */
6939 6940 6941
        case WINED3DRTYPE_SURFACE: {
            unsigned int i;

6942 6943
            if (This->d3d_initialized)
            {
6944 6945
                for (i = 0; i < This->adapter->gl_info.max_buffers; ++i)
                {
6946 6947
                    if (This->render_targets[i] == (IWineD3DSurface *)resource) {
                        This->render_targets[i] = NULL;
6948 6949
                    }
                }
6950 6951 6952
                if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
                    This->stencilBufferTarget = NULL;
                }
6953 6954 6955 6956
            }

            break;
        }
6957 6958 6959
        case WINED3DRTYPE_TEXTURE:
        case WINED3DRTYPE_CUBETEXTURE:
        case WINED3DRTYPE_VOLUMETEXTURE:
6960
                for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6961
                    if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6962
                        WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6963 6964 6965 6966
                        This->stateBlock->textures[counter] = NULL;
                    }
                    if (This->updateStateBlock != This->stateBlock ){
                        if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6967
                            WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6968 6969 6970 6971 6972
                            This->updateStateBlock->textures[counter] = NULL;
                        }
                    }
                }
        break;
6973
        case WINED3DRTYPE_VOLUME:
6974 6975
        /* TODO: nothing really? */
        break;
6976
        case WINED3DRTYPE_BUFFER:
6977 6978 6979 6980 6981 6982 6983 6984 6985 6986
        {
            int streamNumber;
            TRACE("Cleaning up stream pointers\n");

            for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
                /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
                FINDOUT: should changes.streamSource[StreamNumber] be set ?
                */
                if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
                    if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6987
                        FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6988 6989 6990 6991
                        This->updateStateBlock->streamSource[streamNumber] = 0;
                        /* Set changed flag? */
                    }
                }
6992
                if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6993
                    if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6994
                        TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6995 6996 6997 6998
                        This->stateBlock->streamSource[streamNumber] = 0;
                    }
                }
            }
6999 7000

            if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7001
                if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7002 7003
                    This->updateStateBlock->pIndexData =  NULL;
                }
7004
            }
7005
            if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7006
                if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7007 7008
                    This->stateBlock->pIndexData =  NULL;
                }
7009 7010 7011
            }
        }
        break;
7012

7013
        default:
7014
        FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7015 7016 7017 7018
        break;
    }


7019
    /* Remove the resource from the resourceStore */
7020
    device_resource_remove(This, resource);
7021 7022 7023 7024 7025

    TRACE("Resource released\n");

}

7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043
static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DResourceImpl *resource, *cursor;
    HRESULT ret;
    TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);

    LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
        TRACE("enumerating resource %p\n", resource);
        IWineD3DResource_AddRef((IWineD3DResource *) resource);
        ret = pCallback((IWineD3DResource *) resource, pData);
        if(ret == S_FALSE) {
            TRACE("Canceling enumeration\n");
            break;
        }
    }
    return WINED3D_OK;
}

7044 7045 7046 7047
/**********************************************************
 * IWineD3DDevice VTbl follows
 **********************************************************/

7048
const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7049
{
7050
    /*** IUnknown methods ***/
7051 7052
    IWineD3DDeviceImpl_QueryInterface,
    IWineD3DDeviceImpl_AddRef,
7053
    IWineD3DDeviceImpl_Release,
7054
    /*** IWineD3DDevice methods ***/
7055
    IWineD3DDeviceImpl_GetParent,
7056
    /*** Creation methods**/
7057
    IWineD3DDeviceImpl_CreateBuffer,
7058
    IWineD3DDeviceImpl_CreateVertexBuffer,
7059
    IWineD3DDeviceImpl_CreateIndexBuffer,
7060
    IWineD3DDeviceImpl_CreateStateBlock,
7061
    IWineD3DDeviceImpl_CreateSurface,
7062
    IWineD3DDeviceImpl_CreateRendertargetView,
7063 7064 7065 7066
    IWineD3DDeviceImpl_CreateTexture,
    IWineD3DDeviceImpl_CreateVolumeTexture,
    IWineD3DDeviceImpl_CreateVolume,
    IWineD3DDeviceImpl_CreateCubeTexture,
7067
    IWineD3DDeviceImpl_CreateQuery,
7068
    IWineD3DDeviceImpl_CreateSwapChain,
7069
    IWineD3DDeviceImpl_CreateVertexDeclaration,
7070
    IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7071 7072
    IWineD3DDeviceImpl_CreateVertexShader,
    IWineD3DDeviceImpl_CreatePixelShader,
7073
    IWineD3DDeviceImpl_CreatePalette,
7074
    /*** Odd functions **/
7075
    IWineD3DDeviceImpl_Init3D,
7076
    IWineD3DDeviceImpl_InitGDI,
7077
    IWineD3DDeviceImpl_Uninit3D,
7078
    IWineD3DDeviceImpl_UninitGDI,
7079
    IWineD3DDeviceImpl_SetMultithreaded,
7080
    IWineD3DDeviceImpl_EvictManagedResources,
7081 7082 7083 7084 7085 7086
    IWineD3DDeviceImpl_GetAvailableTextureMem,
    IWineD3DDeviceImpl_GetBackBuffer,
    IWineD3DDeviceImpl_GetCreationParameters,
    IWineD3DDeviceImpl_GetDeviceCaps,
    IWineD3DDeviceImpl_GetDirect3D,
    IWineD3DDeviceImpl_GetDisplayMode,
7087
    IWineD3DDeviceImpl_SetDisplayMode,
7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106
    IWineD3DDeviceImpl_GetNumberOfSwapChains,
    IWineD3DDeviceImpl_GetRasterStatus,
    IWineD3DDeviceImpl_GetSwapChain,
    IWineD3DDeviceImpl_Reset,
    IWineD3DDeviceImpl_SetDialogBoxMode,
    IWineD3DDeviceImpl_SetCursorProperties,
    IWineD3DDeviceImpl_SetCursorPosition,
    IWineD3DDeviceImpl_ShowCursor,
    IWineD3DDeviceImpl_TestCooperativeLevel,
    /*** Getters and setters **/
    IWineD3DDeviceImpl_SetClipPlane,
    IWineD3DDeviceImpl_GetClipPlane,
    IWineD3DDeviceImpl_SetClipStatus,
    IWineD3DDeviceImpl_GetClipStatus,
    IWineD3DDeviceImpl_SetCurrentTexturePalette,
    IWineD3DDeviceImpl_GetCurrentTexturePalette,
    IWineD3DDeviceImpl_SetDepthStencilSurface,
    IWineD3DDeviceImpl_GetDepthStencilSurface,
    IWineD3DDeviceImpl_SetGammaRamp,
7107
    IWineD3DDeviceImpl_GetGammaRamp,
7108
    IWineD3DDeviceImpl_SetIndexBuffer,
7109
    IWineD3DDeviceImpl_GetIndexBuffer,
7110
    IWineD3DDeviceImpl_SetBaseVertexIndex,
7111
    IWineD3DDeviceImpl_GetBaseVertexIndex,
7112 7113 7114 7115 7116 7117
    IWineD3DDeviceImpl_SetLight,
    IWineD3DDeviceImpl_GetLight,
    IWineD3DDeviceImpl_SetLightEnable,
    IWineD3DDeviceImpl_GetLightEnable,
    IWineD3DDeviceImpl_SetMaterial,
    IWineD3DDeviceImpl_GetMaterial,
7118
    IWineD3DDeviceImpl_SetNPatchMode,
7119
    IWineD3DDeviceImpl_GetNPatchMode,
7120 7121 7122 7123 7124 7125 7126 7127 7128 7129
    IWineD3DDeviceImpl_SetPaletteEntries,
    IWineD3DDeviceImpl_GetPaletteEntries,
    IWineD3DDeviceImpl_SetPixelShader,
    IWineD3DDeviceImpl_GetPixelShader,
    IWineD3DDeviceImpl_SetPixelShaderConstantB,
    IWineD3DDeviceImpl_GetPixelShaderConstantB,
    IWineD3DDeviceImpl_SetPixelShaderConstantI,
    IWineD3DDeviceImpl_GetPixelShaderConstantI,
    IWineD3DDeviceImpl_SetPixelShaderConstantF,
    IWineD3DDeviceImpl_GetPixelShaderConstantF,
7130 7131
    IWineD3DDeviceImpl_SetRenderState,
    IWineD3DDeviceImpl_GetRenderState,
7132 7133
    IWineD3DDeviceImpl_SetRenderTarget,
    IWineD3DDeviceImpl_GetRenderTarget,
7134
    IWineD3DDeviceImpl_SetFrontBackBuffers,
7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145
    IWineD3DDeviceImpl_SetSamplerState,
    IWineD3DDeviceImpl_GetSamplerState,
    IWineD3DDeviceImpl_SetScissorRect,
    IWineD3DDeviceImpl_GetScissorRect,
    IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
    IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
    IWineD3DDeviceImpl_SetStreamSource,
    IWineD3DDeviceImpl_GetStreamSource,
    IWineD3DDeviceImpl_SetStreamSourceFreq,
    IWineD3DDeviceImpl_GetStreamSourceFreq,
    IWineD3DDeviceImpl_SetTexture,
7146
    IWineD3DDeviceImpl_GetTexture,
7147 7148
    IWineD3DDeviceImpl_SetTextureStageState,
    IWineD3DDeviceImpl_GetTextureStageState,
7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161
    IWineD3DDeviceImpl_SetTransform,
    IWineD3DDeviceImpl_GetTransform,
    IWineD3DDeviceImpl_SetVertexDeclaration,
    IWineD3DDeviceImpl_GetVertexDeclaration,
    IWineD3DDeviceImpl_SetVertexShader,
    IWineD3DDeviceImpl_GetVertexShader,
    IWineD3DDeviceImpl_SetVertexShaderConstantB,
    IWineD3DDeviceImpl_GetVertexShaderConstantB,
    IWineD3DDeviceImpl_SetVertexShaderConstantI,
    IWineD3DDeviceImpl_GetVertexShaderConstantI,
    IWineD3DDeviceImpl_SetVertexShaderConstantF,
    IWineD3DDeviceImpl_GetVertexShaderConstantF,
    IWineD3DDeviceImpl_SetViewport,
7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173
    IWineD3DDeviceImpl_GetViewport,
    IWineD3DDeviceImpl_MultiplyTransform,
    IWineD3DDeviceImpl_ValidateDevice,
    IWineD3DDeviceImpl_ProcessVertices,
    /*** State block ***/
    IWineD3DDeviceImpl_BeginStateBlock,
    IWineD3DDeviceImpl_EndStateBlock,
    /*** Scene management ***/
    IWineD3DDeviceImpl_BeginScene,
    IWineD3DDeviceImpl_EndScene,
    IWineD3DDeviceImpl_Present,
    IWineD3DDeviceImpl_Clear,
7174
    IWineD3DDeviceImpl_ClearRendertargetView,
7175
    /*** Drawing ***/
7176 7177
    IWineD3DDeviceImpl_SetPrimitiveType,
    IWineD3DDeviceImpl_GetPrimitiveType,
7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193
    IWineD3DDeviceImpl_DrawPrimitive,
    IWineD3DDeviceImpl_DrawIndexedPrimitive,
    IWineD3DDeviceImpl_DrawPrimitiveUP,
    IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
    IWineD3DDeviceImpl_DrawPrimitiveStrided,
    IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
    IWineD3DDeviceImpl_DrawRectPatch,
    IWineD3DDeviceImpl_DrawTriPatch,
    IWineD3DDeviceImpl_DeletePatch,
    IWineD3DDeviceImpl_ColorFill,
    IWineD3DDeviceImpl_UpdateTexture,
    IWineD3DDeviceImpl_UpdateSurface,
    IWineD3DDeviceImpl_GetFrontBufferData,
    /*** object tracking ***/
    IWineD3DDeviceImpl_EnumResources
};
7194

7195
void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7196
    DWORD rep = This->StateTable[state].representative;
7197
    struct wined3d_context *context;
7198 7199
    DWORD idx;
    BYTE shift;
7200
    UINT i;
7201

7202
    for(i = 0; i < This->numContexts; i++) {
7203
        context = This->contexts[i];
7204 7205 7206 7207 7208 7209 7210
        if(isStateDirty(context, rep)) continue;

        context->dirtyArray[context->numDirtyEntries++] = rep;
        idx = rep >> 5;
        shift = rep & 0x1f;
        context->isStateDirty[idx] |= (1 << shift);
    }
7211
}
7212

7213
void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7214 7215 7216 7217 7218
{
    IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
    /* The drawable size of a pbuffer render target is the current pbuffer size. */
    *width = device->pbufferWidth;
    *height = device->pbufferHeight;
7219 7220
}

7221
void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7222 7223 7224 7225 7226
{
    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
    /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
    *width = surface->pow2Width;
    *height = surface->pow2Height;
7227 7228
}

7229
void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7230 7231
{
    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7232 7233 7234
    /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
     * current context's drawable, which is the size of the back buffer of the swapchain
     * the active context belongs to. The back buffer of the swapchain is stored as the
7235 7236 7237
     * surface the context belongs to. */
    *width = surface->currentDesc.Width;
    *height = surface->currentDesc.Height;
7238
}