surface_gdi.c 23.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * 2D Surface implementation without OpenGL
 *
 * Copyright 1997-2000 Marcus Meissner
 * Copyright 1998-2000 Lionel Ulmer
 * Copyright 2000-2001 TransGaming Technologies Inc.
 * Copyright 2002-2005 Jason Edmeades
 * Copyright 2002-2003 Raphael Junqueira
 * Copyright 2004 Christian Costa
 * Copyright 2005 Oliver Stieber
11
 * Copyright 2006-2008 Stefan Dösinger
12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * 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
25
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 27 28 29 30 31 32 33 34 35 36 37
 */

#include "config.h"
#include "wine/port.h"
#include "wined3d_private.h"

#include <assert.h>
#include <stdio.h>

/* Use the d3d_surface debug channel to have one channel for all surfaces */
WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);

38 39 40 41 42 43 44
/*****************************************************************************
 * IWineD3DSurface::Release, GDI version
 *
 * In general a normal COM Release method, but the GDI version doesn't have
 * to destroy all the GL things.
 *
 *****************************************************************************/
45
static ULONG WINAPI IWineGDISurfaceImpl_Release(IWineD3DSurface *iface) {
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
    ULONG ref = InterlockedDecrement(&This->resource.ref);
    TRACE("(%p) : Releasing from %d\n", This, ref + 1);
    if (ref == 0) {
        TRACE("(%p) : cleaning up\n", This);

        if(This->Flags & SFLAG_DIBSECTION) {
            /* Release the DC */
            SelectObject(This->hDC, This->dib.holdbitmap);
            DeleteDC(This->hDC);
            /* Release the DIB section */
            DeleteObject(This->dib.DIBsection);
            This->dib.bitmap_data = NULL;
            This->resource.allocatedMemory = NULL;
        }
        if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);

        HeapFree(GetProcessHeap(), 0, This->palette9);

65
        resource_cleanup((IWineD3DResource *)iface);
66

67 68 69 70
        if(This->overlay_dest) {
            list_remove(&This->overlay_entry);
        }

71 72 73 74 75 76 77
        TRACE("(%p) Released\n", This);
        HeapFree(GetProcessHeap(), 0, This);

    }
    return ref;
}

78 79 80 81 82 83 84
/*****************************************************************************
 * IWineD3DSurface::PreLoad, GDI version
 *
 * This call is unsupported on GDI surfaces, if it's called something went
 * wrong in the parent library. Write an informative warning
 *
 *****************************************************************************/
85
static void WINAPI
86 87 88 89 90 91 92
IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
{
    ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
    ERR("(%p): Most likely the parent library did something wrong.\n", iface);
    ERR("(%p): Please report to wine-devel\n", iface);
}

93
/*****************************************************************************
Austin English's avatar
Austin English committed
94
 * IWineD3DSurface::UnLoad, GDI version
95 96
 *
 * This call is unsupported on GDI surfaces, if it's called something went
Austin English's avatar
Austin English committed
97
 * wrong in the parent library. Write an informative warning.
98 99 100 101 102 103 104 105 106
 *
 *****************************************************************************/
static void WINAPI IWineGDISurfaceImpl_UnLoad(IWineD3DSurface *iface)
{
    ERR("(%p): UnLoad is not supported on X11 surfaces!\n", iface);
    ERR("(%p): Most likely the parent library did something wrong.\n", iface);
    ERR("(%p): Please report to wine-devel\n", iface);
}

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
/*****************************************************************************
 * IWineD3DSurface::LockRect, GDI version
 *
 * Locks the surface and returns a pointer to the surface memory
 *
 * Params:
 *  pLockedRect: Address to return the locking info at
 *  pRect: Rectangle to lock
 *  Flags: Some flags
 *
 * Returns:
 *  WINED3D_OK on success
 *  WINED3DERR_INVALIDCALL on errors
 *
 *****************************************************************************/
