device.c 279 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, &GLINFO_LOCATION);
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

1360 1361 1362 1363
    TRACE("Created verrtex declaration %p.\n", object);
    *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 1693 1694 1695 1696
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)");
    }
    for (i = 0; i < GL_LIMITS(textures); i++) {
        GLubyte white = 255;

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

        /* 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();
}

1722 1723 1724
static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
        WINED3DPRESENT_PARAMETERS *pPresentationParameters)
{
1725
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1726
    IWineD3DSwapChainImpl *swapchain = NULL;
1727
    HRESULT hr;
1728
    DWORD state;
1729
    unsigned int i;
1730

1731 1732
    TRACE("(%p)->(%p)\n", This, pPresentationParameters);

1733
    if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1734
    if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1735 1736 1737

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

1738 1739 1740 1741 1742 1743 1744 1745
    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");
1746
        goto err_out;
1747 1748 1749 1750 1751
    }
    TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
    This->updateStateBlock = This->stateBlock;
    IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);

1752 1753 1754
    This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
    This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));

1755 1756
    This->NumberOfPalettes = 1;
    This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1757
    if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
        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;

1774
    /* Initialize the texture unit mapping to a 1:1 mapping */
1775
    for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1776
        if (state < GL_LIMITS(fragment_samplers)) {
1777 1778 1779
            This->texUnitMap[state] = state;
            This->rev_tex_unit_map[state] = state;
        } else {
1780 1781
            This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
            This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1782
        }
1783 1784
    }

1785
    /* Setup the implicit swapchain. This also initializes a context. */
1786
    TRACE("Creating implicit swapchain\n");
1787 1788 1789 1790
    hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
            pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
    if (FAILED(hr))
    {
1791
        WARN("Failed to create implicit swapchain\n");
1792
        goto err_out;
1793 1794
    }

1795 1796 1797 1798
    This->NumberOfSwapChains = 1;
    This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
    if(!This->swapchains) {
        ERR("Out of memory!\n");
1799
        goto err_out;
1800 1801 1802
    }
    This->swapchains[0] = (IWineD3DSwapChain *) swapchain;

1803
    if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1804
        TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1805
        This->render_targets[0] = swapchain->backBuffer[0];
1806 1807 1808
    }
    else {
        TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1809
        This->render_targets[0] = swapchain->frontBuffer;
1810
    }
1811
    IWineD3DSurface_AddRef(This->render_targets[0]);
1812

1813
    /* Depth Stencil support */
1814
    This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1815 1816 1817 1818
    if (NULL != This->stencilBufferTarget) {
        IWineD3DSurface_AddRef(This->stencilBufferTarget);
    }

1819 1820 1821 1822 1823
    hr = This->shader_backend->shader_alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Shader private data couldn't be allocated\n");
        goto err_out;
    }
1824 1825 1826 1827 1828
    hr = This->frag_pipe->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Fragment pipeline private data couldn't be allocated\n");
        goto err_out;
    }
1829 1830 1831 1832 1833
    hr = This->blitter->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Blitter private data couldn't be allocated\n");
        goto err_out;
    }
1834

1835 1836 1837 1838
    /* Set up some starting GL setup */

    /* Setup all the devices defaults */
    IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1839
    create_dummy_textures(This);
1840 1841 1842

    ENTER_GL();

1843 1844
    /* Initialize the current view state */
    This->view_ident = 1;
1845
    This->contexts[0]->last_was_rhw = 0;
1846
    glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1847
    checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1848 1849 1850 1851 1852 1853 1854 1855 1856

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

        case ORM_BACKBUFFER:
        {
1857 1858
            if (context_get_current()->aux_buffers > 0)
            {
1859 1860 1861 1862 1863 1864 1865 1866 1867
                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;
            }
        }
    }

1868
    TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1869
    LEAVE_GL();
1870 1871

    /* Clear the screen */
1872 1873
    IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
                          WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1874
                          0x00, 1.0f, 0);
1875 1876

    This->d3d_initialized = TRUE;
1877 1878 1879 1880

    if(wined3d_settings.logo) {
        IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
    }
1881 1882
    This->highest_dirty_ps_const = 0;
    This->highest_dirty_vs_const = 0;
1883
    return WINED3D_OK;
1884

1885
err_out:
1886 1887 1888 1889
    HeapFree(GetProcessHeap(), 0, This->render_targets);
    HeapFree(GetProcessHeap(), 0, This->draw_buffers);
    HeapFree(GetProcessHeap(), 0, This->swapchains);
    This->NumberOfSwapChains = 0;
1890 1891 1892 1893 1894
    if(This->palettes) {
        HeapFree(GetProcessHeap(), 0, This->palettes[0]);
        HeapFree(GetProcessHeap(), 0, This->palettes);
    }
    This->NumberOfPalettes = 0;
1895 1896 1897 1898 1899 1900 1901
    if(swapchain) {
        IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
    }
    if(This->stateBlock) {
        IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
        This->stateBlock = NULL;
    }
1902 1903 1904 1905 1906 1907 1908 1909 1910
    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);
    }
1911
    return hr;
1912 1913
}

1914 1915 1916
static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
        WINED3DPRESENT_PARAMETERS *pPresentationParameters)
{
1917 1918 1919 1920 1921 1922
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSwapChainImpl *swapchain = NULL;
    HRESULT hr;

    /* Setup the implicit swapchain */
    TRACE("Creating implicit swapchain\n");
1923 1924 1925 1926
    hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
            pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
    if (FAILED(hr))
    {
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
        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;
}

1945 1946 1947 1948 1949 1950 1951
static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
{
    IWineD3DResource_UnLoad(resource);
    IWineD3DResource_Release(resource);
    return WINED3D_OK;
}

1952 1953 1954
static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
        D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
{
1955
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1956 1957
    const struct wined3d_context *context;
    const struct wined3d_gl_info *gl_info;
1958
    int sampler;
1959
    UINT i;
1960 1961 1962 1963
    TRACE("(%p)\n", This);

    if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;

1964
    /* I don't think that the interface guarantees that the device is destroyed from the same thread
1965 1966
     * it was created. Thus make sure a context is active for the glDelete* calls
     */
1967 1968
    context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
    gl_info = context->gl_info;
1969

1970 1971
    if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);

1972 1973 1974
    /* Unload resources */
    IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);

1975 1976 1977 1978 1979 1980 1981 1982 1983 1984
    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);
        }
    }

1985 1986
    /* Delete the palette conversion shader if it is around */
    if(This->paletteConversionShader) {
1987
        ENTER_GL();
1988
        GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1989
        LEAVE_GL();
1990
        This->paletteConversionShader = 0;
1991 1992
    }

1993 1994 1995
    /* Delete the pbuffer context if there is any */
    if(This->pbufferContext) DestroyContext(This, This->pbufferContext);

1996 1997 1998 1999 2000 2001 2002 2003
    /* Delete the mouse cursor texture */
    if(This->cursorTexture) {
        ENTER_GL();
        glDeleteTextures(1, &This->cursorTexture);
        LEAVE_GL();
        This->cursorTexture = 0;
    }

2004
    for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2005
        IWineD3DDevice_SetTexture(iface, sampler, NULL);
2006
    }
2007 2008 2009
    for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
        IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
    }
2010

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

2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047
    /* 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);
        }
    }

2048
    /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2049
    This->blitter->free_private(iface);
2050
    This->frag_pipe->free_private(iface);
2051
    This->shader_backend->shader_free_private(iface);
2052

2053
    /* Release the buffers (with sanity checks)*/
2054 2055
    TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
    if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2056 2057
        if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
            FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2058 2059 2060
    }
    This->stencilBufferTarget = NULL;

2061 2062
    TRACE("Releasing the render target at %p\n", This->render_targets[0]);
    if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2063
          /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2064 2065
    }
    TRACE("Setting rendertarget to NULL\n");
2066
    This->render_targets[0] = NULL;
2067

2068
    if (This->auto_depth_stencil_buffer) {
2069 2070
        if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
        {
2071
            FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2072
        }
2073
        This->auto_depth_stencil_buffer = NULL;
2074 2075
    }

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

    HeapFree(GetProcessHeap(), 0, This->swapchains);
2084
    This->swapchains = NULL;
2085
    This->NumberOfSwapChains = 0;
2086

2087 2088 2089 2090 2091
    for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
    HeapFree(GetProcessHeap(), 0, This->palettes);
    This->palettes = NULL;
    This->NumberOfPalettes = 0;

2092 2093 2094 2095 2096
    HeapFree(GetProcessHeap(), 0, This->render_targets);
    HeapFree(GetProcessHeap(), 0, This->draw_buffers);
    This->render_targets = NULL;
    This->draw_buffers = NULL;

2097 2098
    This->d3d_initialized = FALSE;
    return WINED3D_OK;
2099 2100
}

2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
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;
}

2118 2119
/* 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
2120 2121
 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
 *
2122
 * There is no way to deactivate thread safety once it is enabled.
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132
 */
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;
}

2133 2134
static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
        const WINED3DDISPLAYMODE* pMode) {
2135 2136 2137
    DEVMODEW devmode;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    LONG ret;
2138
    const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2139
    RECT clip_rc;
2140 2141 2142 2143 2144 2145 2146 2147 2148

    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
     */

2149 2150
    memset(&devmode, 0, sizeof(devmode));
    devmode.dmSize = sizeof(devmode);
2151
    devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2152
    devmode.dmBitsPerPel = format_desc->byte_count * 8;
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
    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) ) {
2166
        return WINED3D_OK;
2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177
    }

    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) {
2178
            return WINED3DERR_NOTAVAILABLE;
2179 2180 2181 2182 2183 2184 2185 2186
        }
    }

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

2187 2188 2189 2190
    /* And finally clip mouse to our screen */
    SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
    ClipCursor(&clip_rc);

2191
    return WINED3D_OK;
2192 2193
}

2194
static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2195 2196 2197
   IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
   *ppD3D= This->wineD3D;
   TRACE("(%p) : wineD3D returning %p\n", This,  *ppD3D);
2198
   IWineD3D_AddRef(*ppD3D);
2199
   return WINED3D_OK;
2200
}
2201

2202
static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2203
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2204

2205
    TRACE("(%p) : simulating %dMB, returning %dMB left\n",  This,
2206 2207
         (This->adapter->TextureRam/(1024*1024)),
         ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2208
    /* return simulated texture memory left */
2209
    return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2210 2211
}

2212 2213 2214
/*****
 * Get / Set Stream Source
 *****/
2215 2216 2217 2218 2219
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
        IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    IWineD3DBuffer *oldSrc;
2220

2221 2222
    if (StreamNumber >= MAX_STREAMS) {
        WARN("Stream out of range %d\n", StreamNumber);
2223
        return WINED3DERR_INVALIDCALL;
2224 2225 2226
    } else if(OffsetInBytes & 0x3) {
        WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
        return WINED3DERR_INVALIDCALL;
2227 2228
    }

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

2232
    This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2233 2234 2235

    if(oldSrc == pStreamData &&
       This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2236
       This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2237 2238 2239 2240
       TRACE("Application is setting the old values over, nothing to do\n");
       return WINED3D_OK;
    }

2241
    This->updateStateBlock->streamSource[StreamNumber]         = pStreamData;
2242 2243 2244 2245
    if (pStreamData) {
        This->updateStateBlock->streamStride[StreamNumber]     = Stride;
        This->updateStateBlock->streamOffset[StreamNumber]     = OffsetInBytes;
    }
2246 2247 2248 2249

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2250 2251
        if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
        if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2252
        return WINED3D_OK;
2253 2254
    }

2255
    if (pStreamData != NULL) {
2256 2257
        InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
        IWineD3DBuffer_AddRef(pStreamData);
2258 2259
    }
    if (oldSrc != NULL) {
2260 2261
        InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
        IWineD3DBuffer_Release(oldSrc);
2262
    }
2263

2264 2265
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);

2266
    return WINED3D_OK;
2267 2268
}

2269 2270 2271
static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
        UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
{
2272
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2273

2274 2275 2276 2277
    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]);
2278

2279 2280
    if (StreamNumber >= MAX_STREAMS) {
        WARN("Stream out of range %d\n", StreamNumber);
2281
        return WINED3DERR_INVALIDCALL;
2282
    }
2283 2284
    *pStream = This->stateBlock->streamSource[StreamNumber];
    *pStride = This->stateBlock->streamStride[StreamNumber];
2285 2286 2287
    if (pOffset) {
        *pOffset = This->stateBlock->streamOffset[StreamNumber];
    }
2288

2289
    if (*pStream != NULL) {
2290
        IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2291
    }
2292
    return WINED3D_OK;
2293 2294
}

2295
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT Divider) {
2296
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2297 2298
    UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
    UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2299

2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
    /* 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;
    }

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

2317
    This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2318 2319
    This->updateStateBlock->streamFreq[StreamNumber]          = Divider & 0x7FFFFF;

2320 2321 2322
    if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
       This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2323 2324
    }

2325
    return WINED3D_OK;
2326
}
2327

2328
static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface,  UINT StreamNumber, UINT* Divider) {
2329
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2330

2331 2332 2333 2334 2335
    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);

2336
    return WINED3D_OK;
2337 2338
}

2339
/*****
2340
 * Get / Set & Multiply Transform
2341
 *****/
2342
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2343 2344 2345
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    /* Most of this routine, comments included copied from ddraw tree initially: */
2346
    TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2347 2348 2349 2350

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2351
        This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2352
        This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2353
        return WINED3D_OK;
2354 2355 2356 2357 2358 2359 2360 2361 2362 2363
    }

    /*
     * 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.
     */
2364
    if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2365
        TRACE("The app is setting the same matrix over again\n");
2366
        return WINED3D_OK;
2367 2368 2369 2370 2371 2372 2373 2374 2375
    } 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
2376
       matrix.  The Projection matrix stay projection matrix.
2377 2378 2379
     */

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

2385
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2386
    return WINED3D_OK;
2387 2388

}
2389
static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2390
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391
    TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2392
    *pMatrix = This->stateBlock->transforms[State];
2393
    return WINED3D_OK;
2394 2395
}

