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