122
static HRESULT WINAPI
123 124 125 126 127 128 129
IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface,
                             WINED3DLOCKED_RECT* pLockedRect,
                             CONST RECT* pRect,
                             DWORD Flags)
{
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;

130 131 132 133 134 135 136 137 138
    /* Already locked? */
    if(This->Flags & SFLAG_LOCKED)
    {
        ERR("(%p) Surface already locked\n", This);
        /* What should I return here? */
        return WINED3DERR_INVALIDCALL;
    }
    This->Flags |= SFLAG_LOCKED;

139 140 141 142
    if(!This->resource.allocatedMemory) {
        /* This happens on gdi surfaces if the application set a user pointer and resets it.
         * Recreate the DIB section
         */
143 144
        IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
        This->resource.allocatedMemory = This->dib.bitmap_data;
145 146
    }

147
    return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
148 149 150 151 152 153 154 155 156 157 158 159 160
}

/*****************************************************************************
 * IWineD3DSurface::UnlockRect, GDI version
 *
 * Unlocks a surface. This implementation doesn't do much, except updating
 * the window if the front buffer is unlocked
 *
 * Returns:
 *  WINED3D_OK on success
 *  WINED3DERR_INVALIDCALL on failure
 *
 *****************************************************************************/
161
static HRESULT WINAPI
162 163 164
IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface)
{
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
165
    IWineD3DSwapChainImpl *swapchain = NULL;
166 167 168 169 170
    TRACE("(%p)\n", This);

    if (!(This->Flags & SFLAG_LOCKED))
    {
        WARN("trying to Unlock an unlocked surf@%p\n", This);
171
        return WINEDDERR_NOTLOCKED;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    }

    /* Can be useful for debugging */
#if 0
        {
            static unsigned int gen = 0;
            char buffer[4096];
            ++gen;
            if ((gen % 10) == 0) {
                snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
                IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
            }
            /*
             * debugging crash code
            if (gen == 250) {
              void** test = NULL;
              *test = 0;
            }
            */
        }
#endif

194
    /* Tell the swapchain to update the screen */
195 196
    if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain)))
    {
197 198
        x11_copy_to_screen(swapchain, &This->lockedRect);
        IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
    }

    This->Flags &= ~SFLAG_LOCKED;
    memset(&This->lockedRect, 0, sizeof(RECT));
    return WINED3D_OK;
}

/*****************************************************************************
 * IWineD3DSurface::Flip, GDI version
 *
 * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
 * the parent library. This implementation changes the data pointers of the
 * surfaces and copies the new front buffer content to the screen
 *
 * Params:
 *  override: Flipping target(e.g. back buffer)
 *
 * Returns:
 *  WINED3D_OK on success
 *
 *****************************************************************************/
220
static HRESULT WINAPI
221 222 223 224
IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
                         IWineD3DSurface *override,
                         DWORD Flags)
{
225 226
    IWineD3DSwapChainImpl *swapchain = NULL;
    HRESULT hr;
227

228 229
    if(FAILED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain)))
    {
230 231
        ERR("Flipped surface is not on a swapchain\n");
        return WINEDDERR_NOTFLIPPABLE;
232 233
    }

234 235 236
    hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0);
    IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
    return hr;
237 238 239 240 241 242 243 244 245 246 247
}

/*****************************************************************************
 * IWineD3DSurface::LoadTexture, GDI version
 *
 * This is mutually unsupported by GDI surfaces
 *
 * Returns:
 *  D3DERR_INVALIDCALL
 *
 *****************************************************************************/
248
static HRESULT WINAPI
249
IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode)
250 251
{
    ERR("Unsupported on X11 surfaces\n");
252
    return WINED3DERR_INVALIDCALL;
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
}

/*****************************************************************************
 * IWineD3DSurface::SaveSnapshot, GDI version
 *
 * This method writes the surface's contents to the in tga format to the
 * file specified in filename.
 *
 * Params:
 *  filename: File to write to
 *
 * Returns:
 *  WINED3DERR_INVALIDCALL if the file couldn't be opened
 *  WINED3D_OK on success
 *
 *****************************************************************************/