2396
static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2397
    const WINED3DMATRIX *mat = NULL;
2398
    WINED3DMATRIX temp;
2399

2400 2401
    /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
     * below means it will be recorded in a state block change, but it
2402
     * works regardless where it is recorded.
2403 2404
     * If this is found to be wrong, change to StateBlock.
     */
2405
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2406
    TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2407

2408
    if (State <= HIGHEST_TRANSFORMSTATE)
2409 2410 2411 2412 2413 2414
    {
        mat = &This->updateStateBlock->transforms[State];
    } else {
        FIXME("Unhandled transform state!!\n");
    }

2415
    multiply_matrix(&temp, mat, pMatrix);
2416 2417

    /* Apply change via set transform - will reapply to eg. lights this way */
2418
    return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2419 2420 2421 2422 2423 2424
}

/*****
 * Get / Set Light
 *****/
/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2425
   you can reference any indexes you want as long as that number max are enabled at any
2426 2427
   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,
2428
   but when recording, just build a chain pretty much of commands to be replayed.                  */
2429

2430
static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2431
    float rho;
2432 2433 2434
    PLIGHTINFOEL *object = NULL;
    UINT Hi = LIGHTMAP_HASHFUNC(Index);
    struct list *e;
2435 2436

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

2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454
    /* 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
             */
2455 2456
            if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
            {
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470
                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;
    }

2471 2472 2473 2474
    LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
        object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
        if(object->OriginalIndex == Index) break;
        object = NULL;
2475 2476
    }

2477 2478 2479 2480 2481 2482
    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;
2483
        }
2484
        list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2485
        object->glIndex = -1;
2486 2487
        object->OriginalIndex = Index;
        object->changed = TRUE;
2488 2489
    }

2490
    /* Initialize the object */
2491
    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,
2492 2493 2494 2495 2496 2497 2498 2499
          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 */
2500
    object->OriginalParms = *pLight;
2501 2502

    switch (pLight->Type) {
2503
    case WINED3DLIGHT_POINT:
2504 2505 2506 2507 2508 2509 2510 2511 2512
        /* 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;

2513
    case WINED3DLIGHT_DIRECTIONAL:
2514 2515 2516 2517
        /* Direction */
        object->lightPosn[0] = -pLight->Direction.x;
        object->lightPosn[1] = -pLight->Direction.y;
        object->lightPosn[2] = -pLight->Direction.z;
2518
        object->lightPosn[3] = 0.0f;
2519 2520 2521 2522
        object->exponent     = 0.0f;
        object->cutoff       = 180.0f;
        break;

2523
    case WINED3DLIGHT_SPOT:
2524 2525 2526 2527
        /* Position */
        object->lightPosn[0] = pLight->Position.x;
        object->lightPosn[1] = pLight->Position.y;
        object->lightPosn[2] = pLight->Position.z;
2528
        object->lightPosn[3] = 1.0f;
2529 2530 2531 2532 2533

        /* Direction */
        object->lightDirn[0] = pLight->Direction.x;
        object->lightDirn[1] = pLight->Direction.y;
        object->lightDirn[2] = pLight->Direction.z;
2534
        object->lightDirn[3] = 1.0f;
2535 2536 2537 2538 2539 2540 2541 2542 2543

        /*
         * 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) {
2544 2545 2546 2547 2548
            /* 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
             */
2549
            object->exponent = 0.0f;
2550 2551
        } else {
            rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2552 2553
            if (rho < 0.0001f) rho = 0.0001f;
            object->exponent = -0.3f/logf(cosf(rho/2));
2554
        }
2555 2556 2557
        if (object->exponent > 128.0f)
        {
            object->exponent = 128.0f;
2558
        }
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568
        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 */
2569
    if (object->glIndex != -1 && !This->isRecordingState) {
2570
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2571
    }
2572
    return WINED3D_OK;
2573 2574
}

2575
static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2576
    PLIGHTINFOEL *lightInfo = NULL;
2577
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2578 2579
    DWORD Hi = LIGHTMAP_HASHFUNC(Index);
    struct list *e;
2580
    TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2581

2582 2583 2584 2585 2586
    LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
        lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
        if(lightInfo->OriginalIndex == Index) break;
        lightInfo = NULL;
    }
2587 2588 2589

    if (lightInfo == NULL) {
        TRACE("Light information requested but light not defined\n");
2590
        return WINED3DERR_INVALIDCALL;
2591 2592
    }

2593
    *pLight = lightInfo->OriginalParms;
2594
    return WINED3D_OK;
2595 2596 2597
}

/*****
2598
 * Get / Set Light Enable
2599 2600
 *   (Note for consistency, renamed d3dx function by adding the 'set' prefix)
 *****/
2601
static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2602 2603
    PLIGHTINFOEL *lightInfo = NULL;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 2605
    UINT Hi = LIGHTMAP_HASHFUNC(Index);
    struct list *e;
2606
    TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2607

2608 2609 2610 2611
    LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
        lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
        if(lightInfo->OriginalIndex == Index) break;
        lightInfo = NULL;
2612
    }
2613
    TRACE("Found light: %p\n", lightInfo);
2614 2615 2616

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

2618
        TRACE("Light enabled requested but light not defined, so defining one!\n");
2619
        IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2620 2621

        /* Search for it again! Should be fairly quick as near head of list */
2622 2623 2624 2625 2626
        LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
            lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
            if(lightInfo->OriginalIndex == Index) break;
            lightInfo = NULL;
        }
2627 2628
        if (lightInfo == NULL) {
            FIXME("Adding default lights has failed dismally\n");
2629
            return WINED3DERR_INVALIDCALL;
2630 2631 2632
        }
    }

2633 2634 2635 2636
    lightInfo->enabledChanged = TRUE;
    if(!Enable) {
        if(lightInfo->glIndex != -1) {
            if(!This->isRecordingState) {
2637
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2638
            }
2639

2640
            This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2641
            lightInfo->glIndex = -1;
2642
        } else {
2643
            TRACE("Light already disabled, nothing to do\n");
2644
        }
2645
        lightInfo->enabled = FALSE;
2646
    } else {
2647
        lightInfo->enabled = TRUE;
2648
        if (lightInfo->glIndex != -1) {
2649 2650 2651
            /* nop */
            TRACE("Nothing to do as light was enabled\n");
        } else {
2652 2653 2654
            int i;
            /* Find a free gl light */
            for(i = 0; i < This->maxConcurrentLights; i++) {
2655 2656
                if(This->updateStateBlock->activeLights[i] == NULL) {
                    This->updateStateBlock->activeLights[i] = lightInfo;
2657 2658
                    lightInfo->glIndex = i;
                    break;
2659 2660
                }
            }
2661
            if(lightInfo->glIndex == -1) {
2662 2663 2664 2665 2666 2667 2668
                /* 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
                 */
2669
                WARN("Too many concurrently active lights\n");
2670
                return WINED3D_OK;
2671
            }
2672

2673 2674
            /* i == lightInfo->glIndex */
            if(!This->isRecordingState) {
2675
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2676 2677 2678
            }
        }
    }
2679

2680
    return WINED3D_OK;
2681 2682
}

2683
static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2684 2685

    PLIGHTINFOEL *lightInfo = NULL;
2686
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2687 2688
    struct list *e;
    UINT Hi = LIGHTMAP_HASHFUNC(Index);
2689
    TRACE("(%p) : for idx(%d)\n", This, Index);
2690

2691 2692 2693 2694 2695
    LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
        lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
        if(lightInfo->OriginalIndex == Index) break;
        lightInfo = NULL;
    }
2696 2697 2698

    if (lightInfo == NULL) {
        TRACE("Light enabled state requested but light not defined\n");
2699
        return WINED3DERR_INVALIDCALL;
2700
    }
2701
    /* true is 128 according to SetLightEnable */
2702
    *pEnable = lightInfo->enabled ? 128 : 0;
2703
    return WINED3D_OK;
2704 2705 2706 2707 2708
}

/*****
 * Get / Set Clip Planes
 *****/
2709
static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2710
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2711
    TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2712 2713 2714 2715

    /* Validate Index */
    if (Index >= GL_LIMITS(clipplanes)) {
        TRACE("Application has requested clipplane this device doesn't support\n");
2716
        return WINED3DERR_INVALIDCALL;
2717 2718
    }

2719
    This->updateStateBlock->changed.clipplane |= 1 << Index;
2720 2721 2722 2723 2724 2725 2726 2727 2728

    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;
    }

2729 2730 2731 2732 2733 2734 2735 2736
    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");
2737
        return WINED3D_OK;
2738 2739
    }

2740
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2741

2742
    return WINED3D_OK;
2743 2744
}

2745
static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2746
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2747
    TRACE("(%p) : for idx %d\n", This, Index);
2748 2749 2750 2751

    /* Validate Index */
    if (Index >= GL_LIMITS(clipplanes)) {
        TRACE("Application has requested clipplane this device doesn't support\n");
2752
        return WINED3DERR_INVALIDCALL;
2753 2754 2755 2756 2757 2758
    }

    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];
2759
    return WINED3D_OK;
2760 2761 2762 2763 2764 2765
}

/*****
 * Get / Set Clip Plane Status
 *   WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
 *****/
2766
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2767 2768 2769
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    FIXME("(%p) : stub\n", This);
    if (NULL == pClipStatus) {
2770
      return WINED3DERR_INVALIDCALL;
2771 2772 2773
    }
    This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
    This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2774
    return WINED3D_OK;
2775 2776
}

2777
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2778
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2779
    FIXME("(%p) : stub\n", This);
2780
    if (NULL == pClipStatus) {
2781
      return WINED3DERR_INVALIDCALL;
2782 2783 2784
    }
    pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
    pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2785
    return WINED3D_OK;
2786 2787 2788 2789 2790
}

/*****
 * Get / Set Material
 *****/
2791
static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2792 2793 2794
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    This->updateStateBlock->changed.material = TRUE;
2795
    This->updateStateBlock->material = *pMaterial;
2796 2797 2798 2799

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

2803
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2804
    return WINED3D_OK;
2805 2806
}

2807
static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2808
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809
    *pMaterial = This->updateStateBlock->material;
2810 2811 2812 2813 2814 2815 2816 2817
    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);
2818
    TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2819

2820
    return WINED3D_OK;
2821 2822
}

2823 2824 2825
/*****
 * Get / Set Indices
 *****/
2826 2827 2828 2829
static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
        IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
{
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830
    IWineD3DBuffer *oldIdxs;
2831

2832
    TRACE("(%p) : Setting to %p\n", This, pIndexData);
2833 2834 2835 2836
    oldIdxs = This->updateStateBlock->pIndexData;

    This->updateStateBlock->changed.indices = TRUE;
    This->updateStateBlock->pIndexData = pIndexData;
2837
    This->updateStateBlock->IndexFmt = fmt;
2838 2839 2840 2841

    /* Handle recording of state blocks */
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
2842 2843
        if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
        if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2844
        return WINED3D_OK;
2845 2846
    }

2847 2848
    if(oldIdxs != pIndexData) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2849 2850
        if(pIndexData) {
            InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2851
            IWineD3DBuffer_AddRef(pIndexData);
2852 2853 2854
        }
        if(oldIdxs) {
            InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2855
            IWineD3DBuffer_Release(oldIdxs);
2856
        }
2857
    }
2858

2859
    return WINED3D_OK;
2860 2861
}

2862 2863
static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
{
2864 2865 2866
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

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

2868
    /* up ref count on ppindexdata */
2869
    if (*ppIndexData) {
2870
        IWineD3DBuffer_AddRef(*ppIndexData);
2871
        TRACE("(%p) index data set to %p\n", This, ppIndexData);
2872 2873 2874
    }else{
        TRACE("(%p) No index data set\n", This);
    }
2875
    TRACE("Returning %p\n", *ppIndexData);
2876

2877
    return WINED3D_OK;
2878 2879
}

2880
/* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2881
static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895
    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;
    }
2896
    /* The base vertex index affects the stream sources */
2897 2898 2899 2900
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
    return WINED3D_OK;
}

2901
static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2902 2903 2904 2905 2906 2907 2908 2909 2910 2911
    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;
}

2912 2913 2914
/*****
 * Get / Set Viewports
 *****/
2915
static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2916 2917 2918 2919
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

    TRACE("(%p)\n", This);
    This->updateStateBlock->changed.viewport = TRUE;
2920
    This->updateStateBlock->viewport = *pViewport;
2921 2922 2923 2924

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

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

2931
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2932
    return WINED3D_OK;
2933 2934 2935

}

2936
static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2937 2938
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)\n", This);
2939
    *pViewport = This->stateBlock->viewport;
2940
    return WINED3D_OK;
2941 2942
}

2943 2944 2945 2946
/*****
 * Get / Set Render States
 * TODO: Verify against dx9 definitions
 *****/
2947
static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2948 2949

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

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

2954
    This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2955 2956 2957 2958 2959
    This->updateStateBlock->renderState[State] = Value;

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

2963 2964 2965 2966 2967 2968
    /* 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));
    }
2969

2970
    return WINED3D_OK;
2971 2972
}

2973
static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2974
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975
    TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2976
    *pValue = This->stateBlock->renderState[State];
2977
    return WINED3D_OK;
2978 2979
}

2980
/*****
2981
 * Get / Set Sampler States
2982 2983 2984
 * TODO: Verify against dx9 definitions
 *****/

2985
static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2986
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2987 2988 2989 2990 2991 2992 2993 2994
    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);
    }
2995

2996
    if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2997
        ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2998 2999
        return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
    }
3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013
    /**
    * 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(...).
     ******************/
3014

3015
    oldValue = This->stateBlock->samplerState[Sampler][Type];
3016
    This->updateStateBlock->samplerState[Sampler][Type]         = Value;
3017
    This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3018 3019 3020 3021

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

3025 3026 3027 3028 3029
    if(oldValue == Value) {
        TRACE("Application is setting the old value over, nothing to do\n");
        return WINED3D_OK;
    }

3030 3031
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));

3032
    return WINED3D_OK;
3033 3034
}

3035
static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3036
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 3038 3039 3040 3041 3042 3043 3044

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

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

