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