wined3d: Fix NULL dereference in generator function.
[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 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
38 /*****************************************************************************
39  * x11_copy_to_screen
40  *
41  * Helper function that blts the front buffer contents to the target window
42  *
43  * Params:
44  *  This: Surface to copy from
45  *  rc: Rectangle to copy
46  *
47  *****************************************************************************/
48 static void
49 x11_copy_to_screen(IWineD3DSurfaceImpl *This,
50                    LPRECT rc)
51 {
52     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
53     {
54         POINT offset = {0,0};
55         HWND hDisplayWnd;
56         HDC hDisplayDC;
57         HDC hSurfaceDC = 0;
58         RECT drawrect;
59         TRACE("(%p)->(%p): Copying to screen\n", This, rc);
60
61         hSurfaceDC = This->hDC;
62
63         hDisplayWnd = This->resource.wineD3DDevice->ddraw_window;
64         hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
65         if(rc)
66         {
67             TRACE(" copying rect (%ld,%ld)->(%ld,%ld), offset (%ld,%ld)\n",
68             rc->left, rc->top, rc->right, rc->bottom, offset.x, offset.y);
69         }
70 #if 0
71         /* FIXME: this doesn't work... if users really want to run
72         * X in 8bpp, then we need to call directly into display.drv
73         * (or Wine's equivalent), and force a private colormap
74         * without default entries. */
75         if (This->palette) {
76             SelectPalette(hDisplayDC, This->palette->hpal, FALSE);
77             RealizePalette(hDisplayDC); /* sends messages => deadlocks */
78         }
79 #endif
80         drawrect.left   = 0;
81         drawrect.right  = This->currentDesc.Width;
82         drawrect.top    = 0;
83         drawrect.bottom = This->currentDesc.Height;
84
85 #if 0
86         /* TODO: Support clippers */
87         if (This->clipper)
88         {
89             RECT xrc;
90             HWND hwnd = This->clipper->hWnd;
91             if (hwnd && GetClientRect(hwnd,&xrc))
92             {
93                 OffsetRect(&xrc,offset.x,offset.y);
94                 IntersectRect(&drawrect,&drawrect,&xrc);
95             }
96         }
97 #endif
98         if (rc)
99         {
100             IntersectRect(&drawrect,&drawrect,rc);
101         }
102         else
103         {
104             /* Only use this if the caller did not pass a rectangle, since
105              * due to double locking this could be the wrong one ...
106              */
107             if (This->lockedRect.left != This->lockedRect.right)
108             {
109                 IntersectRect(&drawrect,&drawrect,&This->lockedRect);
110             }
111         }
112
113         BitBlt(hDisplayDC,
114                drawrect.left-offset.x, drawrect.top-offset.y,
115                drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
116                hSurfaceDC,
117                drawrect.left, drawrect.top,
118                SRCCOPY);
119         ReleaseDC(hDisplayWnd, hDisplayDC);
120     }
121 }
122
123 /*****************************************************************************
124  * IWineD3DSurface::PreLoad, GDI version
125  *
126  * This call is unsupported on GDI surfaces, if it's called something went
127  * wrong in the parent library. Write an informative warning
128  *
129  *****************************************************************************/
130 void WINAPI
131 IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
132 {
133     ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
134     ERR("(%p): Most likely the parent library did something wrong.\n", iface);
135     ERR("(%p): Please report to wine-devel\n", iface);
136 }
137
138 /*****************************************************************************
139  * IWineD3DSurface::LockRect, GDI version
140  *
141  * Locks the surface and returns a pointer to the surface memory
142  *
143  * Params:
144  *  pLockedRect: Address to return the locking info at
145  *  pRect: Rectangle to lock
146  *  Flags: Some flags
147  *
148  * Returns:
149  *  WINED3D_OK on success
150  *  WINED3DERR_INVALIDCALL on errors
151  *
152  *****************************************************************************/
153 HRESULT WINAPI
154 IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface,
155                              WINED3DLOCKED_RECT* pLockedRect,
156                              CONST RECT* pRect,
157                              DWORD Flags)
158 {
159     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
160
161     /* Already locked? */
162     if(This->Flags & SFLAG_LOCKED)
163     {
164         ERR("(%p) Surface already locked\n", This);
165         /* What should I return here? */
166         return D3DERR_INVALIDCALL;
167     }
168
169     if (!(This->Flags & SFLAG_LOCKABLE))
170     {
171         /* This is some GL specific thing, see the OpenGL version of
172          * this method, but check for the flag and write a trace
173          */
174         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
175     }
176
177     TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n",
178           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
179
180     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
181
182     if (NULL == pRect)
183     {
184         pLockedRect->pBits = This->resource.allocatedMemory;
185         This->lockedRect.left   = 0;
186         This->lockedRect.top    = 0;
187         This->lockedRect.right  = This->currentDesc.Width;
188         This->lockedRect.bottom = This->currentDesc.Height;
189
190         TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n",
191         &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
192         This->lockedRect.right, This->lockedRect.bottom);
193     }
194     else
195     {
196         TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n",
197               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
198
199         if (This->resource.format == WINED3DFMT_DXT1)
200         {
201             /* DXT1 is half byte per pixel */
202             pLockedRect->pBits = This->resource.allocatedMemory +
203                                   (pLockedRect->Pitch * pRect->top) +
204                                   ((pRect->left * This->bytesPerPixel / 2));
205         }
206         else
207         {
208             pLockedRect->pBits = This->resource.allocatedMemory +
209                                  (pLockedRect->Pitch * pRect->top) +
210                                  (pRect->left * This->bytesPerPixel);
211         }
212         This->lockedRect.left   = pRect->left;
213         This->lockedRect.top    = pRect->top;
214         This->lockedRect.right  = pRect->right;
215         This->lockedRect.bottom = pRect->bottom;
216     }
217
218     /* No dirtifying is needed for this surface implementation */
219     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
220
221     This->Flags |= SFLAG_LOCKED;
222     return D3D_OK;
223 }
224
225 /*****************************************************************************
226  * IWineD3DSurface::UnlockRect, GDI version
227  *
228  * Unlocks a surface. This implementation doesn't do much, except updating
229  * the window if the front buffer is unlocked
230  *
231  * Returns:
232  *  WINED3D_OK on success
233  *  WINED3DERR_INVALIDCALL on failure
234  *
235  *****************************************************************************/
236 HRESULT WINAPI
237 IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface)
238 {
239     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
240     IWineD3DDeviceImpl *dev = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
241     TRACE("(%p)\n", This);
242
243     if (!(This->Flags & SFLAG_LOCKED))
244     {
245         WARN("trying to Unlock an unlocked surf@%p\n", This);
246         return WINED3DERR_INVALIDCALL;
247     }
248
249     /* Can be useful for debugging */
250 #if 0
251         {
252             static unsigned int gen = 0;
253             char buffer[4096];
254             ++gen;
255             if ((gen % 10) == 0) {
256                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
257                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
258             }
259             /*
260              * debugging crash code
261             if (gen == 250) {
262               void** test = NULL;
263               *test = 0;
264             }
265             */
266         }
267 #endif
268
269     /* Update the screen */
270     if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary)
271     {
272         x11_copy_to_screen(This, &This->lockedRect);
273     }
274
275     This->Flags &= ~SFLAG_LOCKED;
276     memset(&This->lockedRect, 0, sizeof(RECT));
277     return WINED3D_OK;
278 }
279
280 /*****************************************************************************
281  * IWineD3DSurface::Flip, GDI version
282  *
283  * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
284  * the parent library. This implementation changes the data pointers of the
285  * surfaces and copies the new front buffer content to the screen
286  *
287  * Params:
288  *  override: Flipping target(e.g. back buffer)
289  *
290  * Returns:
291  *  WINED3D_OK on success
292  *
293  *****************************************************************************/
294 HRESULT WINAPI
295 IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
296                          IWineD3DSurface *override,
297                          DWORD Flags)
298 {
299     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
300     IWineD3DSurfaceImpl *Target = (IWineD3DSurfaceImpl *) override;
301     TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
302
303     TRACE("(%p) Flipping to surface %p\n", This, Target);
304
305     if(Target == NULL)
306     {
307         ERR("(%p): Can't flip without a target\n", This);
308         return WINED3DERR_INVALIDCALL;
309     }
310
311     /* Flip the DC */
312     {
313         HDC tmp;
314         tmp = This->hDC;
315         This->hDC = Target->hDC;
316         Target->hDC = tmp;
317     }
318
319     /* Flip the DIBsection */
320     {
321         HBITMAP tmp;
322         tmp = This->dib.DIBsection;
323         This->dib.DIBsection = Target->dib.DIBsection;
324         Target->dib.DIBsection = tmp;
325     }
326
327     /* Flip the surface data */
328     {
329         void* tmp;
330
331         tmp = This->dib.bitmap_data;
332         This->dib.bitmap_data = Target->dib.bitmap_data;
333         Target->dib.bitmap_data = tmp;
334
335         tmp = This->resource.allocatedMemory;
336         This->resource.allocatedMemory = Target->resource.allocatedMemory;
337         Target->resource.allocatedMemory = tmp;
338     }
339
340     /* client_memory should not be different, but just in case */
341     {
342         BOOL tmp;
343         tmp = This->dib.client_memory;
344         This->dib.client_memory = Target->dib.client_memory;
345         Target->dib.client_memory = tmp;
346     }
347
348     /* Useful for debugging */
349 #if 0
350         {
351             static unsigned int gen = 0;
352             char buffer[4096];
353             ++gen;
354             if ((gen % 10) == 0) {
355                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
356                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
357             }
358             /*
359              * debugging crash code
360             if (gen == 250) {
361               void** test = NULL;
362               *test = 0;
363             }
364             */
365         }
366 #endif
367
368     /* Update the screen */
369     x11_copy_to_screen(This, NULL);
370
371     return WINED3D_OK;
372 }
373
374 /*****************************************************************************
375  * _Blt_ColorFill
376  *
377  * Helper function that fills a memory area with a specific color
378  *
379  * Params:
380  *  buf: memory address to start filling at
381  *  width, height: Dimensions of the area to fill
382  *  bpp: Bit depth of the surface
383  *  lPitch: pitch of the surface
384  *  color: Color to fill with
385  *
386  *****************************************************************************/
387 static HRESULT
388 _Blt_ColorFill(BYTE *buf,
389                int width, int height,
390                int bpp, LONG lPitch,
391                DWORD color)
392 {
393     int x, y;
394     LPBYTE first;
395
396     /* Do first row */
397
398 #define COLORFILL_ROW(type) \
399 { \
400     type *d = (type *) buf; \
401     for (x = 0; x < width; x++) \
402         d[x] = (type) color; \
403     break; \
404 }
405     switch(bpp)
406     {
407         case 1: COLORFILL_ROW(BYTE)
408         case 2: COLORFILL_ROW(WORD)
409         case 3:
410         {
411             BYTE *d = (BYTE *) buf;
412             for (x = 0; x < width; x++,d+=3)
413             {
414                 d[0] = (color    ) & 0xFF;
415                 d[1] = (color>> 8) & 0xFF;
416                 d[2] = (color>>16) & 0xFF;
417             }
418             break;
419         }
420         case 4: COLORFILL_ROW(DWORD)
421         default:
422             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
423             return DDERR_UNSUPPORTED;
424     }
425
426 #undef COLORFILL_ROW
427
428     /* Now copy first row */
429     first = buf;
430     for (y = 1; y < height; y++)
431     {
432         buf += lPitch;
433         memcpy(buf, first, width * bpp);
434     }
435     return DD_OK;
436 }
437
438 /*****************************************************************************
439  * IWineD3DSurface::Blt, GDI version
440  *
441  * Performs blits to a surface, eighter from a source of source-less blts
442  * This is the main functionality of DirectDraw
443  *
444  * Params:
445  *  DestRect: Destination rectangle to write to
446  *  SrcSurface: Source surface, can be NULL
447  *  SrcRect: Source rectangle
448  *****************************************************************************/
449 HRESULT WINAPI
450 IWineGDISurfaceImpl_Blt(IWineD3DSurface *iface,
451                         RECT *DestRect,
452                         IWineD3DSurface *SrcSurface,
453                         RECT *SrcRect,
454                         DWORD Flags,
455                         DDBLTFX *DDBltFx)
456 {
457     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
458     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
459     RECT                xdst,xsrc;
460     HRESULT             ret = DD_OK;
461     WINED3DLOCKED_RECT  dlock, slock;
462     WINED3DFORMAT       dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
463     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
464     int x, y;
465     LPBYTE dbuf, sbuf;
466     TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
467
468     if (TRACE_ON(d3d_surface))
469     {
470         if (DestRect) TRACE("\tdestrect :%ldx%ld-%ldx%ld\n",
471         DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
472         if (SrcRect) TRACE("\tsrcrect  :%ldx%ld-%ldx%ld\n",
473         SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
474 #if 0
475         TRACE("\tflags: ");
476         DDRAW_dump_DDBLT(Flags);
477         if (Flags & DDBLT_DDFX)
478         {
479             TRACE("\tblitfx: ");
480             DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
481         }
482 #endif
483     }
484
485     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
486     {
487         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
488         return DDERR_SURFACEBUSY;
489     }
490
491     if (Src == This)
492     {
493         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
494         dfmt = This->resource.format;
495         slock = dlock;
496         sfmt = dfmt;
497     }
498     else
499     {
500         if (Src)
501         {
502             IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, D3DLOCK_READONLY);
503             sfmt = Src->resource.format;
504         }
505         dfmt = This->resource.format;
506         IWineD3DSurface_LockRect(iface, &dlock,NULL,0);
507     }
508
509     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~DDBLT_DDFX;
510
511     if (isFourcc(sfmt) && isFourcc(dfmt))
512     {
513         if (sfmt != dfmt)
514         {
515             FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
516             ret = DDERR_INVALIDPIXELFORMAT;
517             goto release;
518         }
519         TRACE("Fourcc->Fourcc copy)\n");
520         memcpy(dlock.pBits, slock.pBits, This->currentDesc.Height * dlock.Pitch);
521         goto release;
522     }
523
524     if (isFourcc(sfmt) &&
525         (!isFourcc(dfmt)))
526     {
527         FIXME("DXTC decompression not supported right now\n");
528         goto release;
529     }
530
531     if (DestRect)
532     {
533         memcpy(&xdst,DestRect,sizeof(xdst));
534     }
535     else
536     {
537         xdst.top        = 0;
538         xdst.bottom     = This->currentDesc.Height;
539         xdst.left       = 0;
540         xdst.right      = This->currentDesc.Width;
541     }
542
543     if (SrcRect)
544     {
545         memcpy(&xsrc,SrcRect,sizeof(xsrc));
546     }
547     else
548     {
549         if (Src)
550         {
551             xsrc.top    = 0;
552             xsrc.bottom = Src->currentDesc.Height;
553             xsrc.left   = 0;
554             xsrc.right  = Src->currentDesc.Width;
555         }
556         else
557         {
558             memset(&xsrc,0,sizeof(xsrc));
559         }
560     }
561
562     /* First check for the validity of source / destination rectangles. This was
563       verified using a test application + by MSDN.
564     */
565     if ((Src != NULL) &&
566         ((xsrc.bottom > Src->currentDesc.Height) || (xsrc.bottom < 0) ||
567         (xsrc.top     > Src->currentDesc.Height) || (xsrc.top    < 0) ||
568         (xsrc.left    > Src->currentDesc.Width)  || (xsrc.left   < 0) ||
569         (xsrc.right   > Src->currentDesc.Width)  || (xsrc.right  < 0) ||
570         (xsrc.right   < xsrc.left)               || (xsrc.bottom < xsrc.top)))
571     {
572         WARN("Application gave us bad source rectangle for Blt.\n");
573         ret = DDERR_INVALIDRECT;
574         goto release;
575     }
576     /* For the Destination rect, it can be out of bounds on the condition that a clipper
577       is set for the given surface.
578     */
579     if ((/*This->clipper == NULL*/ TRUE) &&
580         ((xdst.bottom  > This->currentDesc.Height) || (xdst.bottom < 0) ||
581         (xdst.top      > This->currentDesc.Height) || (xdst.top    < 0) ||
582         (xdst.left     > This->currentDesc.Width)  || (xdst.left   < 0) ||
583         (xdst.right    > This->currentDesc.Width)  || (xdst.right  < 0) ||
584         (xdst.right    < xdst.left)                || (xdst.bottom < xdst.top)))
585     {
586         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
587         ret = DDERR_INVALIDRECT;
588         goto release;
589     }
590
591     /* Now handle negative values in the rectangles. Warning: only supported for now
592       in the 'simple' cases (ie not in any stretching / rotation cases).
593
594       First, the case where nothing is to be done.
595     */
596     if (((xdst.bottom <= 0) || (xdst.right <= 0)         ||
597          (xdst.top    >= (int) This->currentDesc.Height) ||
598          (xdst.left   >= (int) This->currentDesc.Width)) ||
599         ((Src != NULL) &&
600         ((xsrc.bottom <= 0) || (xsrc.right <= 0)     ||
601          (xsrc.top >= (int) Src->currentDesc.Height) ||
602          (xsrc.left >= (int) Src->currentDesc.Width))  ))
603     {
604         TRACE("Nothing to be done !\n");
605         goto release;
606     }
607
608     /* The easy case : the source-less blits.... */
609     if (Src == NULL)
610     {
611         RECT full_rect;
612         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
613
614         full_rect.left   = 0;
615         full_rect.top    = 0;
616         full_rect.right  = This->currentDesc.Width;
617         full_rect.bottom = This->currentDesc.Height;
618         IntersectRect(&temp_rect, &full_rect, &xdst);
619         xdst = temp_rect;
620     }
621     else
622     {
623         /* Only handle clipping on the destination rectangle */
624         int clip_horiz = (xdst.left < 0) || (xdst.right  > (int) This->currentDesc.Width );
625         int clip_vert  = (xdst.top  < 0) || (xdst.bottom > (int) This->currentDesc.Height);
626         if (clip_vert || clip_horiz)
627         {
628             /* Now check if this is a special case or not... */
629             if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
630                 (((xdst.right  - xdst.left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
631                 (Flags & DDBLT_DDFX))
632             {
633                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
634                 goto release;
635             }
636
637             if (clip_horiz)
638             {
639                 if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; }
640                 if (xdst.right > This->currentDesc.Width)
641                 {
642                     xsrc.right -= (xdst.right - (int) This->currentDesc.Width);
643                     xdst.right = (int) This->currentDesc.Width;
644                 }
645             }
646             if (clip_vert)
647             {
648                 if (xdst.top < 0)
649                 {
650                     xsrc.top -= xdst.top;
651                     xdst.top = 0;
652                 }
653                 if (xdst.bottom > This->currentDesc.Height)
654                 {
655                     xsrc.bottom -= (xdst.bottom - (int) This->currentDesc.Height);
656                     xdst.bottom = (int) This->currentDesc.Height;
657                 }
658             }
659             /* And check if after clipping something is still to be done... */
660             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
661                 (xdst.top   >= (int) This->currentDesc.Height)  ||
662                 (xdst.left  >= (int) This->currentDesc.Width)   ||
663                 (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
664                 (xsrc.top >= (int) Src->currentDesc.Height)     ||
665                 (xsrc.left >= (int) Src->currentDesc.Width))
666             {
667                 TRACE("Nothing to be done after clipping !\n");
668                 goto release;
669             }
670         }
671     }
672
673     bpp = This->bytesPerPixel;
674     srcheight = xsrc.bottom - xsrc.top;
675     srcwidth = xsrc.right - xsrc.left;
676     dstheight = xdst.bottom - xdst.top;
677     dstwidth = xdst.right - xdst.left;
678     width = (xdst.right - xdst.left) * bpp;
679
680     assert(width <= dlock.Pitch);
681
682     dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
683
684     if (Flags & DDBLT_WAIT)
685     {
686         static BOOL displayed = FALSE;
687         if (!displayed)
688             FIXME("Can't handle DDBLT_WAIT flag right now.\n");
689         displayed = TRUE;
690         Flags &= ~DDBLT_WAIT;
691     }
692     if (Flags & DDBLT_ASYNC)
693     {
694         static BOOL displayed = FALSE;
695         if (!displayed)
696             FIXME("Can't handle DDBLT_ASYNC flag right now.\n");
697         displayed = TRUE;
698         Flags &= ~DDBLT_ASYNC;
699     }
700     if (Flags & DDBLT_DONOTWAIT)
701     {
702         /* DDBLT_DONOTWAIT appeared in DX7 */
703         static BOOL displayed = FALSE;
704         if (!displayed)
705             FIXME("Can't handle DDBLT_DONOTWAIT flag right now.\n");
706         displayed = TRUE;
707         Flags &= ~DDBLT_DONOTWAIT;
708     }
709
710     /* First, all the 'source-less' blits */
711     if (Flags & DDBLT_COLORFILL)
712     {
713         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
714                             dlock.Pitch, DDBltFx->u5.dwFillColor);
715         Flags &= ~DDBLT_COLORFILL;
716     }
717
718     if (Flags & DDBLT_DEPTHFILL)
719     {
720         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
721     }
722     if (Flags & DDBLT_ROP)
723     {
724         /* Catch some degenerate cases here */
725         switch(DDBltFx->dwROP)
726         {
727             case BLACKNESS:
728                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
729                 break;
730             case 0xAA0029: /* No-op */
731                 break;
732             case WHITENESS:
733                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
734                 break;
735             case SRCCOPY: /* well, we do that below ? */
736                 break;
737             default:
738                 FIXME("Unsupported raster op: %08lx  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
739                 goto error;
740         }
741         Flags &= ~DDBLT_ROP;
742     }
743     if (Flags & DDBLT_DDROPS)
744     {
745         FIXME("\tDdraw Raster Ops: %08lx  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
746     }
747     /* Now the 'with source' blits */
748     if (Src)
749     {
750         LPBYTE sbase;
751         int sx, xinc, sy, yinc;
752
753         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
754             goto release;
755         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
756         xinc = (srcwidth << 16) / dstwidth;
757         yinc = (srcheight << 16) / dstheight;
758
759         if (!Flags)
760         {
761             /* No effects, we can cheat here */
762             if (dstwidth == srcwidth)
763             {
764                 if (dstheight == srcheight)
765                 {
766                     /* No stretching in either direction. This needs to be as
767                     * fast as possible */
768                     sbuf = sbase;
769
770                     /* check for overlapping surfaces */
771                     if (SrcSurface != iface || xdst.top < xsrc.top ||
772                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
773                     {
774                         /* no overlap, or dst above src, so copy from top downwards */
775                         for (y = 0; y < dstheight; y++)
776                         {
777                             memcpy(dbuf, sbuf, width);
778                             sbuf += slock.Pitch;
779                             dbuf += dlock.Pitch;
780                         }
781                     }
782                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
783                     {
784                         sbuf += (slock.Pitch*dstheight);
785                         dbuf += (dlock.Pitch*dstheight);
786                         for (y = 0; y < dstheight; y++)
787                         {
788                             sbuf -= slock.Pitch;
789                             dbuf -= dlock.Pitch;
790                             memcpy(dbuf, sbuf, width);
791                         }
792                     }
793                     else /* src and dst overlapping on the same line, use memmove */
794                     {
795                         for (y = 0; y < dstheight; y++)
796                         {
797                             memmove(dbuf, sbuf, width);
798                             sbuf += slock.Pitch;
799                             dbuf += dlock.Pitch;
800                         }
801                     }
802                 } else {
803                     /* Stretching in Y direction only */
804                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
805                         sbuf = sbase + (sy >> 16) * slock.Pitch;
806                         memcpy(dbuf, sbuf, width);
807                         dbuf += dlock.Pitch;
808                     }
809                 }
810             }
811             else
812             {
813                 /* Stretching in X direction */
814                 int last_sy = -1;
815                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
816                 {
817                     sbuf = sbase + (sy >> 16) * slock.Pitch;
818
819                     if ((sy >> 16) == (last_sy >> 16))
820                     {
821                         /* this sourcerow is the same as last sourcerow -
822                          * copy already stretched row
823                          */
824                         memcpy(dbuf, dbuf - dlock.Pitch, width);
825                     }
826                     else
827                     {
828 #define STRETCH_ROW(type) { \
829                     type *s = (type *) sbuf, *d = (type *) dbuf; \
830                     for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
831                     d[x] = s[sx >> 16]; \
832                     break; }
833
834                     switch(bpp)
835                     {
836                         case 1: STRETCH_ROW(BYTE)
837                         case 2: STRETCH_ROW(WORD)
838                         case 4: STRETCH_ROW(DWORD)
839                         case 3:
840                         {
841                             LPBYTE s,d = dbuf;
842                             for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
843                             {
844                                 DWORD pixel;
845
846                                 s = sbuf+3*(sx>>16);
847                                 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
848                                 d[0] = (pixel    )&0xff;
849                                 d[1] = (pixel>> 8)&0xff;
850                                 d[2] = (pixel>>16)&0xff;
851                                 d+=3;
852                             }
853                             break;
854                     }
855                     default:
856                         FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
857                         ret = DDERR_UNSUPPORTED;
858                         goto error;
859                     }
860 #undef STRETCH_ROW
861                     }
862                     dbuf += dlock.Pitch;
863                     last_sy = sy;
864                 }
865             }
866         }
867         else
868         {
869           LONG dstyinc = dlock.Pitch, dstxinc = bpp;
870           DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
871           if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE))
872           {
873
874               if (Flags & DDBLT_KEYSRC)
875               {
876                 keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
877                 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
878               }
879               else if (Flags & DDBLT_KEYDEST)
880               {
881                 keylow  = This->DestBltCKey.dwColorSpaceLowValue;
882                 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
883               }
884               else if (Flags & DDBLT_KEYSRCOVERRIDE)
885               {
886                 keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
887                 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
888               }
889               else
890               {
891                 keylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
892                 keyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
893               }
894               if(bpp == 1)
895               {
896                   keymask = 0xff;
897               }
898               else
899               {
900                   keymask = get_bitmask_red(Src->resource.format)   |
901                             get_bitmask_green(Src->resource.format) |
902                             get_bitmask_blue(Src->resource.format);
903               }
904               Flags &= ~(DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE);
905           }
906
907           if (Flags & DDBLT_DDFX)
908           {
909               LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
910               LONG tmpxy;
911               dTopLeft     = dbuf;
912               dTopRight    = dbuf+((dstwidth-1)*bpp);
913               dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
914               dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
915
916               if (DDBltFx->dwDDFX & DDBLTFX_ARITHSTRETCHY)
917               {
918                 /* I don't think we need to do anything about this flag */
919                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ARITHSTRETCHY\n");
920               }
921               if (DDBltFx->dwDDFX & DDBLTFX_MIRRORLEFTRIGHT)
922               {
923                 tmp          = dTopRight;
924                 dTopRight    = dTopLeft;
925                 dTopLeft     = tmp;
926                 tmp          = dBottomRight;
927                 dBottomRight = dBottomLeft;
928                 dBottomLeft  = tmp;
929                 dstxinc = dstxinc *-1;
930               }
931               if (DDBltFx->dwDDFX & DDBLTFX_MIRRORUPDOWN)
932               {
933                 tmp          = dTopLeft;
934                 dTopLeft     = dBottomLeft;
935                 dBottomLeft  = tmp;
936                 tmp          = dTopRight;
937                 dTopRight    = dBottomRight;
938                 dBottomRight = tmp;
939                 dstyinc = dstyinc *-1;
940               }
941               if (DDBltFx->dwDDFX & DDBLTFX_NOTEARING)
942               {
943                 /* I don't think we need to do anything about this flag */
944                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_NOTEARING\n");
945               }
946               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE180)
947               {
948                 tmp          = dBottomRight;
949                 dBottomRight = dTopLeft;
950                 dTopLeft     = tmp;
951                 tmp          = dBottomLeft;
952                 dBottomLeft  = dTopRight;
953                 dTopRight    = tmp;
954                 dstxinc = dstxinc * -1;
955                 dstyinc = dstyinc * -1;
956               }
957               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE270)
958               {
959                 tmp          = dTopLeft;
960                 dTopLeft     = dBottomLeft;
961                 dBottomLeft  = dBottomRight;
962                 dBottomRight = dTopRight;
963                 dTopRight    = tmp;
964                 tmpxy   = dstxinc;
965                 dstxinc = dstyinc;
966                 dstyinc = tmpxy;
967                 dstxinc = dstxinc * -1;
968               }
969               if (DDBltFx->dwDDFX & DDBLTFX_ROTATE90)
970               {
971                 tmp          = dTopLeft;
972                 dTopLeft     = dTopRight;
973                 dTopRight    = dBottomRight;
974                 dBottomRight = dBottomLeft;
975                 dBottomLeft  = tmp;
976                 tmpxy   = dstxinc;
977                 dstxinc = dstyinc;
978                 dstyinc = tmpxy;
979                 dstyinc = dstyinc * -1;
980               }
981               if (DDBltFx->dwDDFX & DDBLTFX_ZBUFFERBASEDEST)
982               {
983                 /* I don't think we need to do anything about this flag */
984                 WARN("Flags=DDBLT_DDFX nothing done for DDBLTFX_ZBUFFERBASEDEST\n");
985               }
986               dbuf = dTopLeft;
987               Flags &= ~(DDBLT_DDFX);
988           }
989
990 #define COPY_COLORKEY_FX(type) { \
991             type *s, *d = (type *) dbuf, *dx, tmp; \
992             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
993               s = (type*)(sbase + (sy >> 16) * slock.Pitch); \
994               dx = d; \
995               for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
996                   tmp = s[sx >> 16]; \
997                   if ((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) dx[0] = tmp; \
998                   dx = (type*)(((LPBYTE)dx)+dstxinc); \
999               } \
1000               d = (type*)(((LPBYTE)d)+dstyinc); \
1001             } \
1002             break; }
1003
1004             switch (bpp) {
1005             case 1: COPY_COLORKEY_FX(BYTE)
1006             case 2: COPY_COLORKEY_FX(WORD)
1007             case 4: COPY_COLORKEY_FX(DWORD)
1008             case 3:
1009             {
1010                 LPBYTE s,d = dbuf, dx;
1011                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1012                 {
1013                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1014                     dx = d;
1015                     for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1016                     {
1017                         DWORD pixel;
1018                         s = sbuf+3*(sx>>16);
1019                         pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1020                         if ((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
1021                         {
1022                             dx[0] = (pixel    )&0xff;
1023                             dx[1] = (pixel>> 8)&0xff;
1024                             dx[2] = (pixel>>16)&0xff;
1025                         }
1026                         dx+= dstxinc;
1027                     }
1028                     d += dstyinc;
1029                 }
1030                 break;
1031             }
1032             default:
1033               FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1034                   (Flags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1035                   ret = DDERR_UNSUPPORTED;
1036                   goto error;
1037 #undef COPY_COLORKEY_FX
1038             }
1039         }
1040     }
1041
1042 error:
1043     if (Flags && FIXME_ON(d3d_surface))
1044     {
1045         FIXME("\tUnsupported flags: %08lx", Flags);
1046     }
1047
1048 release:
1049     IWineD3DSurface_UnlockRect(iface);
1050     if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface);
1051     return ret;
1052 }
1053
1054 /*****************************************************************************
1055  * IWineD3DSurface::BltFast, GDI version
1056  *
1057  * This is the software implementation of BltFast, as used by GDI surfaces
1058  * and as a fallback for OpenGL surfaces. This code is taken from the old
1059  * DirectDraw code, and was originally written by TransGaming.
1060  *
1061  * Params:
1062  *  dstx:
1063  *  dsty:
1064  *  Source: Source surface to copy from
1065  *  rsrc: Source rectangle
1066  *  trans: Some Flags
1067  *
1068  * Returns:
1069  *  WINED3D_OK on success
1070  *
1071  *****************************************************************************/
1072 HRESULT WINAPI
1073 IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface,
1074                             DWORD dstx,
1075                             DWORD dsty,
1076                             IWineD3DSurface *Source,
1077                             RECT *rsrc,
1078                             DWORD trans)
1079 {
1080     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1081     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1082
1083     int                 bpp, w, h, x, y;
1084     WINED3DLOCKED_RECT  dlock,slock;
1085     HRESULT             ret = DD_OK;
1086     RECT                rsrc2;
1087     RECT                lock_src, lock_dst, lock_union;
1088     BYTE                *sbuf, *dbuf;
1089
1090     if (TRACE_ON(d3d_surface))
1091     {
1092         TRACE("(%p)->(%ld,%ld,%p,%p,%08lx)\n", This,dstx,dsty,Src,rsrc,trans);
1093
1094         if (rsrc)
1095         {
1096             TRACE("\tsrcrect: %ldx%ld-%ldx%ld\n",rsrc->left,rsrc->top,
1097                   rsrc->right,rsrc->bottom);
1098         }
1099         else
1100         {
1101             TRACE(" srcrect: NULL\n");
1102         }
1103     }
1104
1105     if ((This->Flags & SFLAG_LOCKED) ||
1106         ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
1107     {
1108         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1109         return DDERR_SURFACEBUSY;
1110     }
1111
1112     if (!rsrc)
1113     {
1114         WARN("rsrc is NULL!\n");
1115         rsrc = &rsrc2;
1116         rsrc->left = 0;
1117         rsrc->top = 0;
1118         rsrc->right = Src->currentDesc.Width;
1119         rsrc->bottom = Src->currentDesc.Height;
1120     }
1121
1122     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1123     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1124         (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1125         (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1126         (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1127         (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1128     {
1129         WARN("Application gave us bad source rectangle for BltFast.\n");
1130         return DDERR_INVALIDRECT;
1131     }
1132
1133     h = rsrc->bottom - rsrc->top;
1134     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1135     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1136     if (h <= 0) return DDERR_INVALIDRECT;
1137
1138     w = rsrc->right - rsrc->left;
1139     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1140     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1141     if (w <= 0) return DDERR_INVALIDRECT;
1142
1143     /* Now compute the locking rectangle... */
1144     lock_src.left = rsrc->left;
1145     lock_src.top = rsrc->top;
1146     lock_src.right = lock_src.left + w;
1147     lock_src.bottom = lock_src.top + h;
1148
1149     lock_dst.left = dstx;
1150     lock_dst.top = dsty;
1151     lock_dst.right = dstx + w;
1152     lock_dst.bottom = dsty + h;
1153
1154     bpp = This->bytesPerPixel;
1155
1156     /* We need to lock the surfaces, or we won't get refreshes when done. */
1157     if (Src == This)
1158     {
1159         int pitch;
1160
1161         UnionRect(&lock_union, &lock_src, &lock_dst);
1162
1163         /* Lock the union of the two rectangles */
1164         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1165         if(ret != D3D_OK) goto error;
1166
1167         pitch = dlock.Pitch;
1168         slock.Pitch = dlock.Pitch;
1169
1170         /* Since slock was originally copied from this surface's description, we can just reuse it */
1171         assert(This->resource.allocatedMemory != NULL);
1172         sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp; 
1173         dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp; 
1174     }
1175     else
1176     {
1177         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, D3DLOCK_READONLY);
1178         if(ret != D3D_OK) goto error;
1179         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1180         if(ret != D3D_OK) goto error;
1181
1182         sbuf = slock.pBits;
1183         dbuf = dlock.pBits;
1184         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1185     }
1186
1187     /* Handle first the FOURCC surfaces... */
1188     if (isFourcc(Src->resource.format) && isFourcc(This->resource.format))
1189     {
1190         TRACE("Fourcc -> Fourcc copy\n");
1191         if (trans)
1192             FIXME("trans arg not supported when a FOURCC surface is involved\n");
1193         if (dstx || dsty)
1194             FIXME("offset for destination surface is not supported\n");
1195         if (Src->resource.format != This->resource.format)
1196         {
1197             FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1198             ret = DDERR_INVALIDPIXELFORMAT;
1199             goto error;
1200         }
1201         /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1202         memcpy(dbuf, sbuf, This->resource.size);
1203         goto error;
1204     }
1205     if ((isFourcc(Src->resource.format)) &&
1206         (!isFourcc(This->resource.format)))
1207     {
1208         /* TODO: Use the libtxc_dxtn.so shared library to do
1209          * software decompression
1210          */
1211         ERR("DXTC decompression not supported by now\n");
1212         goto error;
1213     }
1214
1215     if (trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY))
1216     {
1217         DWORD keylow, keyhigh;
1218         TRACE("Color keyed copy\n");
1219         if (trans & DDBLTFAST_SRCCOLORKEY)
1220         {
1221             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1222             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1223         }
1224         else
1225         {
1226             /* I'm not sure if this is correct */
1227             FIXME("DDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1228             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1229             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1230         }
1231
1232 #define COPYBOX_COLORKEY(type) { \
1233             type *d, *s, tmp; \
1234             s = (type *) sbuf; \
1235             d = (type *) dbuf; \
1236             for (y = 0; y < h; y++) { \
1237                 for (x = 0; x < w; x++) { \
1238                     tmp = s[x]; \
1239                     if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1240                 } \
1241                 s = (type *)((BYTE *)s + slock.Pitch); \
1242                 d = (type *)((BYTE *)d + dlock.Pitch); \
1243             } \
1244             break; \
1245         }
1246
1247         switch (bpp) {
1248             case 1: COPYBOX_COLORKEY(BYTE)
1249             case 2: COPYBOX_COLORKEY(WORD)
1250             case 4: COPYBOX_COLORKEY(DWORD)
1251             case 3:
1252             {
1253                 BYTE *d, *s;
1254                 DWORD tmp;
1255                 s = (BYTE *) sbuf;
1256                 d = (BYTE *) dbuf;
1257                 for (y = 0; y < h; y++)
1258                 {
1259                     for (x = 0; x < w * 3; x += 3)
1260                     {
1261                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1262                         if (tmp < keylow || tmp > keyhigh)
1263                         {
1264                             d[x + 0] = s[x + 0];
1265                             d[x + 1] = s[x + 1];
1266                             d[x + 2] = s[x + 2];
1267                         }
1268                     }
1269                     s += slock.Pitch;
1270                     d += dlock.Pitch;
1271                 }
1272                 break;
1273             }
1274             default:
1275                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1276                 ret = DDERR_UNSUPPORTED;
1277                 goto error;
1278         }
1279 #undef COPYBOX_COLORKEY
1280         TRACE("Copy Done\n");
1281     }
1282     else
1283     {
1284         int width = w * bpp;
1285         TRACE("NO color key copy\n");
1286         for (y = 0; y < h; y++)
1287         {
1288             /* This is pretty easy, a line for line memcpy */
1289             memcpy(dbuf, sbuf, width);
1290             sbuf += slock.Pitch;
1291             dbuf += dlock.Pitch;
1292         }
1293         TRACE("Copy done\n");
1294     }
1295
1296 error:
1297     if (Src == This)
1298     {
1299         IWineD3DSurface_UnlockRect(iface);
1300     }
1301     else
1302     {
1303         IWineD3DSurface_UnlockRect(iface);
1304         IWineD3DSurface_UnlockRect(Source);
1305     }
1306
1307     return ret;
1308 }
1309
1310 /*****************************************************************************
1311  * IWineD3DSurface::LoadTexture, GDI version
1312  *
1313  * This is mutually unsupported by GDI surfaces
1314  *
1315  * Returns:
1316  *  D3DERR_INVALIDCALL
1317  *
1318  *****************************************************************************/
1319 HRESULT WINAPI
1320 IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface)
1321 {
1322     ERR("Unsupported on X11 surfaces\n");
1323     return D3DERR_INVALIDCALL;
1324 }
1325
1326 /*****************************************************************************
1327  * IWineD3DSurface::SaveSnapshot, GDI version
1328  *
1329  * This method writes the surface's contents to the in tga format to the
1330  * file specified in filename.
1331  *
1332  * Params:
1333  *  filename: File to write to
1334  *
1335  * Returns:
1336  *  WINED3DERR_INVALIDCALL if the file couldn't be opened
1337  *  WINED3D_OK on success
1338  *
1339  *****************************************************************************/
1340 static int get_shift(DWORD color_mask) {
1341     int shift = 0;
1342     while (color_mask > 0xFF) {
1343         color_mask >>= 1;
1344         shift += 1;
1345     }
1346     while ((color_mask & 0x80) == 0) {
1347         color_mask <<= 1;
1348         shift -= 1;
1349     }
1350     return shift;
1351 }
1352
1353
1354 HRESULT WINAPI
1355 IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface,
1356 const char* filename)
1357 {
1358     FILE* f = NULL;
1359     UINT y = 0, x = 0;
1360     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1361     static char *output = NULL;
1362     static int size = 0;
1363
1364     if (This->pow2Width > size) {
1365         output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3);
1366         size = This->pow2Width;
1367     }
1368
1369
1370     f = fopen(filename, "w+");
1371     if (NULL == f) {
1372         ERR("opening of %s failed with\n", filename);
1373         return WINED3DERR_INVALIDCALL;
1374     }
1375     fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height);
1376
1377     if (This->resource.format == WINED3DFMT_P8) {
1378         unsigned char table[256][3];
1379         int i;
1380
1381         if (This->palette == NULL) {
1382             fclose(f);
1383             return WINED3DERR_INVALIDCALL;
1384         }
1385         for (i = 0; i < 256; i++) {
1386             table[i][0] = This->palette->palents[i].peRed;
1387             table[i][1] = This->palette->palents[i].peGreen;
1388             table[i][2] = This->palette->palents[i].peBlue;
1389         }
1390         for (y = 0; y < This->pow2Height; y++) {
1391             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1392             for (x = 0; x < This->pow2Width; x++) {
1393                 unsigned char color = *src;
1394                 src += 1;
1395
1396                 output[3 * x + 0] = table[color][0];
1397                 output[3 * x + 1] = table[color][1];
1398                 output[3 * x + 2] = table[color][2];
1399             }
1400             fwrite(output, 3 * This->pow2Width, 1, f);
1401         }
1402     } else {
1403         int red_shift, green_shift, blue_shift, pix_width;
1404
1405         pix_width = This->bytesPerPixel;
1406
1407         red_shift = get_shift(get_bitmask_red(This->resource.format));
1408         green_shift = get_shift(get_bitmask_green(This->resource.format));
1409         blue_shift = get_shift(get_bitmask_blue(This->resource.format));
1410
1411         for (y = 0; y < This->pow2Height; y++) {
1412             unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface));
1413             for (x = 0; x < This->pow2Width; x++) {         
1414                 unsigned int color;
1415                 unsigned int comp;
1416                 int i;
1417
1418                 color = 0;
1419                 for (i = 0; i < pix_width; i++) {
1420                     color |= src[i] << (8 * i);
1421                 }
1422                 src += 1 * pix_width;
1423
1424                 comp = color & get_bitmask_red(This->resource.format);
1425                 output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift;
1426                 comp = color & get_bitmask_green(This->resource.format);
1427                 output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift;
1428                 comp = color & get_bitmask_blue(This->resource.format);
1429                 output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift;
1430             }
1431             fwrite(output, 3 * This->pow2Width, 1, f);
1432         }
1433     }
1434     fclose(f);
1435     return WINED3D_OK;
1436 }
1437
1438 /*****************************************************************************
1439  * IWineD3DSurface::PrivateSetup, GDI version
1440  *
1441  * Initializes the GDI surface, aka creates the DIB section we render to
1442  * The DIB section creation is done by calling GetDC, which will create the
1443  * section and releasing the dc to allow the app to use it. The dib section
1444  * will stay until the surface is released
1445  *
1446  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1447  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1448  * avoid confusion in the shared surface code.
1449  *
1450  * Returns:
1451  *  D3D_OK on success
1452  *  The return values of called methods on failure
1453  *
1454  *****************************************************************************/
1455 HRESULT WINAPI
1456 IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface)
1457 {
1458     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1459     HRESULT hr;
1460     HDC hdc;
1461     long oldsize = This->resource.size;
1462
1463     /* Sysmem textures have memory already allocated -
1464      * release it, this avoids an unnecessary memcpy
1465      */
1466     HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1467     This->resource.allocatedMemory = NULL;
1468
1469     /* We don't mind the nonpow2 stuff in GDI */
1470     This->resource.size = This->currentDesc.Width * D3DFmtGetBpp(This->resource.wineD3DDevice, This->resource.format) * This->currentDesc.Width;
1471     This->pow2Size = This->resource.size;
1472     This->pow2Width = This->currentDesc.Width;
1473     This->pow2Height = This->currentDesc.Height;
1474     This->Flags &= ~SFLAG_NONPOW2;
1475
1476     /* Adjust the opengl mem counter */
1477     globalChangeGlRam(This->resource.size - oldsize);
1478
1479     /* Call GetDC to create a DIB section. We will use that
1480      * DIB section for rendering
1481      *
1482      * Release the DC afterwards to allow the app to use it
1483      */
1484     hr = IWineD3DSurface_GetDC(iface, &hdc);
1485     if(FAILED(hr))
1486     {
1487         ERR("(%p) IWineD3DSurface::GetDC failed with hr %08lx\n", This, hr);
1488         return hr;
1489     }
1490     hr = IWineD3DSurface_ReleaseDC(iface, hdc);
1491     if(FAILED(hr))
1492     {
1493         ERR("(%p) IWineD3DSurface::ReleaseDC failed with hr %08lx\n", This, hr);
1494         return hr;
1495     }
1496
1497     return WINED3D_OK;
1498 }
1499
1500 const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
1501 {
1502     /* IUnknown */
1503     IWineD3DSurfaceImpl_QueryInterface,
1504     IWineD3DSurfaceImpl_AddRef,
1505     IWineD3DSurfaceImpl_Release,
1506     /* IWineD3DResource */
1507     IWineD3DSurfaceImpl_GetParent,
1508     IWineD3DSurfaceImpl_GetDevice,
1509     IWineD3DSurfaceImpl_SetPrivateData,
1510     IWineD3DSurfaceImpl_GetPrivateData,
1511     IWineD3DSurfaceImpl_FreePrivateData,
1512     IWineD3DSurfaceImpl_SetPriority,
1513     IWineD3DSurfaceImpl_GetPriority,
1514     IWineGDISurfaceImpl_PreLoad,
1515     IWineD3DSurfaceImpl_GetType,
1516     /* IWineD3DSurface */
1517     IWineD3DSurfaceImpl_GetContainerParent,
1518     IWineD3DSurfaceImpl_GetContainer,
1519     IWineD3DSurfaceImpl_GetDesc,
1520     IWineGDISurfaceImpl_LockRect,
1521     IWineGDISurfaceImpl_UnlockRect,
1522     IWineD3DSurfaceImpl_GetDC,
1523     IWineD3DSurfaceImpl_ReleaseDC,
1524     IWineGDISurfaceImpl_Flip,
1525     IWineGDISurfaceImpl_Blt,
1526     IWineD3DSurfaceImpl_GetBltStatus,
1527     IWineD3DSurfaceImpl_GetFlipStatus,
1528     IWineD3DSurfaceImpl_IsLost,
1529     IWineD3DSurfaceImpl_Restore,
1530     IWineGDISurfaceImpl_BltFast,
1531     IWineD3DSurfaceImpl_SetPixelFormat,
1532     IWineD3DSurfaceImpl_GetPalette,
1533     IWineD3DSurfaceImpl_SetPalette,
1534     IWineD3DSurfaceImpl_RealizePalette,
1535     IWineD3DSurfaceImpl_SetColorKey,
1536     IWineD3DSurfaceImpl_GetPitch,
1537     /* Internal use: */
1538     IWineD3DSurfaceImpl_CleanDirtyRect,
1539     IWineD3DSurfaceImpl_AddDirtyRect,
1540     IWineGDISurfaceImpl_LoadTexture,
1541     IWineGDISurfaceImpl_SaveSnapshot,
1542     IWineD3DSurfaceImpl_SetContainer,
1543     IWineD3DSurfaceImpl_SetPBufferState,
1544     IWineD3DSurfaceImpl_SetGlTextureDesc,
1545     IWineD3DSurfaceImpl_GetGlDesc,
1546     IWineD3DSurfaceImpl_GetData,
1547     IWineD3DSurfaceImpl_SetFormat,
1548     IWineGDISurfaceImpl_PrivateSetup
1549 };