3045
    if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3046
        ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3047 3048
        return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
    }
3049
    *Value = This->stateBlock->samplerState[Sampler][Type];
3050
    TRACE("(%p) : Returning %#x\n", This, *Value);
3051

3052
    return WINED3D_OK;
3053 3054
}

3055
static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3056
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057

3058
    This->updateStateBlock->changed.scissorRect = TRUE;
3059
    if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3060 3061 3062
        TRACE("App is setting the old scissor rectangle over, nothing to do\n");
        return WINED3D_OK;
    }
3063
    CopyRect(&This->updateStateBlock->scissorRect, pRect);
3064 3065 3066 3067 3068 3069

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

3070
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3071

3072
    return WINED3D_OK;
3073 3074
}

3075
static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3076 3077
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

3078
    *pRect = This->updateStateBlock->scissorRect;
3079
    TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3080
    return WINED3D_OK;
3081 3082
}

3083
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3084
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3085
    IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3086

3087 3088
    TRACE("(%p) : pDecl=%p\n", This, pDecl);

3089 3090 3091
    if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
    if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);

3092 3093 3094 3095 3096
    This->updateStateBlock->vertexDecl = pDecl;
    This->updateStateBlock->changed.vertexDecl = TRUE;

    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3097 3098 3099 3100 3101
        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;
3102 3103
    }

3104
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3105
    return WINED3D_OK;
3106 3107
}

3108
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3109 3110 3111
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

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

3113
    *ppDecl = This->stateBlock->vertexDecl;
3114
    if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3115
    return WINED3D_OK;
3116 3117
}

3118
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3119 3120
    IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
    IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3121

3122
    This->updateStateBlock->vertexShader         = pShader;
3123
    This->updateStateBlock->changed.vertexShader = TRUE;
3124

3125
    if (This->isRecordingState) {
3126 3127
        if(pShader) IWineD3DVertexShader_AddRef(pShader);
        if(oldShader) IWineD3DVertexShader_Release(oldShader);
3128
        TRACE("Recording... not performing anything\n");
3129 3130 3131 3132 3133
        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;
3134 3135
    }

3136
    TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3137 3138
    if(pShader) IWineD3DVertexShader_AddRef(pShader);
    if(oldShader) IWineD3DVertexShader_Release(oldShader);
3139 3140 3141

    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);

3142
    return WINED3D_OK;
3143 3144
}

3145
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3146
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 3148

    if (NULL == ppShader) {
3149
        return WINED3DERR_INVALIDCALL;
3150 3151 3152
    }
    *ppShader = This->stateBlock->vertexShader;
    if( NULL != *ppShader)
3153
        IWineD3DVertexShader_AddRef(*ppShader);
3154

3155
    TRACE("(%p) : returning %p\n", This, *ppShader);
3156
    return WINED3D_OK;
3157 3158
}

3159
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3160 3161 3162 3163
    IWineD3DDevice *iface,
    UINT start,
    CONST BOOL *srcData,
    UINT count) {
3164

3165
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3166
    unsigned int i, cnt = min(count, MAX_CONST_B - start);
3167

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

3171
    if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3172

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

3177
    for (i = start; i < cnt + start; ++i) {
3178
        This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3179
    }
3180

3181
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3182

3183
    return WINED3D_OK;
3184 3185
}

3186
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3187 3188 3189 3190
    IWineD3DDevice *iface,
    UINT start,
    BOOL *dstData,
    UINT count) {
3191

3192
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193
    int cnt = min(count, MAX_CONST_B - start);
3194

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

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

3201
    memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3202
    return WINED3D_OK;
3203 3204
}

3205
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3206 3207 3208 3209
    IWineD3DDevice *iface,
    UINT start,
    CONST int *srcData,
    UINT count) {
3210

3211
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212
    unsigned int i, cnt = min(count, MAX_CONST_I - start);
3213

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

3217
    if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3218

3219
    memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3220
    for (i = 0; i < cnt; i++)
3221
        TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3222
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3223 3224

    for (i = start; i < cnt + start; ++i) {
3225
        This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3226 3227
    }

3228
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3229

3230
    return WINED3D_OK;
3231
}
3232

3233
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3234 3235 3236 3237 3238
    IWineD3DDevice *iface,
    UINT start,
    int *dstData,
    UINT count) {

3239
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240
    int cnt = min(count, MAX_CONST_I - start);
3241 3242 3243 3244

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

3245
    if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3246 3247
        return WINED3DERR_INVALIDCALL;

3248
    memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3249
    return WINED3D_OK;
3250
}
3251

3252
static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3253 3254 3255 3256
    IWineD3DDevice *iface,
    UINT start,
    CONST float *srcData,
    UINT count) {
3257

3258
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259
    UINT i;
3260 3261 3262

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

3264
    /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3265
    if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3266 3267
        return WINED3DERR_INVALIDCALL;

3268 3269 3270 3271 3272 3273
    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]);
    }
3274

3275 3276
    if (!This->isRecordingState)
    {
3277
        This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3278 3279
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
    }
3280

3281 3282
    memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
            sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3283 3284 3285 3286

    return WINED3D_OK;
}

3287
static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3288 3289 3290 3291 3292
    IWineD3DDevice *iface,
    UINT start,
    float *dstData,
    UINT count) {

3293
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294
    int cnt = min(count, This->d3d_vshader_constantF - start);
3295

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

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

3302
    memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3303
    return WINED3D_OK;
3304 3305
}

3306 3307
static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
    DWORD i;
3308 3309
    for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
    {
3310 3311 3312 3313
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
    }
}

3314 3315 3316 3317
static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
{
    DWORD i = This->rev_tex_unit_map[unit];
    DWORD j = This->texUnitMap[stage];
3318 3319

    This->texUnitMap[stage] = unit;
3320 3321 3322
    if (i != WINED3D_UNMAPPED_STAGE && i != stage)
    {
        This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3323 3324 3325
    }

    This->rev_tex_unit_map[unit] = stage;
3326 3327 3328
    if (j != WINED3D_UNMAPPED_STAGE && j != unit)
    {
        This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3329 3330 3331
    }
}

3332 3333 3334
static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
    int i;

3335
    This->fixed_function_usage_map = 0;
3336
    for (i = 0; i < MAX_TEXTURES; ++i) {
3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356
        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))) {
3357
            This->fixed_function_usage_map |= (1 << i);
3358 3359 3360
        }

        if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3361
            This->fixed_function_usage_map |= (1 << (i + 1));
3362
        }
3363 3364 3365
    }
}

3366
static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3367
    unsigned int i, tex;
3368
    WORD ffu_map;
3369 3370

    device_update_fixed_function_usage_map(This);
3371
    ffu_map = This->fixed_function_usage_map;
3372

3373
    if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3374 3375 3376 3377
            This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
        for (i = 0; ffu_map; ffu_map >>= 1, ++i)
        {
            if (!(ffu_map & 1)) continue;
3378

3379 3380 3381
            if (This->texUnitMap[i] != i) {
                device_map_stage(This, i, i);
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3382
                markTextureStagesDirty(This, i);
3383 3384 3385 3386 3387
            }
        }
        return;
    }

3388 3389
    /* Now work out the mapping */
    tex = 0;
3390 3391 3392
    for (i = 0; ffu_map; ffu_map >>= 1, ++i)
    {
        if (!(ffu_map & 1)) continue;
3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403

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

        ++tex;
    }
}

3404
static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3405 3406
    const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
            ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3407
    unsigned int i;
3408

3409
    for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3410 3411
        if (sampler_type[i] && This->texUnitMap[i] != i)
        {
3412 3413 3414 3415 3416 3417 3418 3419 3420
            device_map_stage(This, i, i);
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
            if (i < MAX_TEXTURES) {
                markTextureStagesDirty(This, i);
            }
        }
    }
}

3421
static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3422
        const DWORD *vshader_sampler_tokens, DWORD unit)
3423
{
3424
    DWORD current_mapping = This->rev_tex_unit_map[unit];
3425

3426 3427
    /* Not currently used */
    if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3428 3429 3430 3431 3432 3433

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

        if (!pshader_sampler_tokens) {
            /* No pixel shader, check fixed function */
3434
            return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3435 3436 3437 3438 3439 3440 3441
        }

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

    /* Used by a vertex sampler */
3442
    return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3443 3444 3445
}

static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3446 3447 3448
    const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
            ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
    const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3449
    int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3450 3451 3452 3453 3454
    int i;

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

3455 3456
        /* 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. */
3457
        pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3458 3459 3460
    }

    for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3461
        DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3462 3463
        if (vshader_sampler_type[i])
        {
3464 3465
            if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
            {
3466 3467 3468 3469 3470
                /* Already mapped somewhere */
                continue;
            }

            while (start >= 0) {
3471 3472
                if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
                {
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485
                    device_map_stage(This, vsampler_idx, start);
                    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));

                    --start;
                    break;
                }

                --start;
            }
        }
    }
}

3486
void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3487 3488
    BOOL vs = use_vs(This->stateBlock);
    BOOL ps = use_ps(This->stateBlock);
3489
    /*
3490 3491 3492 3493 3494 3495
     * 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
     */
3496 3497
    if (ps) {
        device_map_psamplers(This);
3498
    } else {
3499
        device_map_fixed_function_samplers(This);
3500
    }
3501 3502 3503 3504

    if (vs) {
        device_map_vsamplers(This, ps);
    }
3505 3506
}

3507
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3508
    IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
3509
    IWineD3DPixelShader *oldShader  = This->updateStateBlock->pixelShader;
3510 3511 3512 3513 3514
    This->updateStateBlock->pixelShader         = pShader;
    This->updateStateBlock->changed.pixelShader = TRUE;

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

3518 3519
    if (This->isRecordingState) {
        TRACE("Recording... not performing anything\n");
3520 3521
        if(pShader) IWineD3DPixelShader_AddRef(pShader);
        if(oldShader) IWineD3DPixelShader_Release(oldShader);
3522
        return WINED3D_OK;
3523 3524
    }

3525 3526 3527 3528 3529
    if(pShader == oldShader) {
        TRACE("App is setting the old pixel shader over, nothing to do\n");
        return WINED3D_OK;
    }

3530 3531 3532
    if(pShader) IWineD3DPixelShader_AddRef(pShader);
    if(oldShader) IWineD3DPixelShader_Release(oldShader);

3533
    TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3534
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3535

3536
    return WINED3D_OK;
3537 3538
}

3539
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3540
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3541

3542
    if (NULL == ppShader) {
3543
        WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3544
        return WINED3DERR_INVALIDCALL;
3545 3546
    }

3547
    *ppShader =  This->stateBlock->pixelShader;
3548
    if (NULL != *ppShader) {
3549 3550 3551
        IWineD3DPixelShader_AddRef(*ppShader);
    }
    TRACE("(%p) : returning %p\n", This, *ppShader);
3552
    return WINED3D_OK;
3553 3554
}

3555
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3556 3557 3558 3559
    IWineD3DDevice *iface,
    UINT start,
    CONST BOOL *srcData,
    UINT count) {
3560

3561
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3562
    unsigned int i, cnt = min(count, MAX_CONST_B - start);
3563

3564
    TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3565
            iface, srcData, start, count);
3566

3567
    if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3568

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

3573
    for (i = start; i < cnt + start; ++i) {
3574
        This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3575
    }
3576

3577
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3578

3579
    return WINED3D_OK;
3580 3581
}

3582
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3583 3584 3585 3586
    IWineD3DDevice *iface,
    UINT start,
    BOOL *dstData,
    UINT count) {
3587

3588
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3589
    int cnt = min(count, MAX_CONST_B - start);
3590

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

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

3597
    memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3598
    return WINED3D_OK;
3599 3600
}

3601
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3602 3603 3604 3605
    IWineD3DDevice *iface,
    UINT start,
    CONST int *srcData,
    UINT count) {
3606 3607

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

3610
    TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3611
            iface, srcData, start, count);
3612

3613
    if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3614

3615
    memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3616
    for (i = 0; i < cnt; i++)
3617
        TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3618
           srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3619 3620

    for (i = start; i < cnt + start; ++i) {
3621
        This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3622
    }
3623

3624
    if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3625

3626
    return WINED3D_OK;
3627
}
3628

3629
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3630 3631 3632 3633 3634
    IWineD3DDevice *iface,
    UINT start,
    int *dstData,
    UINT count) {

3635
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3636
    int cnt = min(count, MAX_CONST_I - start);
3637 3638 3639 3640 3641 3642 3643

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

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

3644
    memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3645
    return WINED3D_OK;
3646 3647
}

3648
static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3649 3650 3651 3652 3653
    IWineD3DDevice *iface,
    UINT start,
    CONST float *srcData,
    UINT count) {

3654
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3655
    UINT i;
3656 3657 3658 3659

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

3660
    /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3661
    if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3662 3663
        return WINED3DERR_INVALIDCALL;

3664 3665 3666 3667 3668 3669
    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]);
    }
3670

3671 3672
    if (!This->isRecordingState)
    {
3673
        This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3674 3675
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
    }
3676

3677 3678
    memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
            sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3679 3680 3681 3682

    return WINED3D_OK;
}

3683
static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3684 3685 3686 3687 3688
    IWineD3DDevice *iface,
    UINT start,
    float *dstData,
    UINT count) {

3689
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3690
    int cnt = min(count, This->d3d_pshader_constantF - start);
3691

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

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

3698
    memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3699
    return WINED3D_OK;
3700 3701
}

3702
/* Context activation is done by the caller. */
3703
#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3704
static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3705 3706
        const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
        DWORD DestFVF)
