wined3d: Bind the surface texture in LoadLocation().
[wine] / dlls / wined3d / surface_gdi.c
1 /*
2  * 2D Surface implementation without OpenGL
3  *
4  * Copyright 1997-2000 Marcus Meissner
5  * Copyright 1998-2000 Lionel Ulmer
6  * Copyright 2000-2001 TransGaming Technologies Inc.
7  * Copyright 2002-2005 Jason Edmeades
8  * Copyright 2002-2003 Raphael Junqueira
9  * Copyright 2004 Christian Costa
10  * Copyright 2005 Oliver Stieber
11  * Copyright 2006-2008 Stefan Dösinger
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * 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 #include "config.h"
29 #include "wine/port.h"
30 #include "wined3d_private.h"
31
32 #include <assert.h>
33 #include <stdio.h>
34
35 /* Use the d3d_surface debug channel to have one channel for all surfaces */
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37 WINE_DECLARE_DEBUG_CHANNEL(fps);
38
39 /*****************************************************************************
40  * x11_copy_to_screen
41  *
42  * Helper function that blts the front buffer contents to the target window
43  *
44  * Params:
45  *  This: Surface to copy from
46  *  rc: Rectangle to copy
47  *
48  *****************************************************************************/
49 static void
50 x11_copy_to_screen(IWineD3DSurfaceImpl *This,
51                    LPRECT rc)
52 {
53     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
54     {
55         POINT offset = {0,0};
56         HWND hDisplayWnd;
57         HDC hDisplayDC;
58         HDC hSurfaceDC = 0;
59         RECT drawrect;
60         TRACE("(%p)->(%p): Copying to screen\n", This, rc);
61
62         hSurfaceDC = This->hDC;
63
64         hDisplayWnd = This->resource.wineD3DDevice->ddraw_window;
65         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
66         if(rc)
67         {
68             TRACE(" copying rect (%d,%d)->(%d,%d), offset (%d,%d)\n",
69             rc->left, rc->top, rc->right, rc->bottom, offset.x, offset.y);
70         }
71
72         /* Front buffer coordinates are screen coordinates. Map them to the destination
73          * window if not fullscreened
74          */
75         if(!This->resource.wineD3DDevice->ddraw_fullscreen) {
76             ClientToScreen(hDisplayWnd, &offset);
77         }
78 #if 0
79         /* FIXME: this doesn't work... if users really want to run
80         * X in 8bpp, then we need to call directly into display.drv
81         * (or Wine's equivalent), and force a private colormap
82         * without default entries. */
83         if (This->palette) {
84             SelectPalette(hDisplayDC, This->palette->hpal, FALSE);
85             RealizePalette(hDisplayDC); /* sends messages => deadlocks */
86         }
87 #endif
88         drawrect.left   = 0;
89         drawrect.right  = This->currentDesc.Width;
90         drawrect.top    = 0;
91         drawrect.bottom = This->currentDesc.Height;
92
93 #if 0
94         /* TODO: Support clippers */
95         if (This->clipper)
96         {
97             RECT xrc;
98             HWND hwnd = ((IWineD3DClipperImpl *) This->clipper)->hWnd;
99             if (hwnd && GetClientRect(hwnd,&xrc))
100             {
101                 OffsetRect(&xrc,offset.x,offset.y);
102                 IntersectRect(&drawrect,&drawrect,&xrc);
103             }
104         }
105 #endif
106         if (rc)
107         {
108             IntersectRect(&drawrect,&drawrect,rc);
109         }
110         else
111         {
112             /* Only use this if the caller did not pass a rectangle, since
113              * due to double locking this could be the wrong one ...
114              */
115             if (This->lockedRect.left != This->lockedRect.right)
116             {
117                 IntersectRect(&drawrect,&drawrect,&This->lockedRect);
118             }
119         }
120
121         BitBlt(hDisplayDC,
122                drawrect.left-offset.x, drawrect.top-offset.y,
123                drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
124                hSurfaceDC,
125                drawrect.left, drawrect.top,
126                SRCCOPY);
127         ReleaseDC(hDisplayWnd, hDisplayDC);
128     }
129 }
130
131 /*****************************************************************************
132  * IWineD3DSurface::Release, GDI version
133  *
134  * In general a normal COM Release method, but the GDI version doesn't have
135  * to destroy all the GL things.
136  *
137  *****************************************************************************/
138 ULONG WINAPI IWineGDISurfaceImpl_Release(IWineD3DSurface *iface) {
139     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
140     ULONG ref = InterlockedDecrement(&This->resource.ref);
141     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
142     if (ref == 0) {
143         IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
144         TRACE("(%p) : cleaning up\n", This);
145
146         if(This->Flags & SFLAG_DIBSECTION) {
147             /* Release the DC */
148             SelectObject(This->hDC, This->dib.holdbitmap);
149             DeleteDC(This->hDC);
150             /* Release the DIB section */
151             DeleteObject(This->dib.DIBsection);
152             This->dib.bitmap_data = NULL;
153             This->resource.allocatedMemory = NULL;
154         }
155         if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
156
157         HeapFree(GetProcessHeap(), 0, This->palette9);
158
159         IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
160         if(iface == device->ddraw_primary)
161             device->ddraw_primary = NULL;
162
163         TRACE("(%p) Released\n", This);
164         HeapFree(GetProcessHeap(), 0, This);
165
166     }
167     return ref;
168 }
169
170 /*****************************************************************************
171  * IWineD3DSurface::PreLoad, GDI version
172  *
173  * This call is unsupported on GDI surfaces, if it's called something went
174  * wrong in the parent library. Write an informative warning
175  *
176  *****************************************************************************/
177 static void WINAPI
178 IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
179 {
180     ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
181     ERR("(%p): Most likely the parent library did something wrong.\n", iface);
182     ERR("(%p): Please report to wine-devel\n", iface);
183 }
184
185 /*****************************************************************************
186  * IWineD3DSurface::LockRect, GDI version
187  *
188  * Locks the surface and returns a pointer to the surface memory
189  *
190  * Params:
191  *  pLockedRect: Address to return the locking info at
192  *  pRect: Rectangle to lock
193  *  Flags: Some flags
194  *
195  * Returns:
196  *  WINED3D_OK on success
197  *  WINED3DERR_INVALIDCALL on errors
198  *
199  *****************************************************************************/
200 static HRESULT WINAPI
201 IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface,
202                              WINED3DLOCKED_RECT* pLockedRect,
203                              CONST RECT* pRect,
204                              DWORD Flags)
205 {
206     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
207
208     /* Already locked? */
209     if(This->Flags & SFLAG_LOCKED)
210     {
211         ERR("(%p) Surface already locked\n", This);
212         /* What should I return here? */
213         return WINED3DERR_INVALIDCALL;
214     }
215     This->Flags |= SFLAG_LOCKED;
216
217     if(!This->resource.allocatedMemory) {
218         /* This happens on gdi surfaces if the application set a user pointer and resets it.
219          * Recreate the DIB section
220          */
221         IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
222         This->resource.allocatedMemory = This->dib.bitmap_data;
223     }
224
225     return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
226 }
227
228 /*****************************************************************************
229  * IWineD3DSurface::UnlockRect, GDI version
230  *
231  * Unlocks a surface. This implementation doesn't do much, except updating
232  * the window if the front buffer is unlocked
233  *
234  * Returns:
235  *  WINED3D_OK on success
236  *  WINED3DERR_INVALIDCALL on failure
237  *
238  *****************************************************************************/
239 static HRESULT WINAPI
240 IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface)
241 {
242     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
243     IWineD3DDeviceImpl *dev = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
244     TRACE("(%p)\n", This);
245
246     if (!(This->Flags & SFLAG_LOCKED))
247     {
248         WARN("trying to Unlock an unlocked surf@%p\n", This);
249         return WINED3DERR_INVALIDCALL;
250     }
251
252     /* Can be useful for debugging */
253 #if 0
254         {
255             static unsigned int gen = 0;
256             char buffer[4096];
257             ++gen;
258             if ((gen % 10) == 0) {
259                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
260                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
261             }
262             /*
263              * debugging crash code
264             if (gen == 250) {
265               void** test = NULL;
266               *test = 0;
267             }
268             */
269         }
270 #endif
271
272     /* Update the screen */
273     if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary)
274     {
275         x11_copy_to_screen(This, &This->lockedRect);
276     }
277
278     This->Flags &= ~SFLAG_LOCKED;
279     memset(&This->lockedRect, 0, sizeof(RECT));
280     return WINED3D_OK;
281 }
282
283 /*****************************************************************************
284  * IWineD3DSurface::Flip, GDI version
285  *
286  * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
287  * the parent library. This implementation changes the data pointers of the
288  * surfaces and copies the new front buffer content to the screen
289  *
290  * Params:
291  *  override: Flipping target(e.g. back buffer)
292  *
293  * Returns:
294  *  WINED3D_OK on success
295  *
296  *****************************************************************************/
297 static HRESULT WINAPI
298 IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
299                          IWineD3DSurface *override,
300                          DWORD Flags)
301 {
302     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
303     IWineD3DSurfaceImpl *Target = (IWineD3DSurfaceImpl *) override;
304     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
305
306     TRACE("(%p) Flipping to surface %p\n", This, Target);
307
308     if(Target == NULL)
309     {
310         ERR("(%p): Can't flip without a target\n", This);
311         return WINED3DERR_INVALIDCALL;
312     }
313
314     /* Flip the DC */
315     {
316         HDC tmp;
317         tmp = This->hDC;
318         This->hDC = Target->hDC;
319         Target->hDC = tmp;
320     }
321
322     /* Flip the DIBsection */
323     {
324         HBITMAP tmp;
325         tmp = This->dib.DIBsection;
326         This->dib.DIBsection = Target->dib.DIBsection;
327         Target->dib.DIBsection = tmp;
328     }
329
330     /* Flip the surface data */
331     {
332         void* tmp;
333
334         tmp = This->dib.bitmap_data;
335         This->dib.bitmap_data = Target->dib.bitmap_data;
336         Target->dib.bitmap_data = tmp;
337
338         tmp = This->resource.allocatedMemory;
339         This->resource.allocatedMemory = Target->resource.allocatedMemory;
340         Target->resource.allocatedMemory = tmp;
341
342         if(This->resource.heapMemory) {
343             ERR("GDI Surface %p has heap memory allocated\n", This);
344         }
345         if(Target->resource.heapMemory) {
346             ERR("GDI Surface %p has heap memory allocated\n", Target);
347         }
348     }
349
350     /* client_memory should not be different, but just in case */
351     {
352         BOOL tmp;
353         tmp = This->dib.client_memory;
354         This->dib.client_memory = Target->dib.client_memory;
355         Target->dib.client_memory = tmp;
356     }
357
358     /* Useful for debugging */
359 #if 0
360         {
361             static unsigned int gen = 0;
362             char buffer[4096];
363             ++gen;
364             if ((gen % 10) == 0) {
365                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
366                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
367             }
368             /*
369              * debugging crash code
370             if (gen == 250) {
371               void** test = NULL;
372               *test = 0;
373             }
374             */
375         }
376 #endif
377
378     /* Update the screen */
379     x11_copy_to_screen(This, NULL);
380
381     /* FPS support */
382     if (TRACE_ON(fps))
383     {
384         static long prev_time, frames;
385
386         DWORD time = GetTickCount();
387         frames++;
388         /* every 1.5 seconds */
389         if (time - prev_time > 1500) {
390             TRACE_(fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
391             prev_time = time;
392             frames = 0;
393         }
394     }
395
396     return WINED3D_OK;
397 }
398
399 /*****************************************************************************
400  * IWineD3DSurface::LoadTexture, GDI version
401  *
402  * This is mutually unsupported by GDI surfaces
403  *
404  * Returns:
405  *  D3DERR_INVALIDCALL
406  *
407  *****************************************************************************/
408 HRESULT WINAPI
409 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode)
410 {
411     ERR("Unsupported on X11 surfaces\n");
412     return WINED3DERR_INVALIDCALL;
413 }
414
415 /*****************************************************************************
416  * IWineD3DSurface::SaveSnapshot, GDI version
417  *
418  * This method writes the surface's contents to the in tga format to the
419  * file specified in filename.
420  *
421  * Params:
422  *  filename: File to write to
423  *
424  * Returns:
425  *  WINED3DERR_INVALIDCALL if the file couldn't be opened
426  *  WINED3D_OK on success
427  *
428  *****************************************************************************/
429 static int get_shift(DWORD color_mask) {
430     int shift = 0;
431     while (color_mask > 0xFF) {
432         color_mask >>= 1;
433         shift += 1;
434     }
435     while ((color_mask & 0x80) == 0) {
436         color_mask <<= 1;
437         shift -= 1;
438     }
439     return shift;
440 }
441
442
443 HRESULT WINAPI
444 IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
445 const char* filename)
446 {
447     FILE* f = NULL;
448     UINT y = 0, x = 0;
449     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
450     static char *output = NULL;
451     static int size = 0;
452     const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
453
454     if (This->pow2Width > size) {
455         output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
456         size = This->pow2Width;
457     }
458
459
460     f = fopen(filename, "w+");
461     if (NULL == f) {
462         ERR("opening of %s failed with\n", filename);
463         return WINED3DERR_INVALIDCALL;
464     }
465     fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);
466
467     if (This->resource.format == WINED3DFMT_P8) {
468         unsigned char table[256][3];
469         int i;
470
471         if (This->palette == NULL) {
472             fclose(f);
473             return WINED3DERR_INVALIDCALL;
474         }
475         for (i = 0; i < 256; i++) {
476             table[i][0] = This->palette->palents[i].peRed;
477             table[i][1] = This->palette->palents[i].peGreen;
478             table[i][2] = This->palette->palents[i].peBlue;
479         }
480         for (y = 0; y < This->pow2Height; y++) {
481             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
482             for (x = 0; x < This->pow2Width; x++) {
483                 unsigned char color = *src;
484                 src += 1;
485
486                 output[3 * x + 0] = table[color][0];
487                 output[3 * x + 1] = table[color][1];
488                 output[3 * x + 2] = table[color][2];
489             }
490             fwrite(output, 3 * This->pow2Width, 1, f);
491         }
492     } else {
493         int red_shift, green_shift, blue_shift, pix_width;
494
495         pix_width = This->bytesPerPixel;
496
497         red_shift = get_shift(formatEntry->redMask);
498         green_shift = get_shift(formatEntry->greenMask);
499         blue_shift = get_shift(formatEntry->blueMask);
500
501         for (y = 0; y < This->pow2Height; y++) {
502             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
503             for (x = 0; x < This->pow2Width; x++) {         
504                 unsigned int color;
505                 unsigned int comp;
506                 int i;
507
508                 color = 0;
509                 for (i = 0; i < pix_width; i++) {
510                     color |= src[i] << (8 * i);
511                 }
512                 src += 1 * pix_width;
513
514                 comp = color & formatEntry->redMask;
515                 output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
516                 comp = color & formatEntry->greenMask;
517                 output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
518                 comp = color & formatEntry->blueMask;
519                 output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift;
520             }
521             fwrite(output, 3 * This->pow2Width, 1, f);
522         }
523     }
524     fclose(f);
525     return WINED3D_OK;
526 }
527
528 HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
529     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
530     WINED3DLOCKED_RECT lock;
531     HRESULT hr;
532     RGBQUAD col[256];
533
534     TRACE("(%p)->(%p)\n",This,pHDC);
535
536     if(This->Flags & SFLAG_USERPTR) {
537         ERR("Not supported on surfaces with an application-provided surfaces\n");
538         return WINEDDERR_NODC;
539     }
540
541     /* Give more detailed info for ddraw */
542     if (This->Flags & SFLAG_DCINUSE)
543         return WINEDDERR_DCALREADYCREATED;
544
545     /* Can't GetDC if the surface is locked */
546     if (This->Flags & SFLAG_LOCKED)
547         return WINED3DERR_INVALIDCALL;
548
549     memset(&lock, 0, sizeof(lock)); /* To be sure */
550
551     /* Should have a DIB section already */
552
553     /* Lock the surface */
554     hr = IWineD3DSurface_LockRect(iface,
555                                   &lock,
556                                   NULL,
557                                   0);
558     if(FAILED(hr)) {
559         ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
560         /* keep the dib section */
561         return hr;
562     }
563
564     if(This->resource.format == WINED3DFMT_P8 ||
565        This->resource.format == WINED3DFMT_A8P8) {
566         unsigned int n;
567         if(This->palette) {
568             PALETTEENTRY ent[256];
569
570             GetPaletteEntries(This->palette->hpal, 0, 256, ent);
571             for (n=0; n<256; n++) {
572                 col[n].rgbRed   = ent[n].peRed;
573                 col[n].rgbGreen = ent[n].peGreen;
574                 col[n].rgbBlue  = ent[n].peBlue;
575                 col[n].rgbReserved = 0;
576             }
577         } else {
578             IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
579
580             for (n=0; n<256; n++) {
581                 col[n].rgbRed   = device->palettes[device->currentPalette][n].peRed;
582                 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
583                 col[n].rgbBlue  = device->palettes[device->currentPalette][n].peBlue;
584                 col[n].rgbReserved = 0;
585             }
586
587         }
588         SetDIBColorTable(This->hDC, 0, 256, col);
589     }
590
591     *pHDC = This->hDC;
592     TRACE("returning %p\n",*pHDC);
593     This->Flags |= SFLAG_DCINUSE;
594
595     return WINED3D_OK;
596 }
597
598 HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
599     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
600
601     TRACE("(%p)->(%p)\n",This,hDC);
602
603     if (!(This->Flags & SFLAG_DCINUSE))
604         return WINED3DERR_INVALIDCALL;
605
606     if (This->hDC !=hDC) {
607         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
608         return WINED3DERR_INVALIDCALL;
609     }
610
611     /* we locked first, so unlock now */
612     IWineD3DSurface_UnlockRect(iface);
613
614     This->Flags &= ~SFLAG_DCINUSE;
615
616     return WINED3D_OK;
617 }
618
619 /*****************************************************************************
620  * IWineD3DSurface::PrivateSetup, GDI version
621  *
622  * Initializes the GDI surface, aka creates the DIB section we render to
623  * The DIB section creation is done by calling GetDC, which will create the
624  * section and releasing the dc to allow the app to use it. The dib section
625  * will stay until the surface is released
626  *
627  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
628  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
629  * avoid confusion in the shared surface code.
630  *
631  * Returns:
632  *  WINED3D_OK on success
633  *  The return values of called methods on failure
634  *
635  *****************************************************************************/
636 HRESULT WINAPI
637 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
638 {
639     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
640
641     if(This->resource.usage & WINED3DUSAGE_OVERLAY)
642     {
643         ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
644         return WINED3DERR_INVALIDCALL;
645     }
646     /* Sysmem textures have memory already allocated -
647      * release it, this avoids an unnecessary memcpy
648      */
649     HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
650     This->resource.allocatedMemory = NULL;
651     This->resource.heapMemory = NULL;
652
653     /* We don't mind the nonpow2 stuff in GDI */
654     This->pow2Width = This->currentDesc.Width;
655     This->pow2Height = This->currentDesc.Height;
656
657     IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
658     This->resource.allocatedMemory = This->dib.bitmap_data;
659
660     return WINED3D_OK;
661 }
662
663 void WINAPI IWineGDISurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
664     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
665
666     /* Ignore 0 textureName and target. D3D textures can be created with gdi surfaces as plain
667      * containers, but they're useless until the app creates a d3d device from a d3d point of
668      * view, it's not an implementation limitation. This avoids false warnings when the texture
669      * is destroyed and sets the description back to 0/0
670      */
671     if(textureName != 0 || target != 0) {
672         FIXME("(%p) : Should not be called on a GDI surface. textureName %u, target %i\n", This, textureName, target);
673         DebugBreak();
674     }
675 }
676
677 void WINAPI IWineGDISurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
678     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
679     FIXME("(%p) : Should not be called on a GDI surface\n", This);
680     *glDescription = NULL;
681 }
682
683 HRESULT WINAPI IWineGDISurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
684     /* GDI surface data can only be in one location, the system memory dib section. So they are
685      * always clean by definition.
686      */
687     TRACE("No dirtification in GDI surfaces\n");
688     return WINED3D_OK;
689 }
690
691 HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
692     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
693
694     /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
695     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
696         ERR("Not supported on render targets\n");
697         return WINED3DERR_INVALIDCALL;
698     }
699
700     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
701         WARN("Surface is locked or the HDC is in use\n");
702         return WINED3DERR_INVALIDCALL;
703     }
704
705     if(Mem && Mem != This->resource.allocatedMemory) {
706         void *release = NULL;
707
708         /* Do I have to copy the old surface content? */
709         if(This->Flags & SFLAG_DIBSECTION) {
710                 /* Release the DC. No need to hold the critical section for the update
711             * Thread because this thread runs only on front buffers, but this method
712             * fails for render targets in the check above.
713                 */
714             SelectObject(This->hDC, This->dib.holdbitmap);
715             DeleteDC(This->hDC);
716             /* Release the DIB section */
717             DeleteObject(This->dib.DIBsection);
718             This->dib.bitmap_data = NULL;
719             This->resource.allocatedMemory = NULL;
720             This->hDC = NULL;
721             This->Flags &= ~SFLAG_DIBSECTION;
722         } else if(!(This->Flags & SFLAG_USERPTR)) {
723             release = This->resource.allocatedMemory;
724         }
725         This->resource.allocatedMemory = Mem;
726         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
727
728         /* Now free the old memory if any */
729         HeapFree(GetProcessHeap(), 0, release);
730     } else if(This->Flags & SFLAG_USERPTR) {
731         /* Lockrect and GetDC will re-create the dib section and allocated memory */
732         This->resource.allocatedMemory = NULL;
733         This->Flags &= ~SFLAG_USERPTR;
734     }
735     return WINED3D_OK;
736 }
737
738 /***************************
739  *
740  ***************************/
741 static void WINAPI IWineGDISurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
742     TRACE("(%p)->(%s, %s)\n", iface,
743           flag == SFLAG_INSYSMEM ? "SFLAG_INSYSMEM" : flag == SFLAG_INDRAWABLE ? "SFLAG_INDRAWABLE" : "SFLAG_INTEXTURE",
744           persistent ? "TRUE" : "FALSE");
745     /* GDI surfaces can be in system memory only */
746     if(flag != SFLAG_INSYSMEM) {
747         ERR("GDI Surface requested in gl %s memory\n", flag == SFLAG_INDRAWABLE ? "drawable" : "texture");
748     }
749 }
750
751 static HRESULT WINAPI IWineGDISurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
752     if(flag != SFLAG_INSYSMEM) {
753         ERR("GDI Surface requested to be copied to gl %s\n", flag == SFLAG_INTEXTURE ? "texture" : "drawable");
754     } else {
755         TRACE("Surface requested in surface memory\n");
756     }
757     return WINED3D_OK;
758 }
759
760 /* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
761  * only IWineD3DBaseSurface and IWineGDISurface ones.
762  */
763 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
764 {
765     /* IUnknown */
766     IWineD3DBaseSurfaceImpl_QueryInterface,
767     IWineD3DBaseSurfaceImpl_AddRef,
768     IWineGDISurfaceImpl_Release,
769     /* IWineD3DResource */
770     IWineD3DBaseSurfaceImpl_GetParent,
771     IWineD3DBaseSurfaceImpl_GetDevice,
772     IWineD3DBaseSurfaceImpl_SetPrivateData,
773     IWineD3DBaseSurfaceImpl_GetPrivateData,
774     IWineD3DBaseSurfaceImpl_FreePrivateData,
775     IWineD3DBaseSurfaceImpl_SetPriority,
776     IWineD3DBaseSurfaceImpl_GetPriority,
777     IWineGDISurfaceImpl_PreLoad,
778     IWineD3DBaseSurfaceImpl_GetType,
779     /* IWineD3DSurface */
780     IWineD3DBaseSurfaceImpl_GetContainer,
781     IWineD3DBaseSurfaceImpl_GetDesc,
782     IWineGDISurfaceImpl_LockRect,
783     IWineGDISurfaceImpl_UnlockRect,
784     IWineGDISurfaceImpl_GetDC,
785     IWineGDISurfaceImpl_ReleaseDC,
786     IWineGDISurfaceImpl_Flip,
787     IWineD3DBaseSurfaceImpl_Blt,
788     IWineD3DBaseSurfaceImpl_GetBltStatus,
789     IWineD3DBaseSurfaceImpl_GetFlipStatus,
790     IWineD3DBaseSurfaceImpl_IsLost,
791     IWineD3DBaseSurfaceImpl_Restore,
792     IWineD3DBaseSurfaceImpl_BltFast,
793     IWineD3DBaseSurfaceImpl_GetPalette,
794     IWineD3DBaseSurfaceImpl_SetPalette,
795     IWineD3DBaseSurfaceImpl_RealizePalette,
796     IWineD3DBaseSurfaceImpl_SetColorKey,
797     IWineD3DBaseSurfaceImpl_GetPitch,
798     IWineGDISurfaceImpl_SetMem,
799     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
800     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
801     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
802     IWineD3DBaseSurfaceImpl_UpdateOverlay,
803     IWineD3DBaseSurfaceImpl_SetClipper,
804     IWineD3DBaseSurfaceImpl_GetClipper,
805     /* Internal use: */
806     IWineGDISurfaceImpl_AddDirtyRect,
807     IWineGDISurfaceImpl_LoadTexture,
808     IWineD3DBaseSurfaceImpl_BindTexture,
809     IWineGDISurfaceImpl_SaveSnapshot,
810     IWineD3DBaseSurfaceImpl_SetContainer,
811     IWineGDISurfaceImpl_SetGlTextureDesc,
812     IWineGDISurfaceImpl_GetGlDesc,
813     IWineD3DSurfaceImpl_GetData,
814     IWineD3DBaseSurfaceImpl_SetFormat,
815     IWineGDISurfaceImpl_PrivateSetup,
816     IWineGDISurfaceImpl_ModifyLocation,
817     IWineGDISurfaceImpl_LoadLocation
818 };