269 270 271 272 273 274 275 276 277 278 279 280 281 282
static int get_shift(DWORD color_mask) {
    int shift = 0;
    while (color_mask > 0xFF) {
        color_mask >>= 1;
        shift += 1;
    }
    while ((color_mask & 0x80) == 0) {
        color_mask <<= 1;
        shift -= 1;
    }
    return shift;
}


283
static HRESULT WINAPI
284 285 286 287
IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
const char* filename)
{
    FILE* f = NULL;
288
    UINT y = 0, x = 0;
289
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
290
    static char *output = NULL;
291
    static UINT size = 0;
292
    const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
293 294 295 296 297 298

    if (This->pow2Width > size) {
        output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
        size = This->pow2Width;
    }

299 300

    f = fopen(filename, "w+");
301
    if (NULL == f) {
302 303 304
        ERR("opening of %s failed with\n", filename);
        return WINED3DERR_INVALIDCALL;
    }
305 306
    fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);

307 308
    if (This->resource.format_desc->format == WINED3DFMT_P8)
    {
309 310 311 312 313 314 315 316 317 318 319 320 321
        unsigned char table[256][3];
        int i;

        if (This->palette == NULL) {
            fclose(f);
            return WINED3DERR_INVALIDCALL;
        }
        for (i = 0; i < 256; i++) {
            table[i][0] = This->palette->palents[i].peRed;
            table[i][1] = This->palette->palents[i].peGreen;
            table[i][2] = This->palette->palents[i].peBlue;
        }
        for (y = 0; y < This->pow2Height; y++) {
322
            unsigned char *src = This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
323 324 325 326 327 328 329 330 331 332 333
            for (x = 0; x < This->pow2Width; x++) {
                unsigned char color = *src;
                src += 1;

                output[3 * x + 0] = table[color][0];
                output[3 * x + 1] = table[color][1];
                output[3 * x + 2] = table[color][2];
            }
            fwrite(output, 3 * This->pow2Width, 1, f);
        }
    } else {
334
        int red_shift, green_shift, blue_shift, pix_width, alpha_shift;
335

336
        pix_width = format_desc->byte_count;
337

338 339 340 341
        red_shift = get_shift(format_desc->red_mask);
        green_shift = get_shift(format_desc->green_mask);
        blue_shift = get_shift(format_desc->blue_mask);
        alpha_shift = get_shift(format_desc->alpha_mask);
342 343

        for (y = 0; y < This->pow2Height; y++) {
344
            const unsigned char *src = This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
345
            for (x = 0; x < This->pow2Width; x++) {
346 347 348 349 350 351 352 353 354 355
                unsigned int color;
                unsigned int comp;
                int i;

                color = 0;
                for (i = 0; i < pix_width; i++) {
                    color |= src[i] << (8 * i);
                }
                src += 1 * pix_width;

356
                comp = color & format_desc->red_mask;
357
                output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
358
                comp = color & format_desc->green_mask;
359
                output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
360
                comp = color & format_desc->alpha_mask;
361
                output[3 * x + 2] = alpha_shift > 0 ? comp >> alpha_shift : comp << -alpha_shift;
362 363
            }
            fwrite(output, 3 * This->pow2Width, 1, f);
364 365 366 367 368 369
        }
    }
    fclose(f);
    return WINED3D_OK;
}

370
static HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
    WINED3DLOCKED_RECT lock;
    HRESULT hr;
    RGBQUAD col[256];

    TRACE("(%p)->(%p)\n",This,pHDC);

    if(This->Flags & SFLAG_USERPTR) {
        ERR("Not supported on surfaces with an application-provided surfaces\n");
        return WINEDDERR_NODC;
    }

    /* Give more detailed info for ddraw */
    if (This->Flags & SFLAG_DCINUSE)
        return WINEDDERR_DCALREADYCREATED;

    /* Can't GetDC if the surface is locked */
    if (This->Flags & SFLAG_LOCKED)
        return WINED3DERR_INVALIDCALL;

    memset(&lock, 0, sizeof(lock)); /* To be sure */

    /* Should have a DIB section already */

    /* Lock the surface */
    hr = IWineD3DSurface_LockRect(iface,
                                  &lock,
                                  NULL,
                                  0);
    if(FAILED(hr)) {
        ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
        /* keep the dib section */
        return hr;
    }