3707
{
3708
    char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3709
    unsigned int i;
3710
    WINED3DVIEWPORT vp;
3711
    WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3712
    BOOL doClip;
3713
    DWORD numTextures;
3714

3715
    if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3716
    {
3717 3718 3719
        WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
    }

3720
    if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3721
    {
3722 3723 3724 3725
        ERR("Source has no position mask\n");
        return WINED3DERR_INVALIDCALL;
    }

3726 3727 3728
    /* We might access VBOs from this code, so hold the lock */
    ENTER_GL();

3729
    if (dest->resource.allocatedMemory == NULL) {
3730
        buffer_get_sysmem(dest);
3731 3732 3733 3734 3735
    }

    /* 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
     */
3736 3737 3738 3739
    if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
    {
        dest->flags |= WINED3D_BUFFER_CREATEBO;
        IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3740 3741
    }

3742 3743
    if (dest->buffer_object)
    {
3744 3745 3746 3747 3748 3749 3750
        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);
3751 3752
        if(!dest_conv_addr) {
            ERR("Out of memory\n");
3753 3754
            /* Continue without storing converted vertices */
        }
3755
        dest_conv = dest_conv_addr;
3756 3757 3758
    }

    /* Should I clip?
3759
     * a) WINED3DRS_CLIPPING is enabled
3760 3761
     * b) WINED3DVOP_CLIP is passed
     */
3762
    if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
        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;
3778
    dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3779 3780

    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3781
                                 WINED3DTS_VIEW,
3782 3783
                                 &view_mat);
    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3784
                                 WINED3DTS_PROJECTION,
3785 3786
                                 &proj_mat);
    IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3787
                                 WINED3DTS_WORLDMATRIX(0),
3788 3789
                                 &world_mat);

3790
    TRACE("View mat:\n");
3791 3792 3793 3794
    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);
3795

3796
    TRACE("Proj mat:\n");
3797 3798 3799 3800
    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);
3801

3802
    TRACE("World mat:\n");
3803 3804 3805 3806
    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);
3807 3808 3809

    /* Get the viewport */
    IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3810
    TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3811 3812 3813 3814 3815
          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);

3816
    numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3817 3818 3819 3820

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

3821 3822
        if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
             ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3823
            /* The position first */
3824 3825
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
            const float *p = (const float *)(element->data + i * element->stride);
3826 3827 3828 3829
            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 */
3830 3831 3832 3833
            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);
3834 3835 3836 3837 3838 3839 3840

            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!
             */

3841
            /* Clipping conditions: From msdn
3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853
             *
             * 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)
             *
             */

3854
            if( !doClip ||
3855
                ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3856
                  (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3857 3858 3859
                  ( rhw > eps ) ) ) {

                /* "Normal" viewport transformation (not clipped)
3860
                 * 1) The values are divided by rhw
3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 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
                 * 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;

3901
                /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916
                 * 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);

3917
            if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3918 3919
                dest_ptr += sizeof(float);
            }
3920 3921 3922 3923 3924 3925 3926 3927 3928 3929

            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);

3930
                if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3931 3932 3933
                    dest_conv += sizeof(float);
                }
            }
3934
        }
3935
        if (DestFVF & WINED3DFVF_PSIZE) {
3936
            dest_ptr += sizeof(DWORD);
3937
            if(dest_conv) dest_conv += sizeof(DWORD);
3938
        }
3939
        if (DestFVF & WINED3DFVF_NORMAL) {
3940 3941
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
            const float *normal = (const float *)(element->data + i * element->stride);
3942 3943 3944
            /* 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));
3945 3946 3947
            if(dest_conv) {
                copy_and_next(dest_conv, normal, 3 * sizeof(float));
            }
3948 3949
        }

3950
        if (DestFVF & WINED3DFVF_DIFFUSE) {
3951 3952
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
            const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3953 3954
            if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
            {
3955 3956
                static BOOL warned = FALSE;

3957
                if(!warned) {
3958 3959 3960 3961 3962 3963
                    ERR("No diffuse color in source, but destination has one\n");
                    warned = TRUE;
                }

                *( (DWORD *) dest_ptr) = 0xffffffff;
                dest_ptr += sizeof(DWORD);
3964 3965 3966 3967 3968

                if(dest_conv) {
                    *( (DWORD *) dest_conv) = 0xffffffff;
                    dest_conv += sizeof(DWORD);
                }
3969
            }
3970
            else {
3971
                copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3972 3973 3974 3975 3976 3977 3978
                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);
                }
            }
3979 3980
        }

3981 3982
        if (DestFVF & WINED3DFVF_SPECULAR)
        {
3983
            /* What's the color value in the feedback buffer? */
3984 3985
            const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
            const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3986 3987
            if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
            {
3988 3989
                static BOOL warned = FALSE;

3990
                if(!warned) {
3991 3992 3993 3994 3995 3996
                    ERR("No specular color in source, but destination has one\n");
                    warned = TRUE;
                }

                *( (DWORD *) dest_ptr) = 0xFF000000;
                dest_ptr += sizeof(DWORD);
3997 3998 3999 4000 4001

                if(dest_conv) {
                    *( (DWORD *) dest_conv) = 0xFF000000;
                    dest_conv += sizeof(DWORD);
                }
4002 4003 4004
            }
            else {
                copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4005 4006 4007 4008 4009 4010
                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);
                }
4011 4012 4013 4014
            }
        }

        for (tex_index = 0; tex_index < numTextures; tex_index++) {
4015 4016
            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);
4017 4018
            if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
            {
4019 4020
                ERR("No source texture, but destination requests one\n");
                dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4021
                if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4022 4023 4024
            }
            else {
                copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4025 4026 4027
                if(dest_conv) {
                    copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
                }
4028 4029 4030 4031
            }
        }
    }

4032
    if(dest_conv) {
4033
        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4034 4035 4036 4037 4038 4039
        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);
4040 4041 4042 4043
    }

    LEAVE_GL();

4044 4045 4046 4047
    return WINED3D_OK;
}
#undef copy_and_next

4048
static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4049 4050
        UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
        DWORD DestFVF)
4051
{
4052
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4053
    struct wined3d_stream_info stream_info;
4054
    BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4055
    TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4056

4057 4058
    if(pVertexDecl) {
        ERR("Output vertex declaration not implemented yet\n");
4059
    }
4060

4061
    /* Need any context to write to the vbo. */
4062
    ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4063

4064 4065 4066 4067
    /* 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;
4068
    device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4069
    This->stateBlock->streamIsUP = streamWasUP;
4070

4071 4072
    if(vbo || SrcStartIndex) {
        unsigned int i;
4073
        /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4074
         * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4075 4076 4077
         *
         * Also get the start index in, but only loop over all elements if there's something to add at all.
         */
4078
        for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4079
        {
4080 4081 4082 4083 4084
            struct wined3d_stream_info_element *e;

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

            e = &stream_info.elements[i];
4085
            if (e->buffer_object)
4086
            {
4087 4088
                struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
                e->buffer_object = 0;
4089
                e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4090 4091 4092 4093 4094
                ENTER_GL();
                GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
                vb->buffer_object = 0;
                LEAVE_GL();
            }
4095
            if (e->data) e->data += e->stride * SrcStartIndex;
4096 4097 4098
        }
    }

4099
    return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4100
            (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4101
}
4102

4103 4104 4105 4106
/*****
 * Get / Set Texture Stage States
 * TODO: Verify against dx9 definitions
 *****/
4107
static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4108
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109
    DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4110

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

4113 4114 4115 4116 4117
    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;
    }

4118
    This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4119 4120
    This->updateStateBlock->textureState[Stage][Type]         = Value;

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

4126 4127 4128 4129 4130 4131
    /* 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;
    }

4132
    if(Stage > This->stateBlock->lowest_disabled_stage &&
4133
       This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4134 4135 4136 4137 4138 4139 4140
        /* 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) {
4141
        unsigned int i;
4142

4143
        if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4144 4145 4146 4147 4148 4149
            /* 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++) {
4150
                TRACE("Additionally dirtifying stage %u\n", i);
4151 4152 4153
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
            }
            This->stateBlock->lowest_disabled_stage = Stage;
4154
            TRACE("New lowest disabled: %u\n", Stage);
4155
        } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166
            /* 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.
             */

            for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
                if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
                    break;
                }
4167
                TRACE("Additionally dirtifying stage %u due to enable\n", i);
4168 4169 4170
                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
            }
            This->stateBlock->lowest_disabled_stage = i;
4171
            TRACE("New lowest disabled: %u\n", i);
4172 4173 4174 4175 4176
        }
    }

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

4177
    return WINED3D_OK;
4178 4179
}

4180
static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4181
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4182
    TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4183
    *pValue = This->updateStateBlock->textureState[Stage][Type];
4184
    return WINED3D_OK;
4185 4186
}

4187
/*****
4188
 * Get / Set Texture
4189
 *****/
4190 4191 4192
static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
        DWORD stage, IWineD3DBaseTexture *texture)
{
4193
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4194
    IWineD3DBaseTexture *prev;
4195

4196
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4197

4198 4199
    if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
        stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4200

4201 4202 4203 4204 4205
    /* 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;
4206 4207
    }

4208
    /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4209
    if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4210
    {
4211
        WARN("Rejecting attempt to set scratch texture.\n");
4212
        return WINED3DERR_INVALIDCALL;
4213 4214
    }

4215
    This->updateStateBlock->changed.textures |= 1 << stage;
4216

4217 4218
    prev = This->updateStateBlock->textures[stage];
    TRACE("Previous texture %p.\n", prev);
4219

4220 4221 4222
    if (texture == prev)
    {
        TRACE("App is setting the same texture again, nothing to do.\n");
4223
        return WINED3D_OK;
4224 4225
    }

4226 4227 4228 4229 4230 4231 4232 4233 4234 4235
    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);

4236 4237 4238
        return WINED3D_OK;
    }

4239 4240 4241 4242 4243
    if (texture)
    {
        IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
        LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
        UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4244

4245
        IWineD3DBaseTexture_AddRef(texture);
4246

4247
        if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4248 4249 4250 4251
        {
            IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
        }

4252 4253 4254 4255 4256 4257 4258
        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));
4259 4260
        }

4261
        if (bind_count == 1) t->baseTexture.sampler = stage;
4262
    }
4263

4264 4265 4266 4267
    if (prev)
    {
        IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
        LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4268

4269 4270 4271 4272 4273 4274
        IWineD3DBaseTexture_Release(prev);

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

4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289
        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;
4290 4291 4292 4293
                    break;
                }
            }
        }
4294 4295
    }

4296
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4297

4298
    return WINED3D_OK;
4299 4300
}

4301
static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4302
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4303 4304 4305 4306 4307 4308

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

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

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

4315
    *ppTexture=This->stateBlock->textures[Stage];
4316 4317
    if (*ppTexture)
        IWineD3DBaseTexture_AddRef(*ppTexture);
4318

4319 4320
    TRACE("(%p) : Returning %p\n", This, *ppTexture);

4321
    return WINED3D_OK;
4322 4323 4324 4325 4326
}

/*****
 * Get Back Buffer
 *****/
4327
static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4328
                                                IWineD3DSurface **ppBackBuffer) {
4329
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4330 4331 4332
    IWineD3DSwapChain *swapChain;
    HRESULT hr;

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

Oliver Stieber's avatar
Oliver Stieber committed
4335
    hr = IWineD3DDeviceImpl_GetSwapChain(iface,  iSwapChain, &swapChain);
4336
    if (hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
4337
        hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4338
            IWineD3DSwapChain_Release(swapChain);
4339
    } else {
Oliver Stieber's avatar
Oliver Stieber committed
4340
        *ppBackBuffer = NULL;
4341
    }
Oliver Stieber's avatar
Oliver Stieber committed
4342
    return hr;
4343 4344
}

4345
static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4346 4347
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    WARN("(%p) : stub, calling idirect3d for now\n", This);
4348
    return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4349 4350
}

4351
static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4352
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4353 4354
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
4355

4356
    if(iSwapChain > 0) {
4357
        hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4358 4359
        if (hr == WINED3D_OK) {
            hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4360
            IWineD3DSwapChain_Release(swapChain);
4361 4362 4363
        } else {
            FIXME("(%p) Error getting display mode\n", This);
        }
4364
    } else {
4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376
        /* 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
4377
    }
4378

Oliver Stieber's avatar
Oliver Stieber committed
4379
    return hr;
4380
}
4381

4382 4383 4384 4385
/*****
 * Stateblock related functions
 *****/

4386
static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4387
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4388 4389
    IWineD3DStateBlock *stateblock;
    HRESULT hr;
4390

4391
    TRACE("(%p)\n", This);
4392

4393
    if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4394

4395 4396
    hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
    if (FAILED(hr)) return hr;
4397

4398
    IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4399
    This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4400
    This->isRecordingState = TRUE;
4401

4402 4403
    TRACE("(%p) recording stateblock %p\n", This, stateblock);

4404
    return WINED3D_OK;
4405 4406
}

4407
static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4408
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4409
    IWineD3DStateBlockImpl *object = This->updateStateBlock;
4410 4411

    if (!This->isRecordingState) {
4412
        WARN("(%p) not recording! returning error\n", This);
4413
        *ppStateBlock = NULL;
4414
        return WINED3DERR_INVALIDCALL;
4415 4416
    }

4417
    stateblock_init_contained_states(object);
4418 4419

    *ppStateBlock = (IWineD3DStateBlock*) object;
4420
    This->isRecordingState = FALSE;
4421
    This->updateStateBlock = This->stateBlock;
4422 4423 4424
    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);
4425
    return WINED3D_OK;
4426 4427
}

4428 4429 4430
/*****
 * Scene related functions
 *****/
4431
static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4432 4433 4434
    /* At the moment we have no need for any functionality at the beginning
       of a scene                                                          */
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4435 4436 4437 4438 4439 4440 4441
    TRACE("(%p)\n", This);

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

4445
static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4446 4447
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    TRACE("(%p)\n", This);
4448 4449 4450 4451 4452 4453

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

4454
    ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4455
    /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4456
    wglFlush();
4457 4458 4459
    /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
     * fails
     */
4460

4461
    This->inScene = FALSE;
4462
    return WINED3D_OK;
4463 4464
}

4465
static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4466
                                          CONST RECT* pSourceRect, CONST RECT* pDestRect,
4467
                                          HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4468
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
Oliver Stieber's avatar
Oliver Stieber committed
4469 4470 4471
    IWineD3DSwapChain *swapChain = NULL;
    int i;
    int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4472

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

