credui: Add a banner and message box to the dialog presented by CredUIPromptForCreden...
[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
216     if (!(This->Flags & SFLAG_LOCKABLE))
217     {
218         /* This is some GL specific thing, see the OpenGL version of
219          * this method, but check for the flag and write a trace
220          */
221         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
222     }
223
224     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
225           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
226
227     if(!This->resource.allocatedMemory) {
228         HDC hdc;
229         HRESULT hr;
230         /* This happens on gdi surfaces if the application set a user pointer and resets it.
231          * Recreate the DIB section
232          */
233         hr = IWineD3DSurface_GetDC(iface, &hdc);  /* will recursively call lockrect, do not set the LOCKED flag to this line */
234         if(hr != WINED3D_OK) return hr;
235         hr = IWineD3DSurface_ReleaseDC(iface, hdc);
236         if(hr != WINED3D_OK) return hr;
237     }
238
239     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
240
241     if (NULL == pRect)
242     {
243         pLockedRect->pBits = This->resource.allocatedMemory;
244         This->lockedRect.left   = 0;
245         This->lockedRect.top    = 0;
246         This->lockedRect.right  = This->currentDesc.Width;
247         This->lockedRect.bottom = This->currentDesc.Height;
248
249         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
250         &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
251         This->lockedRect.right, This->lockedRect.bottom);
252     }
253     else
254     {
255         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
256               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
257
258         if (This->resource.format == WINED3DFMT_DXT1)
259         {
260             /* DXT1 is half byte per pixel */
261             pLockedRect->pBits = This->resource.allocatedMemory +
262                                   (pLockedRect->Pitch * pRect->top) +
263                                   ((pRect->left * This->bytesPerPixel / 2));
264         }
265         else
266         {
267             pLockedRect->pBits = This->resource.allocatedMemory +
268                                  (pLockedRect->Pitch * pRect->top) +
269                                  (pRect->left * This->bytesPerPixel);
270         }
271         This->lockedRect.left   = pRect->left;
272         This->lockedRect.top    = pRect->top;
273         This->lockedRect.right  = pRect->right;
274         This->lockedRect.bottom = pRect->bottom;
275     }
276
277     /* No dirtifying is needed for this surface implementation */
278     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
279
280     This->Flags |= SFLAG_LOCKED;
281     return WINED3D_OK;
282 }
283
284 /*****************************************************************************
285  * IWineD3DSurface::UnlockRect, GDI version
286  *
287  * Unlocks a surface. This implementation doesn't do much, except updating
288  * the window if the front buffer is unlocked
289  *
290  * Returns:
291  *  WINED3D_OK on success
292  *  WINED3DERR_INVALIDCALL on failure
293  *
294  *****************************************************************************/
295 static HRESULT WINAPI
296 IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface)
297 {
298     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
299     IWineD3DDeviceImpl *dev = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
300     TRACE("(%p)\n", This);
301
302     if (!(This->Flags & SFLAG_LOCKED))
303     {
304         WARN("trying to Unlock an unlocked surf@%p\n", This);
305         return WINED3DERR_INVALIDCALL;
306     }
307
308     /* Can be useful for debugging */
309 #if 0
310         {
311             static unsigned int gen = 0;
312             char buffer[4096];
313             ++gen;
314             if ((gen % 10) == 0) {
315                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
316                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
317             }
318             /*
319              * debugging crash code
320             if (gen == 250) {
321               void** test = NULL;
322               *test = 0;
323             }
324             */
325         }
326 #endif
327
328     /* Update the screen */
329     if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary)
330     {
331         x11_copy_to_screen(This, &This->lockedRect);
332     }
333
334     This->Flags &= ~SFLAG_LOCKED;
335     memset(&This->lockedRect, 0, sizeof(RECT));
336     return WINED3D_OK;
337 }
338
339 /*****************************************************************************
340  * IWineD3DSurface::Flip, GDI version
341  *
342  * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
343  * the parent library. This implementation changes the data pointers of the
344  * surfaces and copies the new front buffer content to the screen
345  *
346  * Params:
347  *  override: Flipping target(e.g. back buffer)
348  *
349  * Returns:
350  *  WINED3D_OK on success
351  *
352  *****************************************************************************/
353 static HRESULT WINAPI
354 IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
355                          IWineD3DSurface *override,
356                          DWORD Flags)
357 {
358     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
359     IWineD3DSurfaceImpl *Target = (IWineD3DSurfaceImpl *) override;
360     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
361
362     TRACE("(%p) Flipping to surface %p\n", This, Target);
363
364     if(Target == NULL)
365     {
366         ERR("(%p): Can't flip without a target\n", This);
367         return WINED3DERR_INVALIDCALL;
368     }
369
370     /* Flip the DC */
371     {
372         HDC tmp;
373         tmp = This->hDC;
374         This->hDC = Target->hDC;
375         Target->hDC = tmp;
376     }
377
378     /* Flip the DIBsection */
379     {
380         HBITMAP tmp;
381         tmp = This->dib.DIBsection;
382         This->dib.DIBsection = Target->dib.DIBsection;
383         Target->dib.DIBsection = tmp;
384     }
385
386     /* Flip the surface data */
387     {
388         void* tmp;
389
390         tmp = This->dib.bitmap_data;
391         This->dib.bitmap_data = Target->dib.bitmap_data;
392         Target->dib.bitmap_data = tmp;
393
394         tmp = This->resource.allocatedMemory;
395         This->resource.allocatedMemory = Target->resource.allocatedMemory;
396         Target->resource.allocatedMemory = tmp;
397     }
398
399     /* client_memory should not be different, but just in case */
400     {
401         BOOL tmp;
402         tmp = This->dib.client_memory;
403         This->dib.client_memory = Target->dib.client_memory;
404         Target->dib.client_memory = tmp;
405     }
406
407     /* Useful for debugging */
408 #if 0
409         {
410             static unsigned int gen = 0;
411             char buffer[4096];
412             ++gen;
413             if ((gen % 10) == 0) {
414                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
415                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
416             }
417             /*
418              * debugging crash code
419             if (gen == 250) {
420               void** test = NULL;
421               *test = 0;
422             }
423             */
424         }
425 #endif
426
427     /* Update the screen */
428     x11_copy_to_screen(This, NULL);
429
430     /* FPS support */
431     if (TRACE_ON(fps))
432     {
433         static long prev_time, frames;
434
435         DWORD time = GetTickCount();
436         frames++;
437         /* every 1.5 seconds */
438         if (time - prev_time > 1500) {
439             TRACE_(fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
440             prev_time = time;
441             frames = 0;
442         }
443     }
444
445     return WINED3D_OK;
446 }
447
448 /*****************************************************************************
449  * IWineD3DSurface::LoadTexture, GDI version
450  *
451  * This is mutually unsupported by GDI surfaces
452  *
453  * Returns:
454  *  D3DERR_INVALIDCALL
455  *
456  *****************************************************************************/
457 HRESULT WINAPI
458 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode)
459 {
460     ERR("Unsupported on X11 surfaces\n");
461     return WINED3DERR_INVALIDCALL;
462 }
463
464 /*****************************************************************************
465  * IWineD3DSurface::SaveSnapshot, GDI version
466  *
467  * This method writes the surface's contents to the in tga format to the
468  * file specified in filename.
469  *
470  * Params:
471  *  filename: File to write to
472  *
473  * Returns:
474  *  WINED3DERR_INVALIDCALL if the file couldn't be opened
475  *  WINED3D_OK on success
476  *
477  *****************************************************************************/
478 static int get_shift(DWORD color_mask) {
479     int shift = 0;
480     while (color_mask > 0xFF) {
481         color_mask >>= 1;
482         shift += 1;
483     }
484     while ((color_mask & 0x80) == 0) {
485         color_mask <<= 1;
486         shift -= 1;
487     }
488     return shift;
489 }
490
491
492 HRESULT WINAPI
493 IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
494 const char* filename)
495 {
496     FILE* f = NULL;
497     UINT y = 0, x = 0;
498     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
499     static char *output = NULL;
500     static int size = 0;
501     const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
502
503     if (This->pow2Width > size) {
504         output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
505         size = This->pow2Width;
506     }
507
508
509     f = fopen(filename, "w+");
510     if (NULL == f) {
511         ERR("opening of %s failed with\n", filename);
512         return WINED3DERR_INVALIDCALL;
513     }
514     fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);
515
516     if (This->resource.format == WINED3DFMT_P8) {
517         unsigned char table[256][3];
518         int i;
519
520         if (This->palette == NULL) {
521             fclose(f);
522             return WINED3DERR_INVALIDCALL;
523         }
524         for (i = 0; i < 256; i++) {
525             table[i][0] = This->palette->palents[i].peRed;
526             table[i][1] = This->palette->palents[i].peGreen;
527             table[i][2] = This->palette->palents[i].peBlue;
528         }
529         for (y = 0; y < This->pow2Height; y++) {
530             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
531             for (x = 0; x < This->pow2Width; x++) {
532                 unsigned char color = *src;
533                 src += 1;
534
535                 output[3 * x + 0] = table[color][0];
536                 output[3 * x + 1] = table[color][1];
537                 output[3 * x + 2] = table[color][2];
538             }
539             fwrite(output, 3 * This->pow2Width, 1, f);
540         }
541     } else {
542         int red_shift, green_shift, blue_shift, pix_width;
543
544         pix_width = This->bytesPerPixel;
545
546         red_shift = get_shift(formatEntry->redMask);
547         green_shift = get_shift(formatEntry->greenMask);
548         blue_shift = get_shift(formatEntry->blueMask);
549
550         for (y = 0; y < This->pow2Height; y++) {
551             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
552             for (x = 0; x < This->pow2Width; x++) {         
553                 unsigned int color;
554                 unsigned int comp;
555                 int i;
556
557                 color = 0;
558                 for (i = 0; i < pix_width; i++) {
559                     color |= src[i] << (8 * i);
560                 }
561                 src += 1 * pix_width;
562
563                 comp = color & formatEntry->redMask;
564                 output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
565                 comp = color & formatEntry->greenMask;
566                 output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
567                 comp = color & formatEntry->blueMask;
568                 output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift;
569             }
570             fwrite(output, 3 * This->pow2Width, 1, f);
571         }
572     }
573     fclose(f);
574     return WINED3D_OK;
575 }
576
577 HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
578     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
579     WINED3DLOCKED_RECT lock;
580     HRESULT hr;
581     RGBQUAD col[256];
582
583     TRACE("(%p)->(%p)\n",This,pHDC);
584
585     if(This->Flags & SFLAG_USERPTR) {
586         ERR("Not supported on surfaces with an application-provided surfaces\n");
587         return WINEDDERR_NODC;
588     }
589
590     /* Give more detailed info for ddraw */
591     if (This->Flags & SFLAG_DCINUSE)
592         return WINEDDERR_DCALREADYCREATED;
593
594     /* Can't GetDC if the surface is locked */
595     if (This->Flags & SFLAG_LOCKED)
596         return WINED3DERR_INVALIDCALL;
597
598     memset(&lock, 0, sizeof(lock)); /* To be sure */
599
600     /* Should have a DIB section already */
601
602     /* Lock the surface */
603     hr = IWineD3DSurface_LockRect(iface,
604                                   &lock,
605                                   NULL,
606                                   0);
607     if(FAILED(hr)) {
608         ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
609         /* keep the dib section */
610         return hr;
611     }
612
613     if(This->resource.format == WINED3DFMT_P8 ||
614        This->resource.format == WINED3DFMT_A8P8) {
615         unsigned int n;
616         if(This->palette) {
617             PALETTEENTRY ent[256];
618
619             GetPaletteEntries(This->palette->hpal, 0, 256, ent);
620             for (n=0; n<256; n++) {
621                 col[n].rgbRed   = ent[n].peRed;
622                 col[n].rgbGreen = ent[n].peGreen;
623                 col[n].rgbBlue  = ent[n].peBlue;
624                 col[n].rgbReserved = 0;
625             }
626         } else {
627             IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
628
629             for (n=0; n<256; n++) {
630                 col[n].rgbRed   = device->palettes[device->currentPalette][n].peRed;
631                 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
632                 col[n].rgbBlue  = device->palettes[device->currentPalette][n].peBlue;
633                 col[n].rgbReserved = 0;
634             }
635
636         }
637         SetDIBColorTable(This->hDC, 0, 256, col);
638     }
639
640     *pHDC = This->hDC;
641     TRACE("returning %p\n",*pHDC);
642     This->Flags |= SFLAG_DCINUSE;
643
644     return WINED3D_OK;
645 }
646
647 HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
648     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
649
650     TRACE("(%p)->(%p)\n",This,hDC);
651
652     if (!(This->Flags & SFLAG_DCINUSE))
653         return WINED3DERR_INVALIDCALL;
654
655     if (This->hDC !=hDC) {
656         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
657         return WINED3DERR_INVALIDCALL;
658     }
659
660     /* we locked first, so unlock now */
661     IWineD3DSurface_UnlockRect(iface);
662
663     This->Flags &= ~SFLAG_DCINUSE;
664
665     return WINED3D_OK;
666 }
667
668 /*****************************************************************************
669  * IWineD3DSurface::PrivateSetup, GDI version
670  *
671  * Initializes the GDI surface, aka creates the DIB section we render to
672  * The DIB section creation is done by calling GetDC, which will create the
673  * section and releasing the dc to allow the app to use it. The dib section
674  * will stay until the surface is released
675  *
676  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
677  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
678  * avoid confusion in the shared surface code.
679  *
680  * Returns:
681  *  WINED3D_OK on success
682  *  The return values of called methods on failure
683  *
684  *****************************************************************************/
685 HRESULT WINAPI
686 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
687 {
688     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
689
690     if(This->resource.usage & WINED3DUSAGE_OVERLAY)
691     {
692         ERR("(%p) Overlays not yet supported by GDI surfaces\n", This);
693         return WINED3DERR_INVALIDCALL;
694     }
695     /* Sysmem textures have memory already allocated -
696      * release it, this avoids an unnecessary memcpy
697      */
698     HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
699     This->resource.allocatedMemory = NULL;
700
701     /* We don't mind the nonpow2 stuff in GDI */
702     This->pow2Width = This->currentDesc.Width;
703     This->pow2Height = This->currentDesc.Height;
704
705     IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
706     This->resource.allocatedMemory = This->dib.bitmap_data;
707
708     return WINED3D_OK;
709 }
710
711 void WINAPI IWineGDISurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
712     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
713
714     /* Ignore 0 textureName and target. D3D textures can be created with gdi surfaces as plain
715      * containers, but they're useless until the app creates a d3d device from a d3d point of
716      * view, it's not an implementation limitation. This avoids false warnings when the texture
717      * is destroyed and sets the description back to 0/0
718      */
719     if(textureName != 0 || target != 0) {
720         FIXME("(%p) : Should not be called on a GDI surface. textureName %u, target %i\n", This, textureName, target);
721         DebugBreak();
722     }
723 }
724
725 void WINAPI IWineGDISurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
726     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
727     FIXME("(%p) : Should not be called on a GDI surface\n", This);
728     *glDescription = NULL;
729 }
730
731 HRESULT WINAPI IWineGDISurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
732     /* GDI surface data can only be in one location, the system memory dib section. So they are
733      * always clean by definition.
734      */
735     TRACE("No dirtification in GDI surfaces\n");
736     return WINED3D_OK;
737 }
738
739 HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
740     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
741
742     /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
743     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
744         ERR("Not supported on render targets\n");
745         return WINED3DERR_INVALIDCALL;
746     }
747
748     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
749         WARN("Surface is locked or the HDC is in use\n");
750         return WINED3DERR_INVALIDCALL;
751     }
752
753     if(Mem && Mem != This->resource.allocatedMemory) {
754         void *release = NULL;
755
756         /* Do I have to copy the old surface content? */
757         if(This->Flags & SFLAG_DIBSECTION) {
758                 /* Release the DC. No need to hold the critical section for the update
759             * Thread because this thread runs only on front buffers, but this method
760             * fails for render targets in the check above.
761                 */
762             SelectObject(This->hDC, This->dib.holdbitmap);
763             DeleteDC(This->hDC);
764             /* Release the DIB section */
765             DeleteObject(This->dib.DIBsection);
766             This->dib.bitmap_data = NULL;
767             This->resource.allocatedMemory = NULL;
768             This->hDC = NULL;
769             This->Flags &= ~SFLAG_DIBSECTION;
770         } else if(!(This->Flags & SFLAG_USERPTR)) {
771             release = This->resource.allocatedMemory;
772         }
773         This->resource.allocatedMemory = Mem;
774         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
775
776         /* Now free the old memory if any */
777         HeapFree(GetProcessHeap(), 0, release);
778     } else if(This->Flags & SFLAG_USERPTR) {
779         /* Lockrect and GetDC will re-create the dib section and allocated memory */
780         This->resource.allocatedMemory = NULL;
781         This->Flags &= ~SFLAG_USERPTR;
782     }
783     return WINED3D_OK;
784 }
785
786 /* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
787  * only IWineD3DBaseSurface and IWineGDISurface ones.
788  */
789 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
790 {
791     /* IUnknown */
792     IWineD3DBaseSurfaceImpl_QueryInterface,
793     IWineD3DBaseSurfaceImpl_AddRef,
794     IWineGDISurfaceImpl_Release,
795     /* IWineD3DResource */
796     IWineD3DBaseSurfaceImpl_GetParent,
797     IWineD3DBaseSurfaceImpl_GetDevice,
798     IWineD3DBaseSurfaceImpl_SetPrivateData,
799     IWineD3DBaseSurfaceImpl_GetPrivateData,
800     IWineD3DBaseSurfaceImpl_FreePrivateData,
801     IWineD3DBaseSurfaceImpl_SetPriority,
802     IWineD3DBaseSurfaceImpl_GetPriority,
803     IWineGDISurfaceImpl_PreLoad,
804     IWineD3DBaseSurfaceImpl_GetType,
805     /* IWineD3DSurface */
806     IWineD3DBaseSurfaceImpl_GetContainer,
807     IWineD3DBaseSurfaceImpl_GetDesc,
808     IWineGDISurfaceImpl_LockRect,
809     IWineGDISurfaceImpl_UnlockRect,
810     IWineGDISurfaceImpl_GetDC,
811     IWineGDISurfaceImpl_ReleaseDC,
812     IWineGDISurfaceImpl_Flip,
813     IWineD3DBaseSurfaceImpl_Blt,
814     IWineD3DBaseSurfaceImpl_GetBltStatus,
815     IWineD3DBaseSurfaceImpl_GetFlipStatus,
816     IWineD3DBaseSurfaceImpl_IsLost,
817     IWineD3DBaseSurfaceImpl_Restore,
818     IWineD3DBaseSurfaceImpl_BltFast,
819     IWineD3DBaseSurfaceImpl_GetPalette,
820     IWineD3DBaseSurfaceImpl_SetPalette,
821     IWineD3DBaseSurfaceImpl_RealizePalette,
822     IWineD3DBaseSurfaceImpl_SetColorKey,
823     IWineD3DBaseSurfaceImpl_GetPitch,
824     IWineGDISurfaceImpl_SetMem,
825     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
826     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
827     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
828     IWineD3DBaseSurfaceImpl_UpdateOverlay,
829     IWineD3DBaseSurfaceImpl_SetClipper,
830     IWineD3DBaseSurfaceImpl_GetClipper,
831     /* Internal use: */
832     IWineGDISurfaceImpl_AddDirtyRect,
833     IWineGDISurfaceImpl_LoadTexture,
834     IWineGDISurfaceImpl_SaveSnapshot,
835     IWineD3DBaseSurfaceImpl_SetContainer,
836     IWineGDISurfaceImpl_SetGlTextureDesc,
837     IWineGDISurfaceImpl_GetGlDesc,
838     IWineD3DSurfaceImpl_GetData,
839     IWineD3DBaseSurfaceImpl_SetFormat,
840     IWineGDISurfaceImpl_PrivateSetup
841 };