406 407 408
    if (This->resource.format_desc->format == WINED3DFMT_P8
            || This->resource.format_desc->format == WINED3DFMT_A8P8)
    {
409
        unsigned int n;
410
        const PALETTEENTRY *pal = NULL;
411

412 413
        if(This->palette) {
            pal = This->palette->palents;
414
        } else {
415 416 417 418
            IWineD3DSurfaceImpl *dds_primary;
            IWineD3DSwapChainImpl *swapchain;
            swapchain = (IWineD3DSwapChainImpl *)This->resource.wineD3DDevice->swapchains[0];
            dds_primary = (IWineD3DSurfaceImpl *)swapchain->frontBuffer;
419 420 421
            if (dds_primary && dds_primary->palette)
                pal = dds_primary->palette->palents;
        }
422

423
        if (pal) {
424
            for (n=0; n<256; n++) {
425 426 427
                col[n].rgbRed   = pal[n].peRed;
                col[n].rgbGreen = pal[n].peGreen;
                col[n].rgbBlue  = pal[n].peBlue;
428 429
                col[n].rgbReserved = 0;
            }
430
            SetDIBColorTable(This->hDC, 0, 256, col);
431 432 433 434 435 436 437 438 439 440
        }
    }

    *pHDC = This->hDC;
    TRACE("returning %p\n",*pHDC);
    This->Flags |= SFLAG_DCINUSE;

    return WINED3D_OK;
}

441
static HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
442 443 444 445 446
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;

    TRACE("(%p)->(%p)\n",This,hDC);

    if (!(This->Flags & SFLAG_DCINUSE))
447
        return WINEDDERR_NODC;
448 449 450

    if (This->hDC !=hDC) {
        WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
451
        return WINEDDERR_NODC;
452 453 454 455 456 457 458 459 460 461
    }

    /* we locked first, so unlock now */
    IWineD3DSurface_UnlockRect(iface);

    This->Flags &= ~SFLAG_DCINUSE;

    return WINED3D_OK;
}

462
static HRESULT WINAPI IWineGDISurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
463 464 465 466
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
    RGBQUAD col[256];
    IWineD3DPaletteImpl *pal = This->palette;
    unsigned int n;
467
    IWineD3DSwapChainImpl *swapchain;
468 469
    TRACE("(%p)\n", This);

470 471
    if (!pal) return WINED3D_OK;

472 473 474
    if(This->Flags & SFLAG_DIBSECTION) {
        TRACE("(%p): Updating the hdc's palette\n", This);
        for (n=0; n<256; n++) {
475 476 477
            col[n].rgbRed   = pal->palents[n].peRed;
            col[n].rgbGreen = pal->palents[n].peGreen;
            col[n].rgbBlue  = pal->palents[n].peBlue;
478 479 480 481 482
            col[n].rgbReserved = 0;
        }
        SetDIBColorTable(This->hDC, 0, 256, col);
    }

483 484
    /* Update the image because of the palette change. Some games like e.g Red Alert
       call SetEntries a lot to implement fading. */
485
    /* Tell the swapchain to update the screen */
486 487
    if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain)))
    {
488
        x11_copy_to_screen(swapchain, NULL);
489 490
        IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
    }
491 492 493 494

    return WINED3D_OK;
}

495 496 497 498 499 500 501 502 503 504 505 506 507
/*****************************************************************************
 * IWineD3DSurface::PrivateSetup, GDI version
 *
 * Initializes the GDI surface, aka creates the DIB section we render to
 * The DIB section creation is done by calling GetDC, which will create the
 * section and releasing the dc to allow the app to use it. The dib section
 * will stay until the surface is released
 *
 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
 * avoid confusion in the shared surface code.
 *
 * Returns:
508
 *  WINED3D_OK on success
509 510 511
 *  The return values of called methods on failure
 *
 *****************************************************************************/