4475
    for(i = 0 ; i < swapchains ; i ++) {
4476

4477
        IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
Oliver Stieber's avatar
Oliver Stieber committed
4478 4479
        TRACE("presentinng chain %d, %p\n", i, swapChain);
        IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4480
        IWineD3DSwapChain_Release(swapChain);
4481 4482
    }

4483
    return WINED3D_OK;
4484 4485
}

4486 4487 4488 4489 4490 4491 4492 4493
/* 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;
4494
    const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4495
    UINT drawable_width, drawable_height;
4496
    IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4497
    IWineD3DSwapChainImpl *swapchain = NULL;
4498
    struct wined3d_context *context;
4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533

    /* 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;
        }
    }

4534
    context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4535

4536
    target->get_drawable_size(context, &drawable_width, &drawable_height);
4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548

    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) {
4549
        DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4550 4551 4552 4553 4554
        glDepthMask(GL_TRUE);
        glClearDepth(Z);
        checkGLcall("glClearDepth");
        glMask = glMask | GL_DEPTH_BUFFER_BIT;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4555

4556 4557
        if (vp->X != 0 || vp->Y != 0 ||
                vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4558
            surface_load_ds_location(This->stencilBufferTarget, context, location);
4559 4560 4561 4562 4563
        }
        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)) {
4564
            surface_load_ds_location(This->stencilBufferTarget, context, location);
4565 4566 4567 4568 4569
        }
        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)) {
4570
            surface_load_ds_location(This->stencilBufferTarget, context, location);
4571
        }
4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594
    }

    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);
        }
4595 4596
        if (context->render_offscreen)
        {
4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609
            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 */
4610
            IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627
            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;
            }

4628 4629
            if (context->render_offscreen)
            {
4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656
                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
         */
4657
        IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4658
    }
4659 4660
    if (Flags & WINED3DCLEAR_ZBUFFER) {
        /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4661
        DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4662 4663 4664
        surface_modify_ds_location(This->stencilBufferTarget, location);
    }

4665 4666
    LEAVE_GL();

4667
    if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4668
        if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4669
            wglFlush();
4670 4671 4672 4673
        }
        IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
    }

4674 4675 4676
    return WINED3D_OK;
}

4677
static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4678
                                        DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4679
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4680
    IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4681

4682 4683
    TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
          Count, pRects, Flags, Color, Z, Stencil);
4684

4685 4686 4687 4688 4689 4690
    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;
    }

4691
    return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4692 4693
}

4694 4695 4696
/*****
 * Drawing functions
 *****/
4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721

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)
4722
{
4723 4724
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;

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

4727 4728 4729 4730 4731
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4732 4733 4734 4735 4736 4737
    /* 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;
    }

4738 4739 4740 4741
    if(This->stateBlock->loadBaseVertexIndex != 0) {
        This->stateBlock->loadBaseVertexIndex = 0;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
    }
4742
    /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4743
    drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4744
    return WINED3D_OK;
4745 4746
}

4747
static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4748
{
4749 4750
    IWineD3DDeviceImpl  *This = (IWineD3DDeviceImpl *)iface;
    UINT                 idxStride = 2;
4751
    IWineD3DBuffer *pIB;
4752
    GLuint vbo;
4753

4754 4755 4756 4757 4758 4759
    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. */
4760
        WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4761 4762 4763
        return WINED3DERR_INVALIDCALL;
    }

4764 4765 4766 4767 4768
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4769 4770 4771 4772
    if(This->stateBlock->streamIsUP) {
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
        This->stateBlock->streamIsUP = FALSE;
    }
4773
    vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4774

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

4777
    if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4778 4779 4780 4781 4782
        idxStride = 2;
    } else {
        idxStride = 4;
    }

4783 4784 4785 4786 4787
    if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
        This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
    }

4788 4789
    drawPrimitive(iface, index_count, startIndex, idxStride,
            vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4790

4791
    return WINED3D_OK;
4792 4793
}

4794 4795
static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
        const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4796
{
4797
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798
    IWineD3DBuffer *vb;
4799

4800 4801
    TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
            This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4802

4803 4804 4805 4806 4807
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4808
    /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4809
    vb = This->stateBlock->streamSource[0];
4810 4811
    This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
    if (vb) IWineD3DBuffer_Release(vb);
4812
    This->stateBlock->streamOffset[0] = 0;
4813
    This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4814
    This->stateBlock->streamIsUP = TRUE;
4815
    This->stateBlock->loadBaseVertexIndex = 0;
4816

4817 4818 4819
    /* TODO: Only mark dirty if drawing from a different UP address */
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);

4820
    drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4821 4822

    /* MSDN specifies stream zero settings must be set to NULL */
4823 4824
    This->stateBlock->streamStride[0] = 0;
    This->stateBlock->streamSource[0] = NULL;
4825

4826 4827 4828
    /* 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
     */
4829
    return WINED3D_OK;
4830 4831
}

4832 4833
static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
        UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4834 4835
        const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
{
4836 4837
    int                 idxStride;
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4838
    IWineD3DBuffer *vb;
4839
    IWineD3DBuffer *ib;
4840

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

4844 4845 4846 4847 4848
    if(!This->stateBlock->vertexDecl) {
        WARN("(%p) : Called without a valid vertex declaration set\n", This);
        return WINED3DERR_INVALIDCALL;
    }

4849
    if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4850 4851 4852 4853 4854
        idxStride = 2;
    } else {
        idxStride = 4;
    }

4855
    /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4856
    vb = This->stateBlock->streamSource[0];
4857 4858
    This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
    if (vb) IWineD3DBuffer_Release(vb);
4859
    This->stateBlock->streamIsUP = TRUE;
4860
    This->stateBlock->streamOffset[0] = 0;
4861
    This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4862

4863 4864
    /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
    This->stateBlock->baseVertexIndex = 0;
4865 4866 4867
    This->stateBlock->loadBaseVertexIndex = 0;
    /* Mark the state dirty until we have nicer tracking of the stream source pointers */
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4868
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4869

4870
    drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4871

4872
    /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4873 4874
    This->stateBlock->streamSource[0] = NULL;
    This->stateBlock->streamStride[0] = 0;
4875 4876
    ib = This->stateBlock->pIndexData;
    if(ib) {
4877
        IWineD3DBuffer_Release(ib);
4878 4879
        This->stateBlock->pIndexData = NULL;
    }
4880 4881 4882
    /* 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
     */
4883

4884
    return WINED3D_OK;
4885 4886
}

4887
static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4888
        UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4889
{
4890
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4891

4892 4893 4894 4895
    /* 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.
     */
4896
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4897
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4898
    This->stateBlock->baseVertexIndex = 0;
4899
    This->up_strided = DrawPrimStrideData;
4900
    drawPrimitive(iface, vertex_count, 0, 0, NULL);
4901
    This->up_strided = NULL;
4902 4903
    return WINED3D_OK;
}
4904

4905
static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4906
        UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4907
        UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4908
{
4909
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4910
    DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4911 4912 4913 4914 4915 4916 4917 4918 4919 4920

    /* 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;
4921
    drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4922 4923 4924 4925
    This->up_strided = NULL;
    return WINED3D_OK;
}

4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956
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;
}
4957 4958

/* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4959
static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture,  IWineD3DBaseTexture *pDestinationTexture){
4960
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961
    HRESULT hr = WINED3D_OK;
4962 4963
    WINED3DRESOURCETYPE sourceType;
    WINED3DRESOURCETYPE destinationType;
4964
    int i ,levels;
4965

4966
    /* TODO: think about moving the code into IWineD3DBaseTexture  */
4967

4968
    TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4969

4970
    /* verify that the source and destination textures aren't NULL */
4971
    if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4972
        WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4973
             This, pSourceTexture, pDestinationTexture);
4974
        hr = WINED3DERR_INVALIDCALL;
4975
    }
4976

4977
    if (pSourceTexture == pDestinationTexture) {
4978
        WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4979
             This, pSourceTexture, pDestinationTexture);
4980
        hr = WINED3DERR_INVALIDCALL;
4981
    }
4982 4983 4984
    /* Verify that the source and destination textures are the same type */
    sourceType      = IWineD3DBaseTexture_GetType(pSourceTexture);
    destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4985

4986
    if (sourceType != destinationType) {
4987
        WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4988
             This);
4989
        hr = WINED3DERR_INVALIDCALL;
4990
    }
4991

4992 4993
    /* check that both textures have the identical numbers of levels  */
    if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture)  != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4994
        WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4995
        hr = WINED3DERR_INVALIDCALL;
4996
    }
4997

4998
    if (WINED3D_OK == hr) {
4999
        IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5000 5001

        /* Make sure that the destination texture is loaded */
5002
        pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5003 5004 5005 5006 5007

        /* Update every surface level of the texture */
        levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);

        switch (sourceType) {
5008
        case WINED3DRTYPE_TEXTURE:
5009 5010 5011 5012 5013 5014 5015 5016 5017 5018
            {
                IWineD3DSurface *srcSurface;
                IWineD3DSurface *destSurface;

                for (i = 0 ; i < levels ; ++i) {
                    IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture,      i, &srcSurface);
                    IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
                    hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
                    IWineD3DSurface_Release(srcSurface);
                    IWineD3DSurface_Release(destSurface);
5019
                    if (WINED3D_OK != hr) {
5020 5021 5022 5023 5024 5025
                        WARN("(%p) : Call to update surface failed\n", This);
                        return hr;
                    }
                }
            }
            break;
5026
        case WINED3DRTYPE_CUBETEXTURE:
5027 5028 5029
            {
                IWineD3DSurface *srcSurface;
                IWineD3DSurface *destSurface;
5030
                WINED3DCUBEMAP_FACES faceType;
5031 5032 5033

                for (i = 0 ; i < levels ; ++i) {
                    /* Update each cube face */
5034
                    for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5035
                        hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture,      faceType, i, &srcSurface);
5036
                        if (WINED3D_OK != hr) {
5037 5038 5039 5040 5041
                            FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
                        } else {
                            TRACE("Got srcSurface %p\n", srcSurface);
                        }
                        hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5042
                        if (WINED3D_OK != hr) {
5043 5044 5045 5046 5047 5048 5049
                            FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
                        } else {
                            TRACE("Got desrSurface %p\n", destSurface);
                        }
                        hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
                        IWineD3DSurface_Release(srcSurface);
                        IWineD3DSurface_Release(destSurface);
5050
                        if (WINED3D_OK != hr) {
5051 5052 5053 5054 5055 5056 5057
                            WARN("(%p) : Call to update surface failed\n", This);
                            return hr;
                        }
                    }
                }
            }
            break;
5058

5059
        case WINED3DRTYPE_VOLUMETEXTURE:
5060
            {
5061 5062
                IWineD3DVolume  *srcVolume  = NULL;
                IWineD3DVolume  *destVolume = NULL;
5063 5064

                for (i = 0 ; i < levels ; ++i) {
5065 5066 5067 5068 5069
                    IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture,      i, &srcVolume);
                    IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
                    hr =  IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
                    IWineD3DVolume_Release(srcVolume);
                    IWineD3DVolume_Release(destVolume);
5070
                    if (WINED3D_OK != hr) {
5071 5072 5073 5074 5075 5076
                        WARN("(%p) : Call to update volume failed\n", This);
                        return hr;
                    }
                }
            }
            break;
5077

5078 5079
        default:
            FIXME("(%p) : Unsupported source and destination type\n", This);
5080
            hr = WINED3DERR_INVALIDCALL;
5081
        }
5082 5083
    }

5084
    return hr;
5085
}
5086

5087
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
Oliver Stieber's avatar
Oliver Stieber committed
5088 5089
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
5090
    hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5091
    if(hr == WINED3D_OK) {
Oliver Stieber's avatar
Oliver Stieber committed
5092
        hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5093
                IWineD3DSwapChain_Release(swapChain);
Oliver Stieber's avatar
Oliver Stieber committed
5094 5095
    }
    return hr;
5096 5097
}

5098
static HRESULT  WINAPI  IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5099
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5100 5101 5102
    IWineD3DBaseTextureImpl *texture;
    DWORD i;

5103
    TRACE("(%p) : %p\n", This, pNumPasses);
5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115

    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];
5116
        if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132

        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;
        }
    }

5133 5134
    /* return a sensible default */
    *pNumPasses = 1;
5135 5136

    TRACE("returning D3D_OK\n");
5137
    return WINED3D_OK;
5138
}
5139

5140 5141 5142 5143
static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
{
    int i;

5144 5145 5146 5147 5148 5149 5150
    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));
5151
        }
5152
    }
5153 5154
}

5155
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5156
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5157
    int j;
5158 5159 5160
    UINT NewSize;
    PALETTEENTRY **palettes;

5161
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5162

5163
    if (PaletteNumber >= MAX_PALETTES) {
5164
        ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5165
        return WINED3DERR_INVALIDCALL;
5166
    }
5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189

    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;
        }
    }

5190 5191 5192 5193 5194 5195
    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;
    }
5196
    if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5197
    TRACE("(%p) : returning\n", This);
5198
    return WINED3D_OK;
5199
}
5200

5201
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5202
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5203 5204
    int j;
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5205 5206 5207
    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. */
5208
        ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5209
        return WINED3DERR_INVALIDCALL;
5210 5211 5212 5213 5214 5215 5216 5217
    }
    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);
5218
    return WINED3D_OK;
5219
}
5220

5221
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5222
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223
    TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5224 5225 5226
    /* 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]) {
5227
        ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5228
        return WINED3DERR_INVALIDCALL;
5229 5230
    }
    /*TODO: stateblocks */
5231 5232 5233 5234
    if (This->currentPalette != PaletteNumber) {
        This->currentPalette = PaletteNumber;
        dirtify_p8_texture_samplers(This);
    }
5235
    TRACE("(%p) : returning\n", This);
5236
    return WINED3D_OK;
5237
}
5238

5239
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5240
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5241 5242
    if (PaletteNumber == NULL) {
        WARN("(%p) : returning Invalid Call\n", This);
5243
        return WINED3DERR_INVALIDCALL;
5244 5245 5246 5247
    }
    /*TODO: stateblocks */
    *PaletteNumber = This->currentPalette;
    TRACE("(%p) : returning  %u\n", This, *PaletteNumber);
5248
    return WINED3D_OK;
5249
}
5250

5251
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5252
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 5254 5255
    static BOOL warned;
    if (!warned)
    {
5256
        FIXME("(%p) : stub\n", This);
5257
        warned = TRUE;
5258 5259
    }

5260
    This->softwareVertexProcessing = bSoftware;
5261
    return WINED3D_OK;
5262 5263 5264
}


5265
static BOOL     WINAPI  IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5266
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5267 5268 5269
    static BOOL warned;
    if (!warned)
    {
5270
        FIXME("(%p) : stub\n", This);
5271
        warned = TRUE;
5272
    }
5273
    return This->softwareVertexProcessing;
5274 5275 5276
}


5277
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5278
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5279 5280
    IWineD3DSwapChain *swapChain;
    HRESULT hr;
5281

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

5284
    hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5285
    if(hr == WINED3D_OK){
5286
        hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5287
        IWineD3DSwapChain_Release(swapChain);
5288
    }else{
5289
        FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5290 5291
    }
    return hr;
5292 5293 5294
}


5295
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5296
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5297
    static BOOL warned;
5298
    if(nSegments != 0.0f) {
5299 5300
        if (!warned)
        {
5301
            FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5302
            warned = TRUE;
5303
        }
5304
    }
5305
    return WINED3D_OK;
5306
}
5307

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

5319
static HRESULT  WINAPI  IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5320 5321 5322 5323 5324
    IWineD3DDeviceImpl  *This         = (IWineD3DDeviceImpl *) iface;
    /** TODO: remove casts to IWineD3DSurfaceImpl
     *       NOTE: move code to surface to accomplish this
      ****************************************/
    IWineD3DSurfaceImpl *pSrcSurface  = (IWineD3DSurfaceImpl *)pSourceSurface;
5325
    IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
Mike McCormack's avatar
Mike McCormack committed
5326
    int srcWidth, srcHeight;
5327
    unsigned int  srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5328
    WINED3DFORMAT destFormat, srcFormat;
5329
    UINT          destSize;
5330
    int srcLeft, destLeft, destTop;
5331
    WINED3DPOOL       srcPool, destPool;
5332 5333
    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 */
5334
    const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5335
    GLenum dummy;
5336
    DWORD sampler;
5337 5338
    int bpp;
    CONVERT_TYPES convert = NO_CONVERSION;
5339 5340 5341

    WINED3DSURFACE_DESC  winedesc;

5342
    TRACE("(%p) : Source (%p)  Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5343 5344

    IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5345 5346 5347 5348
    srcSurfaceWidth = winedesc.width;
    srcSurfaceHeight = winedesc.height;
    srcPool = winedesc.pool;
    srcFormat = winedesc.format;
5349 5350

    IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5351 5352 5353 5354 5355
    destSurfaceWidth = winedesc.width;
    destSurfaceHeight = winedesc.height;
    destPool = winedesc.pool;
    destFormat = winedesc.format;
    destSize = winedesc.size;
5356

5357
    if(srcPool != WINED3DPOOL_SYSTEMMEM  || destPool != WINED3DPOOL_DEFAULT){
5358 5359
        WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
        return WINED3DERR_INVALIDCALL;
5360
    }
5361

5362 5363 5364 5365
    /* 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.
     */
5366
    d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5367 5368 5369 5370
    if(convert != NO_CONVERSION) {
        return IWineD3DSurface_BltFast(pDestinationSurface,
                                        pDestPoint  ? pDestPoint->x : 0,
                                        pDestPoint  ? pDestPoint->y : 0,
5371
                                        pSourceSurface, pSourceRect, 0);
5372 5373
    }

5374 5375 5376 5377 5378 5379 5380 5381
    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);
    }

5382
    ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5383

5384 5385 5386 5387
    ENTER_GL();
    GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
    checkGLcall("glActiveTextureARB");
    LEAVE_GL();
5388

5389
    /* Make sure the surface is loaded and up to date */
5390
    surface_internal_preload(pDestinationSurface, SRGB_RGB);
5391
    IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5392

5393
    src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5394
    dst_format_desc = dst_impl->resource.format_desc;
5395

5396 5397
    /* this needs to be done in lines if the sourceRect != the sourceWidth */
    srcWidth   = pSourceRect ? pSourceRect->right - pSourceRect->left   : srcSurfaceWidth;
5398
    srcHeight  = pSourceRect ? pSourceRect->bottom - pSourceRect->top   : srcSurfaceHeight;
5399
    srcLeft    = pSourceRect ? pSourceRect->left : 0;
5400 5401 5402 5403 5404 5405
    destLeft   = pDestPoint  ? pDestPoint->x : 0;
    destTop    = pDestPoint  ? pDestPoint->y : 0;


    /* This function doesn't support compressed textures
    the pitch is just bytesPerPixel * width */
5406
    if(srcWidth != srcSurfaceWidth  || srcLeft ){
5407 5408
        rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
        offset   += srcLeft * src_format_desc->byte_count;
5409 5410 5411 5412 5413
        /* 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){
5414
       offset +=  pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5415
    }
5416
    TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5417
            This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5418
            dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5419 5420 5421

    /* Sanity check */
    if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5422 5423 5424

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

5427 5428
    ENTER_GL();

5429 5430 5431 5432
    /* 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;
5433

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

5437 5438
        for (j = destTop; j < (srcHeight + destTop); ++j)
        {
5439
            glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5440
                    srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5441 5442 5443 5444
            data += rowoffset;
        }

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

5447 5448
        if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
        {
5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459
            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
            {
5460
                GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5461 5462 5463 5464 5465
                        dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
            }
        }
        else
        {
5466
            glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5467
                    srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5468 5469 5470 5471 5472 5473
        }
     }
    checkGLcall("glTexSubImage2D");

    LEAVE_GL();

5474
    IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5475
    sampler = This->rev_tex_unit_map[0];
5476 5477
    if (sampler != WINED3D_UNMAPPED_STAGE)
    {
5478 5479
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
    }
5480

5481
    return WINED3D_OK;
5482 5483
}

5484
static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5485
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5486
    struct WineD3DRectPatch *patch;
5487
    GLenum old_primitive_type;
5488 5489 5490
    unsigned int i;
    struct list *e;
    BOOL found;
5491
    TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5492

5493 5494 5495 5496 5497 5498 5499 5500 5501 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
    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) {
5537
            patch->RectPatchInfo = *pRectPatchInfo;
5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556
        }
        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;
5557 5558
    old_primitive_type = This->stateBlock->gl_primitive_type;
    This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5559
    IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5560
    This->stateBlock->gl_primitive_type = old_primitive_type;
5561 5562 5563 5564 5565 5566 5567 5568
    This->currentPatch = NULL;

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

5571
static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5572
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573
    TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5574
    FIXME("(%p) : Stub\n", This);
5575
    return WINED3D_OK;
5576
}
5577

5578
static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5579
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5580 5581 5582
    int i;
    struct WineD3DRectPatch *patch;
    struct list *e;
5583
    TRACE("(%p) Handle(%d)\n", This, Handle);
5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597

    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 */
5598
    FIXME("Attempt to destroy nonexistent patch\n");
5599
    return WINED3DERR_INVALIDCALL;
5600
}
5601

5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614
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;
}

5615 5616 5617
static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
        const WINED3DRECT *rect, const float color[4])
{
5618
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5619
    struct wined3d_context *context;
5620 5621 5622 5623 5624 5625 5626 5627
    IWineD3DSwapChain *swapchain;

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

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

5628
        context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5629
        ENTER_GL();
5630
        context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5631 5632 5633 5634 5635
        buffer = surface_get_gl_buffer(surface, swapchain);
        glDrawBuffer(buffer);
        checkGLcall("glDrawBuffer()");
    } else {
        TRACE("Surface %p is offscreen\n", surface);
5636

5637
        context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5638
        ENTER_GL();
5639 5640 5641
        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);
5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652
    }

    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");
5653
        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5654 5655 5656
    } else {
        glDisable(GL_SCISSOR_TEST);
    }
5657 5658 5659 5660
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));

    glDisable(GL_BLEND);
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5661 5662 5663 5664

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

5665
    glClearColor(color[0], color[1], color[2], color[3]);
5666 5667 5668 5669 5670 5671 5672 5673
    glClear(GL_COLOR_BUFFER_BIT);
    checkGLcall("glClear");

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

    LEAVE_GL();
5676 5677
}

5678 5679 5680 5681
static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
    unsigned int r, g, b, a;
    DWORD ret;

5682 5683 5684
    if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
            || destfmt == WINED3DFMT_B8G8R8X8_UNORM
            || destfmt == WINED3DFMT_B8G8R8_UNORM)
5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695
        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)
    {
5696
        case WINED3DFMT_B5G6R5_UNORM:
5697 5698 5699 5700 5701 5702 5703 5704 5705 5706
            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;

5707 5708
        case WINED3DFMT_B5G5R5X1_UNORM:
        case WINED3DFMT_B5G5R5A1_UNORM:
5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719
            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;

5720
        case WINED3DFMT_A8_UNORM:
5721 5722 5723
            TRACE("Returning %08x\n", a);
            return a;

5724 5725
        case WINED3DFMT_B4G4R4X4_UNORM:
        case WINED3DFMT_B4G4R4A4_UNORM:
5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736
            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;

5737
        case WINED3DFMT_B2G3R3_UNORM:
5738 5739 5740 5741 5742 5743 5744 5745 5746
            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;

5747
        case WINED3DFMT_R8G8B8X8_UNORM:
5748
        case WINED3DFMT_R8G8B8A8_UNORM:
5749 5750 5751 5752 5753 5754 5755
            ret  = a << 24;
            ret |= b << 16;
            ret |= g <<  8;
            ret |= r <<  0;
            TRACE("Returning %08x\n", ret);
            return ret;

5756
        case WINED3DFMT_B10G10R10A2_UNORM:
5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767
            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;

5768
        case WINED3DFMT_R10G10B10A2_UNORM:
5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785
            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;
    }
}

5786
static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5787 5788
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5789
    WINEDDBLTFX BltFx;
5790
    TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5791

5792 5793
    if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
        FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5794
        return WINED3DERR_INVALIDCALL;
5795
    }
5796

5797
    if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5798 5799
        const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
        color_fill_fbo(iface, pSurface, pRect, c);
5800
        return WINED3D_OK;
5801 5802 5803 5804
    } else {
        /* Just forward this to the DirectDraw blitting engine */
        memset(&BltFx, 0, sizeof(BltFx));
        BltFx.dwSize = sizeof(BltFx);
5805
        BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5806
        return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5807
                WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5808
    }
5809 5810
}

5811 5812 5813 5814 5815 5816 5817 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
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");

5845 5846 5847 5848
        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;
5849 5850 5851 5852

        /* Just forward this to the DirectDraw blitting engine */
        memset(&BltFx, 0, sizeof(BltFx));
        BltFx.dwSize = sizeof(BltFx);
5853
        BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5854
        hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5855 5856 5857 5858 5859 5860 5861 5862 5863
        if (FAILED(hr))
        {
            ERR("Blt failed, hr %#x\n", hr);
        }
    }

    IWineD3DResource_Release(resource);
}

5864
/* rendertarget and depth stencil functions */
5865
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5866
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5867

5868 5869 5870 5871
    if (RenderTargetIndex >= GL_LIMITS(buffers)) {
        ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
        return WINED3DERR_INVALIDCALL;
    }
5872

5873
    *ppRenderTarget = This->render_targets[RenderTargetIndex];
5874
    TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5875 5876 5877
    /* Note inc ref on returned surface */
    if(*ppRenderTarget != NULL)
        IWineD3DSurface_AddRef(*ppRenderTarget);
5878
    return WINED3D_OK;
5879
}
5880

5881
static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895
    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;
    }

5896 5897 5898
    /* Make sure to release the swapchain */
    IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);

5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911
    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)
5912
        {
5913
            IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5914 5915
            ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
        }
5916 5917 5918 5919
        Swapchain->frontBuffer = Front;

        if(Swapchain->frontBuffer) {
            IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5920
            ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5921 5922
        }
    }
5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933

    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) {
5934
        TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5935 5936 5937 5938

        /* 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
         */
5939 5940
        WARN("No active context?\n");

5941
        ENTER_GL();
5942
        if(!Swapchain->backBuffer[0]) {
5943 5944 5945 5946 5947
            /* GL was told to draw to the front buffer at creation,
             * undo that
             */
            glDrawBuffer(GL_BACK);
            checkGLcall("glDrawBuffer(GL_BACK)");
5948 5949
            /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
            Swapchain->presentParms.BackBufferCount = 1;
5950 5951 5952 5953
        } else if (!Back) {
            /* That makes problems - disable for now */
            /* glDrawBuffer(GL_FRONT); */
            checkGLcall("glDrawBuffer(GL_FRONT)");
5954 5955
            /* We have lost our back buffer, set this to 0 to avoid confusing other code */
            Swapchain->presentParms.BackBufferCount = 0;
5956 5957 5958
        }
        LEAVE_GL();

5959
        if(Swapchain->backBuffer[0])
5960
        {
5961
            IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5962 5963
            ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
        }
5964
        Swapchain->backBuffer[0] = Back;
5965

5966 5967
        if(Swapchain->backBuffer[0]) {
            IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5968
            ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5969 5970
        } else {
            HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5971
            Swapchain->backBuffer = NULL;
5972 5973 5974 5975 5976
        }

    }

    return WINED3D_OK;
5977 5978
}

5979
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5980
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5981
    *ppZStencilSurface = This->stencilBufferTarget;
5982
    TRACE("(%p) : zStencilSurface  returning %p\n", This,  *ppZStencilSurface);
5983

5984 5985 5986
    if(*ppZStencilSurface != NULL) {
        /* Note inc ref on returned surface */
        IWineD3DSurface_AddRef(*ppZStencilSurface);
5987 5988 5989
        return WINED3D_OK;
    } else {
        return WINED3DERR_NOTFOUND;
5990
    }
5991 5992
}