512
static HRESULT WINAPI
513 514 515 516
IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
{
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;

517 518 519 520 521
    if(This->resource.usage & WINED3DUSAGE_OVERLAY)
    {
        ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
        return WINED3DERR_INVALIDCALL;
    }
522 523 524
    /* Sysmem textures have memory already allocated -
     * release it, this avoids an unnecessary memcpy
     */
525
    HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
526
    This->resource.allocatedMemory = NULL;
527
    This->resource.heapMemory = NULL;
528

529 530 531
    /* We don't mind the nonpow2 stuff in GDI */
    This->pow2Width = This->currentDesc.Width;
    This->pow2Height = This->currentDesc.Height;
532

533 534
    IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
    This->resource.allocatedMemory = This->dib.bitmap_data;
535 536 537 538

    return WINED3D_OK;
}

539
static void WINAPI IWineGDISurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
540 541 542 543 544
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
    FIXME("(%p) : Should not be called on a GDI surface\n", This);
    *glDescription = NULL;
}

545
static HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;

    /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
    if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
        ERR("Not supported on render targets\n");
        return WINED3DERR_INVALIDCALL;
    }

    if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
        WARN("Surface is locked or the HDC is in use\n");
        return WINED3DERR_INVALIDCALL;
    }

    if(Mem && Mem != This->resource.allocatedMemory) {
        void *release = NULL;

        /* Do I have to copy the old surface content? */
        if(This->Flags & SFLAG_DIBSECTION) {
                /* Release the DC. No need to hold the critical section for the update
            * Thread because this thread runs only on front buffers, but this method
            * fails for render targets in the check above.
                */
            SelectObject(This->hDC, This->dib.holdbitmap);
            DeleteDC(This->hDC);
            /* Release the DIB section */
            DeleteObject(This->dib.DIBsection);
            This->dib.bitmap_data = NULL;
            This->resource.allocatedMemory = NULL;
            This->hDC = NULL;
            This->Flags &= ~SFLAG_DIBSECTION;
        } else if(!(This->Flags & SFLAG_USERPTR)) {
            release = This->resource.allocatedMemory;
        }
        This->resource.allocatedMemory = Mem;
        This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;

        /* Now free the old memory if any */
        HeapFree(GetProcessHeap(), 0, release);
    } else if(This->Flags & SFLAG_USERPTR) {
Austin English's avatar
Austin English committed
585
        /* LockRect and GetDC will re-create the dib section and allocated memory */
586 587 588 589 590 591
        This->resource.allocatedMemory = NULL;
        This->Flags &= ~SFLAG_USERPTR;
    }
    return WINED3D_OK;
}

592 593 594 595 596 597 598 599 600 601 602 603 604
/***************************
 *
 ***************************/
static void WINAPI IWineGDISurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
    TRACE("(%p)->(%s, %s)\n", iface,
          flag == SFLAG_INSYSMEM ? "SFLAG_INSYSMEM" : flag == SFLAG_INDRAWABLE ? "SFLAG_INDRAWABLE" : "SFLAG_INTEXTURE",
          persistent ? "TRUE" : "FALSE");
    /* GDI surfaces can be in system memory only */
    if(flag != SFLAG_INSYSMEM) {
        ERR("GDI Surface requested in gl %s memory\n", flag == SFLAG_INDRAWABLE ? "drawable" : "texture");
    }
}

605 606 607 608 609 610 611 612 613
static HRESULT WINAPI IWineGDISurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
    if(flag != SFLAG_INSYSMEM) {
        ERR("GDI Surface requested to be copied to gl %s\n", flag == SFLAG_INTEXTURE ? "texture" : "drawable");
    } else {
        TRACE("Surface requested in surface memory\n");
    }
    return WINED3D_OK;
}