5993
void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5994 5995
        IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
{
5996 5997
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5998
    IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5999
    const struct wined3d_gl_info *gl_info;
6000
    struct wined3d_context *context;
6001
    GLenum gl_filter;
6002
    POINT offset = {0, 0};
6003

6004 6005 6006 6007
    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);
6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022

    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 */
6023
    src_swapchain = get_swapchain(src_surface);
6024 6025
    dst_swapchain = get_swapchain(dst_surface);

6026 6027 6028
    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);
6029

6030 6031
    gl_info = context->gl_info;

6032
    if (src_swapchain) {
6033
        GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6034

6035
        TRACE("Source surface %p is onscreen\n", src_surface);
6036 6037 6038
        /* 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);
6039

6040 6041 6042
        if(buffer == GL_FRONT) {
            RECT windowsize;
            UINT h;
6043 6044
            ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
            GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6045 6046 6047 6048 6049 6050 6051 6052 6053
            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;
        }

6054
        ENTER_GL();
6055
        context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6056 6057
        glReadBuffer(buffer);
        checkGLcall("glReadBuffer()");
6058
    } else {
6059
        TRACE("Source surface %p is offscreen\n", src_surface);
6060
        ENTER_GL();
6061 6062 6063
        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);
6064
        checkGLcall("glReadBuffer()");
6065
        context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6066
    }
6067
    LEAVE_GL();
6068 6069

    /* Attach dst surface to dst fbo */
6070
    if (dst_swapchain) {
6071
        GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6072

6073
        TRACE("Destination surface %p is onscreen\n", dst_surface);
6074 6075 6076
        /* 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);
6077

6078 6079 6080
        if(buffer == GL_FRONT) {
            RECT windowsize;
            UINT h;
6081 6082
            ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
            GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6083 6084 6085 6086 6087 6088 6089 6090 6091 6092
            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;
        }

6093
        ENTER_GL();
6094
        context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6095 6096
        glDrawBuffer(buffer);
        checkGLcall("glDrawBuffer()");
6097
    } else {
6098
        TRACE("Destination surface %p is offscreen\n", dst_surface);
6099

6100
        ENTER_GL();
6101 6102 6103
        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);
6104
        checkGLcall("glDrawBuffer()");
6105
        context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6106
    }
6107 6108
    glDisable(GL_SCISSOR_TEST);
    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6109 6110

    if (flip) {
6111 6112
        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);
6113
        checkGLcall("glBlitFramebuffer()");
6114
    } else {
6115 6116
        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);
6117
        checkGLcall("glBlitFramebuffer()");
6118 6119
    }

6120 6121
    IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);

6122 6123 6124 6125 6126
    /* 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()");
6127
    }
6128
    LEAVE_GL();
6129 6130
}

6131
static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6132
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6133
    int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
6134

6135 6136 6137
    TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);

    if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6138 6139
        WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
             This, RenderTargetIndex, GL_LIMITS(buffers));
6140
        return WINED3DERR_INVALIDCALL;
6141 6142 6143
    }

    /* MSDN says that null disables the render target
6144
    but a device must always be associated with a render target
6145 6146 6147 6148
    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");
6149
        return WINED3DERR_INVALIDCALL;
6150
    }
6151
    if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6152
        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);
6153
        return WINED3DERR_INVALIDCALL;
6154
    }
6155

6156
    /* If we are trying to set what we already have, don't bother */
6157
    if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6158
        TRACE("Trying to do a NOP SetRenderTarget operation\n");
6159
        return WINED3D_OK;
6160
    }
6161 6162 6163
    if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
    if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
    This->render_targets[RenderTargetIndex] = pRenderTarget;
6164

6165
    /* Render target 0 is special */
6166
    if(RenderTargetIndex == 0 && dxVersion > 7) {
6167 6168 6169
        /* 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.
6170 6171 6172 6173 6174 6175 6176 6177
         */
        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);
6178 6179 6180 6181 6182 6183

        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);
6184
    }
6185
    return WINED3D_OK;
6186 6187
}

6188
static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6189
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6190
    HRESULT  hr = WINED3D_OK;
6191 6192
    IWineD3DSurface *tmp;

6193
    TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6194

6195
    if (pNewZStencil == This->stencilBufferTarget) {
6196
        TRACE("Trying to do a NOP SetRenderTarget operation\n");
6197
    } else {
6198
        /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6199
        * depending on the renter target implementation being used.
6200
        * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6201
        * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6202
        * stencil buffer and incur an extra memory overhead
6203 6204
         ******************************************************/

6205
        if (This->stencilBufferTarget) {
6206 6207 6208 6209
            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 {
6210
                struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6211
                surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6212 6213
                surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
            }
6214 6215
        }

6216 6217 6218 6219 6220
        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);
6221
        hr = WINED3D_OK;
6222

6223 6224 6225 6226 6227 6228
        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));
        }
6229 6230 6231 6232 6233
    }

    return hr;
}

6234
static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6235
                                                        UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6236
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6237
    /* TODO: the use of Impl is deprecated. */
6238
    IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6239
    WINED3DLOCKED_RECT lockedRect;
6240 6241 6242

    TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);

6243
    /* some basic validation checks */
6244
    if(This->cursorTexture) {
6245
        ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6246
        ENTER_GL();
6247 6248 6249 6250 6251
        glDeleteTextures(1, &This->cursorTexture);
        LEAVE_GL();
        This->cursorTexture = 0;
    }

6252 6253 6254 6255 6256
    if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
        This->haveHardwareCursor = TRUE;
    else
        This->haveHardwareCursor = FALSE;

6257
    if(pCursorBitmap) {
6258 6259
        WINED3DLOCKED_RECT rect;

6260
        /* MSDN: Cursor must be A8R8G8B8 */
6261
        if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6262
        {
6263 6264 6265 6266 6267 6268 6269
            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) {
6270
            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);
6271 6272 6273
            return WINED3DERR_INVALIDCALL;
        }

6274 6275
        if (!This->haveHardwareCursor) {
            /* TODO: MSDN: Cursor sizes must be a power of 2 */
6276

6277 6278 6279 6280 6281 6282 6283 6284 6285 6286
            /* 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)))
            {
6287 6288
                const struct GlPixelFormatDesc *glDesc =
                        getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, &GLINFO_LOCATION);
6289
                char *mem, *bits = rect.pBits;
6290 6291 6292
                GLint intfmt = glDesc->glInternal;
                GLint format = glDesc->glFormat;
                GLint type = glDesc->glType;
6293 6294
                INT height = This->cursorHeight;
                INT width = This->cursorWidth;
6295
                INT bpp = glDesc->byte_count;
6296 6297
                DWORD sampler;
                INT i;
6298 6299 6300 6301 6302 6303 6304

                /* 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);
6305

6306
                ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6307

6308 6309 6310 6311 6312 6313
                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)");
                }
6314

6315
                /* Make sure that a proper texture unit is selected */
6316 6317
                GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
                checkGLcall("glActiveTextureARB");
6318
                sampler = This->rev_tex_unit_map[0];
6319 6320
                if (sampler != WINED3D_UNMAPPED_STAGE)
                {
6321 6322
                    IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
                }
6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336
                /* 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)");
                }
6337

6338
                LEAVE_GL();
6339
            }
6340 6341 6342 6343
            else
            {
                FIXME("A cursor texture was not returned.\n");
                This->cursorTexture = 0;
6344
            }
6345 6346 6347
        }
        else
        {
6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380
            /* 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;
            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);
            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);
6381
        }
6382
    }
6383

6384 6385
    This->xHotSpot = XHotSpot;
    This->yHotSpot = YHotSpot;
6386
    return WINED3D_OK;
6387 6388
}

6389
static void     WINAPI  IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6390 6391
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6392

6393 6394
    This->xScreenSpace = XScreenSpace;
    This->yScreenSpace = YScreenSpace;
6395

6396 6397 6398 6399
    return;

}

6400
static BOOL     WINAPI  IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6401
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6402
    BOOL oldVisible = This->bCursorVisible;
6403 6404
    POINT pt;

6405
    TRACE("(%p) : visible(%d)\n", This, bShow);
6406

6407 6408 6409 6410 6411 6412 6413 6414
    /*
     * 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;
6415

6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428
    if (This->haveHardwareCursor) {
        This->bCursorVisible = bShow;
        if (bShow)
            SetCursor(This->hardwareCursor);
        else
            SetCursor(NULL);
    }
    else
    {
        if (This->cursorTexture)
            This->bCursorVisible = bShow;
    }

6429
    return oldVisible;
6430 6431
}

6432
static HRESULT  WINAPI  IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6433
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6434
    IWineD3DResourceImpl *resource;
6435
    TRACE("(%p) : state (%u)\n", This, This->state);
6436

Austin English's avatar
Austin English committed
6437
    /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6438
    switch (This->state) {
6439 6440 6441
    case WINED3D_OK:
        return WINED3D_OK;
    case WINED3DERR_DEVICELOST:
6442
        {
6443 6444 6445
            LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
                if (resource->resource.pool == WINED3DPOOL_DEFAULT)
                    return WINED3DERR_DEVICENOTRESET;
6446
            }
6447
            return WINED3DERR_DEVICELOST;
6448
        }
6449 6450
    case WINED3DERR_DRIVERINTERNALERROR:
        return WINED3DERR_DRIVERINTERNALERROR;
6451 6452 6453
    }

    /* Unknown state */
6454
    return WINED3DERR_DRIVERINTERNALERROR;
6455 6456
}

6457 6458 6459 6460 6461 6462 6463 6464 6465
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;
}
6466

6467
static HRESULT  WINAPI  IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6468
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6469 6470 6471
    TRACE("(%p)\n", This);

    IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6472
    return WINED3D_OK;
6473 6474
}

6475 6476
static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
{
6477 6478
    IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */

6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489
    /* 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;
    }
6490 6491
    surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
    surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6492 6493
    if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
        GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6494 6495
        surface->pow2Width = pPresentationParameters->BackBufferWidth;
        surface->pow2Height = pPresentationParameters->BackBufferHeight;
6496 6497
    } else {
        surface->pow2Width = surface->pow2Height = 1;
6498 6499
        while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
        while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6500
    }
6501 6502 6503 6504 6505
    surface->glRect.left = 0;
    surface->glRect.top = 0;
    surface->glRect.right = surface->pow2Width;
    surface->glRect.bottom = surface->pow2Height;

6506 6507
    if (surface->texture_name)
    {
6508
        ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6509
        ENTER_GL();
6510
        glDeleteTextures(1, &surface->texture_name);
6511
        LEAVE_GL();
6512
        surface->texture_name = 0;
6513
        surface->Flags &= ~SFLAG_CLIENT;
6514
    }
6515 6516
    if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
       surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6517 6518 6519 6520
        surface->Flags |= SFLAG_NONPOW2;
    } else  {
        surface->Flags &= ~SFLAG_NONPOW2;
    }
6521 6522 6523
    HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
    surface->resource.allocatedMemory = NULL;
    surface->resource.heapMemory = NULL;
6524
    surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6525 6526 6527 6528 6529 6530
    /* 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);
    }
6531 6532
}

6533 6534 6535 6536 6537 6538 6539
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;
}

6540 6541
static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
{
6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566
    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;
}

6567 6568 6569
void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
    IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6570 6571
    const struct wined3d_context *context;
    const struct wined3d_gl_info *gl_info;
6572 6573 6574
    UINT i;
    IWineD3DBaseShaderImpl *shader;

6575 6576
    context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
    gl_info = context->gl_info;
6577

6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588
    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) {
6589
        gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6590 6591 6592 6593
        This->depth_blt_rb = 0;
        This->depth_blt_rb_w = 0;
        This->depth_blt_rb_h = 0;
    }
6594 6595
    LEAVE_GL();

6596
    This->blitter->free_private(iface);
6597 6598 6599
    This->frag_pipe->free_private(iface);
    This->shader_backend->shader_free_private(iface);

6600
    ENTER_GL();
6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 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
    for (i = 0; i < GL_LIMITS(textures); i++) {
        /* 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");
6639
        goto err_out;
6640 6641 6642 6643
    }
    hr = This->frag_pipe->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Fragment pipeline private data couldn't be allocated\n");
6644 6645 6646 6647 6648 6649
        goto err_out;
    }
    hr = This->blitter->alloc_private(iface);
    if(FAILED(hr)) {
        TRACE("Blitter private data couldn't be allocated\n");
        goto err_out;
6650 6651 6652
    }

    return WINED3D_OK;
6653 6654 6655 6656 6657 6658

err_out:
    This->blitter->free_private(iface);
    This->frag_pipe->free_private(iface);
    This->shader_backend->shader_free_private(iface);
    return hr;
6659 6660
}

6661
static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6662
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674
    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;
    }

6675 6676 6677 6678
    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);
6679
        IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6680 6681 6682
        return WINED3DERR_INVALIDCALL;
    }

6683 6684 6685 6686 6687 6688 6689 6690
    /* 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");
6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703
    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);
6704 6705

    /* No special treatment of these parameters. Just store them */
6706 6707 6708 6709
    swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
    swapchain->presentParms.Flags = pPresentationParameters->Flags;
    swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
    swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6710 6711

    /* What to do about these? */
6712 6713
    if(pPresentationParameters->BackBufferCount != 0 &&
        pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6714 6715
        ERR("Cannot change the back buffer count yet\n");
    }
6716 6717
    if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
        pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6718 6719
        ERR("Cannot change the back buffer format yet\n");
    }
6720 6721
    if(pPresentationParameters->hDeviceWindow != NULL &&
        pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6722 6723
        ERR("Cannot change the device window yet\n");
    }
6724
    if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743
        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;
        }
6744
    }
6745

6746 6747 6748 6749 6750 6751
    /* Reset the depth stencil */
    if (pPresentationParameters->EnableAutoDepthStencil)
        IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
    else
        IWineD3DDevice_SetDepthStencilSurface(iface, NULL);

6752 6753 6754 6755
    TRACE("Resetting stateblock\n");
    IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
    IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);

6756
    delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6757