614 615 616 617
static WINED3DSURFTYPE WINAPI IWineGDISurfaceImpl_GetImplType(IWineD3DSurface *iface) {
    return SURFACE_GDI;
}

618 619 620 621 622
static HRESULT WINAPI IWineGDISurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
    FIXME("GDI surfaces can't draw overlays yet\n");
    return E_FAIL;
}

623 624 625
/* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
 * only IWineD3DBaseSurface and IWineGDISurface ones.
 */
626 627 628
const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
{
    /* IUnknown */
629
    IWineD3DBaseSurfaceImpl_QueryInterface,
630
    IWineD3DBaseSurfaceImpl_AddRef,
631
    IWineGDISurfaceImpl_Release,
632
    /* IWineD3DResource */
633 634 635 636 637 638 639
    IWineD3DBaseSurfaceImpl_GetParent,
    IWineD3DBaseSurfaceImpl_GetDevice,
    IWineD3DBaseSurfaceImpl_SetPrivateData,
    IWineD3DBaseSurfaceImpl_GetPrivateData,
    IWineD3DBaseSurfaceImpl_FreePrivateData,
    IWineD3DBaseSurfaceImpl_SetPriority,
    IWineD3DBaseSurfaceImpl_GetPriority,
640
    IWineGDISurfaceImpl_PreLoad,
641
    IWineGDISurfaceImpl_UnLoad,
642
    IWineD3DBaseSurfaceImpl_GetType,
643
    /* IWineD3DSurface */
644 645
    IWineD3DBaseSurfaceImpl_GetContainer,
    IWineD3DBaseSurfaceImpl_GetDesc,
646 647
    IWineGDISurfaceImpl_LockRect,
    IWineGDISurfaceImpl_UnlockRect,
648
    IWineGDISurfaceImpl_GetDC,
649
    IWineGDISurfaceImpl_ReleaseDC,
650
    IWineGDISurfaceImpl_Flip,
651
    IWineD3DBaseSurfaceImpl_Blt,
652 653 654 655
    IWineD3DBaseSurfaceImpl_GetBltStatus,
    IWineD3DBaseSurfaceImpl_GetFlipStatus,
    IWineD3DBaseSurfaceImpl_IsLost,
    IWineD3DBaseSurfaceImpl_Restore,
656
    IWineD3DBaseSurfaceImpl_BltFast,
657 658
    IWineD3DBaseSurfaceImpl_GetPalette,
    IWineD3DBaseSurfaceImpl_SetPalette,
659
    IWineGDISurfaceImpl_RealizePalette,
660 661
    IWineD3DBaseSurfaceImpl_SetColorKey,
    IWineD3DBaseSurfaceImpl_GetPitch,
662
    IWineGDISurfaceImpl_SetMem,
663 664 665 666 667 668
    IWineD3DBaseSurfaceImpl_SetOverlayPosition,
    IWineD3DBaseSurfaceImpl_GetOverlayPosition,
    IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
    IWineD3DBaseSurfaceImpl_UpdateOverlay,
    IWineD3DBaseSurfaceImpl_SetClipper,
    IWineD3DBaseSurfaceImpl_GetClipper,
669 670
    /* Internal use: */
    IWineGDISurfaceImpl_LoadTexture,
671
    IWineD3DBaseSurfaceImpl_BindTexture,
672
    IWineGDISurfaceImpl_SaveSnapshot,
673
    IWineD3DBaseSurfaceImpl_SetContainer,
674
    IWineGDISurfaceImpl_GetGlDesc,
675
    IWineD3DBaseSurfaceImpl_GetData,
676
    IWineD3DBaseSurfaceImpl_SetFormat,
677
    IWineGDISurfaceImpl_PrivateSetup,
678
    IWineGDISurfaceImpl_ModifyLocation,
679
    IWineGDISurfaceImpl_LoadLocation,
680 681
    IWineGDISurfaceImpl_GetImplType,
    IWineGDISurfaceImpl_DrawOverlay
682
};