6758
    if(pPresentationParameters->Windowed) {
6759 6760 6761 6762 6763
        mode.Width = swapchain->orig_width;
        mode.Height = swapchain->orig_height;
        mode.RefreshRate = 0;
        mode.Format = swapchain->presentParms.BackBufferFormat;
    } else {
6764 6765 6766
        mode.Width = pPresentationParameters->BackBufferWidth;
        mode.Height = pPresentationParameters->BackBufferHeight;
        mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6767 6768 6769 6770
        mode.Format = swapchain->presentParms.BackBufferFormat;
    }

    /* Should Width == 800 && Height == 0 set 800x600? */
6771 6772 6773
    if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
       (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
        pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6774
    {
6775
        UINT i;
6776

6777
        if(!pPresentationParameters->Windowed) {
6778 6779
            DisplayModeChanged = TRUE;
        }
6780 6781
        swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
        swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6782 6783 6784 6785 6786

        updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
        for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
            updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
        }
6787 6788 6789
        if(This->auto_depth_stencil_buffer) {
            updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
        }
6790 6791
    }

6792 6793
    if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
       (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6794
        DisplayModeChanged) {
6795

6796
        IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6797

6798
        if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6799 6800
            if(swapchain->presentParms.Windowed) {
                /* switch from windowed to fs */
6801
                IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6802 6803 6804 6805
                                                         pPresentationParameters->BackBufferWidth,
                                                         pPresentationParameters->BackBufferHeight);
            } else {
                /* Fullscreen -> fullscreen mode change */
6806 6807 6808
                MoveWindow(swapchain->win_handle, 0, 0,
                           pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
                           TRUE);
6809
            }
6810
        } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6811
            /* Fullscreen -> windowed switch */
6812
            IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6813 6814
        }
        swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6815 6816 6817 6818 6819 6820 6821 6822
    } 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;
6823
        IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6824 6825
                                                 pPresentationParameters->BackBufferWidth,
                                                 pPresentationParameters->BackBufferHeight);
6826 6827
        This->style = style;
        This->exStyle = exStyle;
6828
    }
6829 6830 6831 6832 6833 6834 6835 6836

    /* 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);

6837 6838 6839 6840
    hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
    if(FAILED(hr)) {
        ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
    }
6841

6842 6843
    hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
    IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6844

6845 6846 6847
    /* All done. There is no need to reload resources or shaders, this will happen automatically on the
     * first use
     */
6848
    return hr;
6849 6850
}

6851
static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6852 6853
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
    /** FIXME: always true at the moment **/
6854
    if(!bEnableDialogs) {
6855 6856
        FIXME("(%p) Dialogs cannot be disabled yet\n", This);
    }
6857
    return WINED3D_OK;
6858 6859 6860
}


6861
static HRESULT  WINAPI  IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6862
    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6863
    TRACE("(%p) : pParameters %p\n", This, pParameters);
6864

6865
    *pParameters = This->createParms;
6866
    return WINED3D_OK;
6867 6868
}

6869
static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
Oliver Stieber's avatar
Oliver Stieber committed
6870 6871 6872 6873
    IWineD3DSwapChain *swapchain;

    TRACE("Relaying  to swapchain\n");

6874
    if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6875
        IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6876
        IWineD3DSwapChain_Release(swapchain);
Oliver Stieber's avatar
Oliver Stieber committed
6877
    }
6878 6879 6880
    return;
}

6881
static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
Oliver Stieber's avatar
Oliver Stieber committed
6882
    IWineD3DSwapChain *swapchain;
6883

Oliver Stieber's avatar
Oliver Stieber committed
6884 6885
    TRACE("Relaying  to swapchain\n");

6886 6887
    if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
        IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6888
        IWineD3DSwapChain_Release(swapchain);
Oliver Stieber's avatar
Oliver Stieber committed
6889
    }
6890
    return;
6891 6892
}

6893 6894 6895 6896 6897 6898

/** ********************************************************
*   Notification functions
** ********************************************************/
/** This function must be called in the release of a resource when ref == 0,
* the contents of resource must still be correct,
6899
* any handles to other resource held by the caller must be closed
6900 6901
* (e.g. a texture should release all held surfaces because telling the device that it's been released.)
 *****************************************************/
6902 6903 6904
void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
{
    TRACE("(%p) : Adding resource %p\n", This, resource);
6905

6906
    list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6907 6908
}

6909 6910
static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
{
6911
    TRACE("(%p) : Removing resource %p\n", This, resource);
6912

6913
    list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6914 6915
}

6916 6917
void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
{
6918
    WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6919 6920 6921
    int counter;

    TRACE("(%p) : resource %p\n", This, resource);
6922

6923
    context_resource_released((IWineD3DDevice *)This, resource, type);
6924 6925

    switch (type) {
6926
        /* TODO: check front and back buffers, rendertargets etc..  possibly swapchains? */
6927 6928 6929
        case WINED3DRTYPE_SURFACE: {
            unsigned int i;

6930 6931
            if (This->d3d_initialized)
            {
6932
                for (i = 0; i < GL_LIMITS(buffers); ++i) {
6933 6934
                    if (This->render_targets[i] == (IWineD3DSurface *)resource) {
                        This->render_targets[i] = NULL;
6935 6936
                    }
                }
6937 6938 6939
                if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
                    This->stencilBufferTarget = NULL;
                }
6940 6941 6942 6943
            }

            break;
        }
6944 6945 6946
        case WINED3DRTYPE_TEXTURE:
        case WINED3DRTYPE_CUBETEXTURE:
        case WINED3DRTYPE_VOLUMETEXTURE:
6947
                for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6948
                    if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6949
                        WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6950 6951 6952 6953
                        This->stateBlock->textures[counter] = NULL;
                    }
                    if (This->updateStateBlock != This->stateBlock ){
                        if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6954
                            WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6955 6956 6957 6958 6959
                            This->updateStateBlock->textures[counter] = NULL;
                        }
                    }
                }
        break;
6960
        case WINED3DRTYPE_VOLUME:
6961 6962
        /* TODO: nothing really? */
        break;
6963
        case WINED3DRTYPE_BUFFER:
6964 6965 6966 6967 6968 6969 6970 6971 6972 6973
        {
            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) {
6974
                        FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6975 6976 6977 6978
                        This->updateStateBlock->streamSource[streamNumber] = 0;
                        /* Set changed flag? */
                    }
                }
6979
                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) */
6980
                    if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6981
                        TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6982 6983 6984 6985
                        This->stateBlock->streamSource[streamNumber] = 0;
                    }
                }
            }
6986 6987

            if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6988
                if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6989 6990
                    This->updateStateBlock->pIndexData =  NULL;
                }
6991
            }
6992
            if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6993
                if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6994 6995
                    This->stateBlock->pIndexData =  NULL;
                }
6996 6997 6998
            }
        }
        break;
6999

7000
        default:
7001
        FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7002 7003 7004 7005
        break;
    }


7006
    /* Remove the resource from the resourceStore */
7007
    device_resource_remove(This, resource);
7008 7009 7010 7011 7012

    TRACE("Resource released\n");

}

7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030
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;
}

7031 7032 7033 7034
/**********************************************************
 * IWineD3DDevice VTbl follows
 **********************************************************/

7035
const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7036
{
7037
    /*** IUnknown methods ***/
7038 7039
    IWineD3DDeviceImpl_QueryInterface,
    IWineD3DDeviceImpl_AddRef,
7040
    IWineD3DDeviceImpl_Release,
7041
    /*** IWineD3DDevice methods ***/
7042
    IWineD3DDeviceImpl_GetParent,
7043
    /*** Creation methods**/
7044
    IWineD3DDeviceImpl_CreateBuffer,
7045
    IWineD3DDeviceImpl_CreateVertexBuffer,
7046
    IWineD3DDeviceImpl_CreateIndexBuffer,
7047
    IWineD3DDeviceImpl_CreateStateBlock,
7048
    IWineD3DDeviceImpl_CreateSurface,
7049
    IWineD3DDeviceImpl_CreateRendertargetView,
7050 7051 7052 7053
    IWineD3DDeviceImpl_CreateTexture,
    IWineD3DDeviceImpl_CreateVolumeTexture,
    IWineD3DDeviceImpl_CreateVolume,
    IWineD3DDeviceImpl_CreateCubeTexture,
7054
    IWineD3DDeviceImpl_CreateQuery,
7055
    IWineD3DDeviceImpl_CreateSwapChain,
7056
    IWineD3DDeviceImpl_CreateVertexDeclaration,
7057
    IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7058 7059
    IWineD3DDeviceImpl_CreateVertexShader,
    IWineD3DDeviceImpl_CreatePixelShader,
7060
    IWineD3DDeviceImpl_CreatePalette,
7061
    /*** Odd functions **/
7062
    IWineD3DDeviceImpl_Init3D,
7063
    IWineD3DDeviceImpl_InitGDI,
7064
    IWineD3DDeviceImpl_Uninit3D,
7065
    IWineD3DDeviceImpl_UninitGDI,
7066
    IWineD3DDeviceImpl_SetMultithreaded,
7067
    IWineD3DDeviceImpl_EvictManagedResources,
7068 7069 7070 7071 7072 7073
    IWineD3DDeviceImpl_GetAvailableTextureMem,
    IWineD3DDeviceImpl_GetBackBuffer,
    IWineD3DDeviceImpl_GetCreationParameters,
    IWineD3DDeviceImpl_GetDeviceCaps,
    IWineD3DDeviceImpl_GetDirect3D,
    IWineD3DDeviceImpl_GetDisplayMode,
7074
    IWineD3DDeviceImpl_SetDisplayMode,
7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093
    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,
7094
    IWineD3DDeviceImpl_GetGammaRamp,
7095
    IWineD3DDeviceImpl_SetIndexBuffer,
7096
    IWineD3DDeviceImpl_GetIndexBuffer,
7097
    IWineD3DDeviceImpl_SetBaseVertexIndex,
7098
    IWineD3DDeviceImpl_GetBaseVertexIndex,
7099 7100 7101 7102 7103 7104
    IWineD3DDeviceImpl_SetLight,
    IWineD3DDeviceImpl_GetLight,
    IWineD3DDeviceImpl_SetLightEnable,
    IWineD3DDeviceImpl_GetLightEnable,
    IWineD3DDeviceImpl_SetMaterial,
    IWineD3DDeviceImpl_GetMaterial,
7105
    IWineD3DDeviceImpl_SetNPatchMode,
7106
    IWineD3DDeviceImpl_GetNPatchMode,
7107 7108 7109 7110 7111 7112 7113 7114 7115 7116
    IWineD3DDeviceImpl_SetPaletteEntries,
    IWineD3DDeviceImpl_GetPaletteEntries,
    IWineD3DDeviceImpl_SetPixelShader,
    IWineD3DDeviceImpl_GetPixelShader,
    IWineD3DDeviceImpl_SetPixelShaderConstantB,
    IWineD3DDeviceImpl_GetPixelShaderConstantB,
    IWineD3DDeviceImpl_SetPixelShaderConstantI,
    IWineD3DDeviceImpl_GetPixelShaderConstantI,
    IWineD3DDeviceImpl_SetPixelShaderConstantF,
    IWineD3DDeviceImpl_GetPixelShaderConstantF,
7117 7118
    IWineD3DDeviceImpl_SetRenderState,
    IWineD3DDeviceImpl_GetRenderState,
7119 7120
    IWineD3DDeviceImpl_SetRenderTarget,
    IWineD3DDeviceImpl_GetRenderTarget,
7121
    IWineD3DDeviceImpl_SetFrontBackBuffers,
7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132
    IWineD3DDeviceImpl_SetSamplerState,
    IWineD3DDeviceImpl_GetSamplerState,
    IWineD3DDeviceImpl_SetScissorRect,
    IWineD3DDeviceImpl_GetScissorRect,
    IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
    IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
    IWineD3DDeviceImpl_SetStreamSource,
    IWineD3DDeviceImpl_GetStreamSource,
    IWineD3DDeviceImpl_SetStreamSourceFreq,
    IWineD3DDeviceImpl_GetStreamSourceFreq,
    IWineD3DDeviceImpl_SetTexture,
7133
    IWineD3DDeviceImpl_GetTexture,
7134 7135
    IWineD3DDeviceImpl_SetTextureStageState,
    IWineD3DDeviceImpl_GetTextureStageState,
7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148
    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,
7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160
    IWineD3DDeviceImpl_GetViewport,
    IWineD3DDeviceImpl_MultiplyTransform,
    IWineD3DDeviceImpl_ValidateDevice,
    IWineD3DDeviceImpl_ProcessVertices,
    /*** State block ***/
    IWineD3DDeviceImpl_BeginStateBlock,
    IWineD3DDeviceImpl_EndStateBlock,
    /*** Scene management ***/
    IWineD3DDeviceImpl_BeginScene,
    IWineD3DDeviceImpl_EndScene,
    IWineD3DDeviceImpl_Present,
    IWineD3DDeviceImpl_Clear,
7161
    IWineD3DDeviceImpl_ClearRendertargetView,
7162
    /*** Drawing ***/
7163 7164
    IWineD3DDeviceImpl_SetPrimitiveType,
    IWineD3DDeviceImpl_GetPrimitiveType,
7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180
    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
};
7181

7182
void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7183
    DWORD rep = This->StateTable[state].representative;
7184
    struct wined3d_context *context;
7185 7186
    DWORD idx;
    BYTE shift;
7187
    UINT i;
7188

7189
    for(i = 0; i < This->numContexts; i++) {
7190
        context = This->contexts[i];
7191 7192 7193 7194 7195 7196 7197
        if(isStateDirty(context, rep)) continue;

        context->dirtyArray[context->numDirtyEntries++] = rep;
        idx = rep >> 5;
        shift = rep & 0x1f;
        context->isStateDirty[idx] |= (1 << shift);
    }
7198
}
7199

7200
void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7201 7202 7203 7204 7205
{
    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;
7206 7207
}

7208
void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7209 7210 7211 7212 7213
{
    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;
7214 7215
}

7216
void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7217 7218
{
    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7219 7220 7221
    /* 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
7222 7223 7224
     * surface the context belongs to. */
    *width = surface->currentDesc.Width;
    *height = surface->currentDesc.Height;
7225
}