wined3d: Use the format info for doing compressed surface blits in BltFast().
[wine] / dlls / wined3d / surface_base.c
1 /*
2  * IWineD3DSurface Implementation of management(non-rendering) functions
3  *
4  * Copyright 1998 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2002-2005 Jason Edmeades
7  * Copyright 2002-2003 Raphael Junqueira
8  * Copyright 2004 Christian Costa
9  * Copyright 2005 Oliver Stieber
10  * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11  * Copyright 2007 Henri Verbeet
12  * Copyright 2006-2007 Roderick Colenbrander
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
32
33 #include <assert.h>
34
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36
37 /* See also float_16_to_32() in wined3d_private.h */
38 static inline unsigned short float_32_to_16(const float *in)
39 {
40     int exp = 0;
41     float tmp = fabs(*in);
42     unsigned int mantissa;
43     unsigned short ret;
44
45     /* Deal with special numbers */
46     if(*in == 0.0) return 0x0000;
47     if(isnan(*in)) return 0x7C01;
48     if(isinf(*in)) return (*in < 0.0 ? 0xFC00 : 0x7c00);
49
50     if(tmp < pow(2, 10)) {
51         do
52         {
53             tmp = tmp * 2.0;
54             exp--;
55         }while(tmp < pow(2, 10));
56     } else if(tmp >= pow(2, 11)) {
57         do
58         {
59             tmp /= 2.0;
60             exp++;
61         }while(tmp >= pow(2, 11));
62     }
63
64     mantissa = (unsigned int) tmp;
65     if(tmp - mantissa >= 0.5) mantissa++; /* round to nearest, away from zero */
66
67     exp += 10;  /* Normalize the mantissa */
68     exp += 15;  /* Exponent is encoded with excess 15 */
69
70     if(exp > 30) { /* too big */
71         ret = 0x7c00; /* INF */
72     } else if(exp <= 0) {
73         /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
74         while(exp <= 0) {
75             mantissa = mantissa >> 1;
76             exp++;
77         }
78         ret = mantissa & 0x3ff;
79     } else {
80         ret = (exp << 10) | (mantissa & 0x3ff);
81     }
82
83     ret |= ((*in < 0.0 ? 1 : 0) << 15); /* Add the sign */
84     return ret;
85 }
86
87
88 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
89
90 /* *******************************************
91    IWineD3DSurface IUnknown parts follow
92    ******************************************* */
93 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
94 {
95     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
96     /* Warn ,but be nice about things */
97     TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
98
99     if (IsEqualGUID(riid, &IID_IUnknown)
100         || IsEqualGUID(riid, &IID_IWineD3DBase)
101         || IsEqualGUID(riid, &IID_IWineD3DResource)
102         || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
103         IUnknown_AddRef((IUnknown*)iface);
104         *ppobj = This;
105         return S_OK;
106         }
107         *ppobj = NULL;
108         return E_NOINTERFACE;
109 }
110
111 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
112     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
113     ULONG ref = InterlockedIncrement(&This->resource.ref);
114     TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
115     return ref;
116 }
117
118 /* ****************************************************
119    IWineD3DSurface IWineD3DResource parts follow
120    **************************************************** */
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
122     return resource_get_device((IWineD3DResource *)iface, ppDevice);
123 }
124
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
126     return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
127 }
128
129 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
130     return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
131 }
132
133 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
134     return resource_free_private_data((IWineD3DResource *)iface, refguid);
135 }
136
137 DWORD   WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
138     return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
139 }
140
141 DWORD   WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
142     return resource_get_priority((IWineD3DResource *)iface);
143 }
144
145 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
146     TRACE("(%p) : calling resourceimpl_GetType\n", iface);
147     return resource_get_type((IWineD3DResource *)iface);
148 }
149
150 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
151     TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
152     return resource_get_parent((IWineD3DResource *)iface, pParent);
153 }
154
155 /* ******************************************************
156    IWineD3DSurface IWineD3DSurface parts follow
157    ****************************************************** */
158
159 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
160     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
161     IWineD3DBase *container = 0;
162
163     TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
164
165     if (!ppContainer) {
166         ERR("Called without a valid ppContainer.\n");
167     }
168
169     /* Standalone surfaces return the device as container. */
170     if (This->container) {
171         container = This->container;
172     } else {
173         container = (IWineD3DBase *)This->resource.wineD3DDevice;
174     }
175
176     TRACE("Relaying to QueryInterface\n");
177     return IUnknown_QueryInterface(container, riid, ppContainer);
178 }
179
180 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
181     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
182
183     TRACE("(%p) : copying into %p\n", This, pDesc);
184     if(pDesc->Format != NULL)             *(pDesc->Format) = This->resource.format_desc->format;
185     if(pDesc->Type != NULL)               *(pDesc->Type)   = This->resource.resourceType;
186     if(pDesc->Usage != NULL)              *(pDesc->Usage)              = This->resource.usage;
187     if(pDesc->Pool != NULL)               *(pDesc->Pool)               = This->resource.pool;
188     if(pDesc->Size != NULL)               *(pDesc->Size)               = This->resource.size;   /* dx8 only */
189     if(pDesc->MultiSampleType != NULL)    *(pDesc->MultiSampleType)    = This->currentDesc.MultiSampleType;
190     if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
191     if(pDesc->Width != NULL)              *(pDesc->Width)              = This->currentDesc.Width;
192     if(pDesc->Height != NULL)             *(pDesc->Height)             = This->currentDesc.Height;
193     return WINED3D_OK;
194 }
195
196 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
197     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
198     TRACE("(%p)->(%x)\n", This, Flags);
199
200     switch (Flags)
201     {
202         case WINEDDGBS_CANBLT:
203         case WINEDDGBS_ISBLTDONE:
204             return WINED3D_OK;
205
206         default:
207             return WINED3DERR_INVALIDCALL;
208     }
209 }
210
211 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
212     /* XXX: DDERR_INVALIDSURFACETYPE */
213
214     TRACE("(%p)->(%08x)\n",iface,Flags);
215     switch (Flags) {
216         case WINEDDGFS_CANFLIP:
217         case WINEDDGFS_ISFLIPDONE:
218             return WINED3D_OK;
219
220         default:
221             return WINED3DERR_INVALIDCALL;
222     }
223 }
224
225 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
226     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
227     TRACE("(%p)\n", This);
228
229     /* D3D8 and 9 loose full devices, ddraw only surfaces */
230     return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
231 }
232
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
234     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235     TRACE("(%p)\n", This);
236
237     /* So far we don't lose anything :) */
238     This->Flags &= ~SFLAG_LOST;
239     return WINED3D_OK;
240 }
241
242 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
243     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
244     IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
245     TRACE("(%p)->(%p)\n", This, Pal);
246
247     if(This->palette == PalImpl) {
248         TRACE("Nop palette change\n");
249         return WINED3D_OK;
250     }
251
252     if(This->palette != NULL)
253         if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
254             This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
255
256     This->palette = PalImpl;
257
258     if(PalImpl != NULL) {
259         if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
260             (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
261         }
262
263         return IWineD3DSurface_RealizePalette(iface);
264     }
265     else return WINED3D_OK;
266 }
267
268 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
269 {
270     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
271     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
272
273     if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
274         FIXME(" colorkey value not supported (%08x) !\n", Flags);
275         return WINED3DERR_INVALIDCALL;
276     }
277
278     /* Dirtify the surface, but only if a key was changed */
279     if(CKey) {
280         switch (Flags & ~WINEDDCKEY_COLORSPACE) {
281             case WINEDDCKEY_DESTBLT:
282                 This->DestBltCKey = *CKey;
283                 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
284                 break;
285
286             case WINEDDCKEY_DESTOVERLAY:
287                 This->DestOverlayCKey = *CKey;
288                 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
289                 break;
290
291             case WINEDDCKEY_SRCOVERLAY:
292                 This->SrcOverlayCKey = *CKey;
293                 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
294                 break;
295
296             case WINEDDCKEY_SRCBLT:
297                 This->SrcBltCKey = *CKey;
298                 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
299                 break;
300         }
301     }
302     else {
303         switch (Flags & ~WINEDDCKEY_COLORSPACE) {
304             case WINEDDCKEY_DESTBLT:
305                 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
306                 break;
307
308             case WINEDDCKEY_DESTOVERLAY:
309                 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
310                 break;
311
312             case WINEDDCKEY_SRCOVERLAY:
313                 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
314                 break;
315
316             case WINEDDCKEY_SRCBLT:
317                 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
318                 break;
319         }
320     }
321
322     return WINED3D_OK;
323 }
324
325 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
326     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
327     TRACE("(%p)->(%p)\n", This, Pal);
328
329     *Pal = (IWineD3DPalette *) This->palette;
330     return WINED3D_OK;
331 }
332
333 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
334     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
335     WINED3DFORMAT format = This->resource.format_desc->format;
336     DWORD ret;
337     TRACE("(%p)\n", This);
338
339     /* DXTn formats don't have exact pitches as they are to the new row of blocks,
340     where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
341     ie pitch = (width/4) * bytes per block                                  */
342     if (format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
343         ret = ((This->currentDesc.Width + 3) >> 2) << 3;
344     else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
345              format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
346         ret = ((This->currentDesc.Width + 3) >> 2) << 4;
347     else {
348         unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
349         ret = This->resource.format_desc->byte_count * This->currentDesc.Width;  /* Bytes / row */
350         ret = (ret + alignment - 1) & ~(alignment - 1);
351     }
352     TRACE("(%p) Returning %d\n", This, ret);
353     return ret;
354 }
355
356 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
357     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
358     LONG w, h;
359
360     TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
361
362     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
363     {
364         TRACE("(%p): Not an overlay surface\n", This);
365         return WINEDDERR_NOTAOVERLAYSURFACE;
366     }
367
368     w = This->overlay_destrect.right - This->overlay_destrect.left;
369     h = This->overlay_destrect.bottom - This->overlay_destrect.top;
370     This->overlay_destrect.left = X;
371     This->overlay_destrect.top = Y;
372     This->overlay_destrect.right = X + w;
373     This->overlay_destrect.bottom = Y + h;
374
375     IWineD3DSurface_DrawOverlay(iface);
376
377     return WINED3D_OK;
378 }
379
380 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
381     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
382     HRESULT hr;
383
384     TRACE("(%p)->(%p,%p)\n", This, X, Y);
385
386     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
387     {
388         TRACE("(%p): Not an overlay surface\n", This);
389         return WINEDDERR_NOTAOVERLAYSURFACE;
390     }
391     if(This->overlay_dest == NULL) {
392         *X = 0; *Y = 0;
393         hr = WINEDDERR_OVERLAYNOTVISIBLE;
394     } else {
395         *X = This->overlay_destrect.left;
396         *Y = This->overlay_destrect.top;
397         hr = WINED3D_OK;
398     }
399
400     TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
401     return hr;
402 }
403
404 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
405     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
406     IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
407
408     FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
409
410     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
411     {
412         TRACE("(%p): Not an overlay surface\n", This);
413         return WINEDDERR_NOTAOVERLAYSURFACE;
414     }
415
416     return WINED3D_OK;
417 }
418
419 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
420         IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
421 {
422     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
423     IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
424     TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
425
426     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
427     {
428         WARN("(%p): Not an overlay surface\n", This);
429         return WINEDDERR_NOTAOVERLAYSURFACE;
430     } else if(!DstSurface) {
431         WARN("(%p): Dest surface is NULL\n", This);
432         return WINED3DERR_INVALIDCALL;
433     }
434
435     if(SrcRect) {
436         This->overlay_srcrect = *SrcRect;
437     } else {
438         This->overlay_srcrect.left = 0;
439         This->overlay_srcrect.top = 0;
440         This->overlay_srcrect.right = This->currentDesc.Width;
441         This->overlay_srcrect.bottom = This->currentDesc.Height;
442     }
443
444     if(DstRect) {
445         This->overlay_destrect = *DstRect;
446     } else {
447         This->overlay_destrect.left = 0;
448         This->overlay_destrect.top = 0;
449         This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
450         This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
451     }
452
453     if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
454         list_remove(&This->overlay_entry);
455     }
456
457     if(Flags & WINEDDOVER_SHOW) {
458         if(This->overlay_dest != Dst) {
459             This->overlay_dest = Dst;
460             list_add_tail(&Dst->overlays, &This->overlay_entry);
461         }
462     } else if(Flags & WINEDDOVER_HIDE) {
463         /* tests show that the rectangles are erased on hide */
464         This->overlay_srcrect.left   = 0; This->overlay_srcrect.top     = 0;
465         This->overlay_srcrect.right  = 0; This->overlay_srcrect.bottom  = 0;
466         This->overlay_destrect.left  = 0; This->overlay_destrect.top    = 0;
467         This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
468         This->overlay_dest = NULL;
469     }
470
471     IWineD3DSurface_DrawOverlay(iface);
472
473     return WINED3D_OK;
474 }
475
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
477 {
478     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479     TRACE("(%p)->(%p)\n", This, clipper);
480
481     This->clipper = clipper;
482     return WINED3D_OK;
483 }
484
485 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
486 {
487     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
488     TRACE("(%p)->(%p)\n", This, clipper);
489
490     *clipper = This->clipper;
491     if(*clipper) {
492         IWineD3DClipper_AddRef(*clipper);
493     }
494     return WINED3D_OK;
495 }
496
497 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
498     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
499
500     TRACE("This %p, container %p\n", This, container);
501
502     /* We can't keep a reference to the container, since the container already keeps a reference to us. */
503
504     TRACE("Setting container to %p from %p\n", container, This->container);
505     This->container = container;
506
507     return WINED3D_OK;
508 }
509
510 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
511     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
512     const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
513             &This->resource.wineD3DDevice->adapter->gl_info);
514
515     if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
516     {
517         FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
518         return WINED3DERR_INVALIDCALL;
519     }
520
521     TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
522     if (format == WINED3DFMT_UNKNOWN) {
523         This->resource.size = 0;
524     } else if (format == WINED3DFMT_DXT1) {
525         /* DXT1 is half byte per pixel */
526         This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4)) >> 1;
527
528     } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
529                format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
530         This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4));
531     } else {
532         unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
533         This->resource.size = ((This->pow2Width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1);
534         This->resource.size *= This->pow2Height;
535     }
536
537     This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
538
539     This->resource.format_desc = format_desc;
540
541     TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
542
543     return WINED3D_OK;
544 }
545
546 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
547     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
548     const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
549     int extraline = 0;
550     SYSTEM_INFO sysInfo;
551     BITMAPINFO* b_info;
552     HDC ddc;
553     DWORD *masks;
554     UINT usage;
555
556     switch (format_desc->byte_count)
557     {
558         case 2:
559         case 4:
560             /* Allocate extra space to store the RGB bit masks. */
561             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
562             break;
563
564         case 3:
565             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
566             break;
567
568         default:
569             /* Allocate extra space for a palette. */
570             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
571                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
572             break;
573     }
574
575     if (!b_info)
576         return E_OUTOFMEMORY;
577
578         /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
579     * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
580     * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
581     * add an extra line to the dib section
582         */
583     GetSystemInfo(&sysInfo);
584     if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
585         extraline = 1;
586         TRACE("Adding an extra line to the dib section\n");
587     }
588
589     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
590     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
591     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
592     b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
593     b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
594     b_info->bmiHeader.biPlanes = 1;
595     b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
596
597     b_info->bmiHeader.biXPelsPerMeter = 0;
598     b_info->bmiHeader.biYPelsPerMeter = 0;
599     b_info->bmiHeader.biClrUsed = 0;
600     b_info->bmiHeader.biClrImportant = 0;
601
602     /* Get the bit masks */
603     masks = (DWORD *)b_info->bmiColors;
604     switch (This->resource.format_desc->format)
605     {
606         case WINED3DFMT_R8G8B8:
607             usage = DIB_RGB_COLORS;
608             b_info->bmiHeader.biCompression = BI_RGB;
609             break;
610
611         case WINED3DFMT_X1R5G5B5:
612         case WINED3DFMT_A1R5G5B5:
613         case WINED3DFMT_A4R4G4B4:
614         case WINED3DFMT_X4R4G4B4:
615         case WINED3DFMT_R3G3B2:
616         case WINED3DFMT_A8R3G3B2:
617         case WINED3DFMT_R10G10B10A2_UNORM:
618         case WINED3DFMT_R8G8B8A8_UNORM:
619         case WINED3DFMT_X8B8G8R8:
620         case WINED3DFMT_A2R10G10B10:
621         case WINED3DFMT_R5G6B5:
622         case WINED3DFMT_R16G16B16A16_UNORM:
623             usage = 0;
624             b_info->bmiHeader.biCompression = BI_BITFIELDS;
625             masks[0] = format_desc->red_mask;
626             masks[1] = format_desc->green_mask;
627             masks[2] = format_desc->blue_mask;
628             break;
629
630         default:
631             /* Don't know palette */
632             b_info->bmiHeader.biCompression = BI_RGB;
633             usage = 0;
634             break;
635     }
636
637     ddc = GetDC(0);
638     if (ddc == 0) {
639         HeapFree(GetProcessHeap(), 0, b_info);
640         return HRESULT_FROM_WIN32(GetLastError());
641     }
642
643     TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
644     This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
645     ReleaseDC(0, ddc);
646
647     if (!This->dib.DIBsection) {
648         ERR("CreateDIBSection failed!\n");
649         HeapFree(GetProcessHeap(), 0, b_info);
650         return HRESULT_FROM_WIN32(GetLastError());
651     }
652
653     TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
654     /* copy the existing surface to the dib section */
655     if(This->resource.allocatedMemory) {
656         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,  This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
657     } else {
658         /* This is to make LockRect read the gl Texture although memory is allocated */
659         This->Flags &= ~SFLAG_INSYSMEM;
660     }
661     This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
662
663     HeapFree(GetProcessHeap(), 0, b_info);
664
665     /* Now allocate a HDC */
666     This->hDC = CreateCompatibleDC(0);
667     This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
668     TRACE("using wined3d palette %p\n", This->palette);
669     SelectPalette(This->hDC,
670                   This->palette ? This->palette->hpal : 0,
671                   FALSE);
672
673     This->Flags |= SFLAG_DIBSECTION;
674
675     HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
676     This->resource.heapMemory = NULL;
677
678     return WINED3D_OK;
679 }
680
681 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
682                               unsigned int w, unsigned int h)
683 {
684     unsigned int x, y;
685     const float *src_f;
686     unsigned short *dst_s;
687
688     TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
689     for(y = 0; y < h; y++) {
690         src_f = (const float *)(src + y * pitch_in);
691         dst_s = (unsigned short *) (dst + y * pitch_out);
692         for(x = 0; x < w; x++) {
693             dst_s[x] = float_32_to_16(src_f + x);
694         }
695     }
696 }
697
698 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
699         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
700 {
701     static const unsigned char convert_5to8[] =
702     {
703         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
704         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
705         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
706         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
707     };
708     static const unsigned char convert_6to8[] =
709     {
710         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
711         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
712         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
713         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
714         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
715         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
716         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
717         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
718     };
719     unsigned int x, y;
720
721     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
722
723     for (y = 0; y < h; ++y)
724     {
725         const WORD *src_line = (const WORD *)(src + y * pitch_in);
726         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
727         for (x = 0; x < w; ++x)
728         {
729             WORD pixel = src_line[x];
730             dst_line[x] = 0xff000000
731                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
732                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
733                     | convert_5to8[(pixel & 0x001f)];
734         }
735     }
736 }
737
738 struct d3dfmt_convertor_desc {
739     WINED3DFORMAT from, to;
740     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
741 };
742
743 static const struct d3dfmt_convertor_desc convertors[] =
744 {
745     {WINED3DFMT_R32_FLOAT,  WINED3DFMT_R16_FLOAT,   convert_r32_float_r16_float},
746     {WINED3DFMT_R5G6B5,     WINED3DFMT_X8R8G8B8,    convert_r5g6b5_x8r8g8b8},
747 };
748
749 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
750 {
751     unsigned int i;
752     for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
753         if(convertors[i].from == from && convertors[i].to == to) {
754             return &convertors[i];
755         }
756     }
757     return NULL;
758 }
759
760 /*****************************************************************************
761  * surface_convert_format
762  *
763  * Creates a duplicate of a surface in a different format. Is used by Blt to
764  * blit between surfaces with different formats
765  *
766  * Parameters
767  *  source: Source surface
768  *  fmt: Requested destination format
769  *
770  *****************************************************************************/
771 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
772     IWineD3DSurface *ret = NULL;
773     const struct d3dfmt_convertor_desc *conv;
774     WINED3DLOCKED_RECT lock_src, lock_dst;
775     HRESULT hr;
776
777     conv = find_convertor(source->resource.format_desc->format, to_fmt);
778     if(!conv) {
779         FIXME("Cannot find a conversion function from format %s to %s\n",
780               debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
781         return NULL;
782     }
783
784     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice,
785             source->currentDesc.Width, source->currentDesc.Height, to_fmt, TRUE /* lockable */,
786             TRUE /* discard  */, 0 /* level */, &ret, WINED3DRTYPE_SURFACE, 0 /* usage */,
787             WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
788             0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
789     if(!ret) {
790         ERR("Failed to create a destination surface for conversion\n");
791         return NULL;
792     }
793
794     memset(&lock_src, 0, sizeof(lock_src));
795     memset(&lock_dst, 0, sizeof(lock_dst));
796
797     hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
798     if(FAILED(hr)) {
799         ERR("Failed to lock the source surface\n");
800         IWineD3DSurface_Release(ret);
801         return NULL;
802     }
803     hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
804     if(FAILED(hr)) {
805         ERR("Failed to lock the dest surface\n");
806         IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
807         IWineD3DSurface_Release(ret);
808         return NULL;
809     }
810
811     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
812                   source->currentDesc.Width, source->currentDesc.Height);
813
814     IWineD3DSurface_UnlockRect(ret);
815     IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
816
817     return (IWineD3DSurfaceImpl *) ret;
818 }
819
820 /*****************************************************************************
821  * _Blt_ColorFill
822  *
823  * Helper function that fills a memory area with a specific color
824  *
825  * Params:
826  *  buf: memory address to start filling at
827  *  width, height: Dimensions of the area to fill
828  *  bpp: Bit depth of the surface
829  *  lPitch: pitch of the surface
830  *  color: Color to fill with
831  *
832  *****************************************************************************/
833 static HRESULT
834         _Blt_ColorFill(BYTE *buf,
835                        int width, int height,
836                        int bpp, LONG lPitch,
837                        DWORD color)
838 {
839     int x, y;
840     LPBYTE first;
841
842     /* Do first row */
843
844 #define COLORFILL_ROW(type) \
845     { \
846     type *d = (type *) buf; \
847     for (x = 0; x < width; x++) \
848     d[x] = (type) color; \
849     break; \
850 }
851     switch(bpp)
852     {
853         case 1: COLORFILL_ROW(BYTE)
854                 case 2: COLORFILL_ROW(WORD)
855         case 3:
856         {
857             BYTE *d = buf;
858             for (x = 0; x < width; x++,d+=3)
859             {
860                 d[0] = (color    ) & 0xFF;
861                 d[1] = (color>> 8) & 0xFF;
862                 d[2] = (color>>16) & 0xFF;
863             }
864             break;
865         }
866         case 4: COLORFILL_ROW(DWORD)
867         default:
868             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
869             return WINED3DERR_NOTAVAILABLE;
870     }
871
872 #undef COLORFILL_ROW
873
874     /* Now copy first row */
875     first = buf;
876     for (y = 1; y < height; y++)
877     {
878         buf += lPitch;
879         memcpy(buf, first, width * bpp);
880     }
881     return WINED3D_OK;
882 }
883
884 /*****************************************************************************
885  * IWineD3DSurface::Blt, SW emulation version
886  *
887  * Performs blits to a surface, eigher from a source of source-less blts
888  * This is the main functionality of DirectDraw
889  *
890  * Params:
891  *  DestRect: Destination rectangle to write to
892  *  SrcSurface: Source surface, can be NULL
893  *  SrcRect: Source rectangle
894  *****************************************************************************/
895 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
896         const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
897 {
898     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
899     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
900     RECT        xdst,xsrc;
901     HRESULT     ret = WINED3D_OK;
902     WINED3DLOCKED_RECT  dlock, slock;
903     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
904     const struct GlPixelFormatDesc *sEntry, *dEntry;
905     int x, y;
906     const BYTE *sbuf;
907     BYTE *dbuf;
908     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
909
910     if (TRACE_ON(d3d_surface))
911     {
912         if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
913             DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
914         if (SrcRect) TRACE("\tsrcrect  :%dx%d-%dx%d\n",
915             SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
916 #if 0
917         TRACE("\tflags: ");
918                       DDRAW_dump_DDBLT(Flags);
919                       if (Flags & WINEDDBLT_DDFX)
920               {
921                       TRACE("\tblitfx: ");
922                       DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
923     }
924 #endif
925     }
926
927     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
928     {
929         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
930         return WINEDDERR_SURFACEBUSY;
931     }
932
933     if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
934         /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
935         FIXME("Filters not supported in software blit\n");
936     }
937
938     /* First check for the validity of source / destination rectangles. This was
939      * verified using a test application + by MSDN.
940      */
941     if ((Src != NULL) && (SrcRect != NULL) &&
942          ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
943          (SrcRect->top     > Src->currentDesc.Height)||(SrcRect->top    < 0) ||
944          (SrcRect->left    > Src->currentDesc.Width) ||(SrcRect->left   < 0) ||
945          (SrcRect->right   > Src->currentDesc.Width) ||(SrcRect->right  < 0) ||
946          (SrcRect->right   < SrcRect->left)          ||(SrcRect->bottom < SrcRect->top)))
947     {
948         WARN("Application gave us bad source rectangle for Blt.\n");
949         return WINEDDERR_INVALIDRECT;
950     }
951     /* For the Destination rect, it can be out of bounds on the condition that a clipper
952      * is set for the given surface.
953      */
954     if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
955          ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
956          (DestRect->top     > This->currentDesc.Height)||(DestRect->top    < 0) ||
957          (DestRect->left    > This->currentDesc.Width) ||(DestRect->left   < 0) ||
958          (DestRect->right   > This->currentDesc.Width) ||(DestRect->right  < 0) ||
959          (DestRect->right   < DestRect->left)          ||(DestRect->bottom < DestRect->top)))
960     {
961         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
962         return WINEDDERR_INVALIDRECT;
963     }
964
965     /* Now handle negative values in the rectangles. Warning: only supported for now
966     in the 'simple' cases (ie not in any stretching / rotation cases).
967
968     First, the case where nothing is to be done.
969     */
970     if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0)  ||
971           (DestRect->top    >= (int) This->currentDesc.Height) ||
972           (DestRect->left   >= (int) This->currentDesc.Width))) ||
973           ((Src != NULL) && (SrcRect != NULL) &&
974           ((SrcRect->bottom <= 0) || (SrcRect->right <= 0)     ||
975           (SrcRect->top >= (int) Src->currentDesc.Height) ||
976           (SrcRect->left >= (int) Src->currentDesc.Width))  ))
977     {
978         TRACE("Nothing to be done !\n");
979         return  WINED3D_OK;
980     }
981
982     if (DestRect)
983     {
984         xdst = *DestRect;
985     }
986     else
987     {
988         xdst.top    = 0;
989         xdst.bottom = This->currentDesc.Height;
990         xdst.left   = 0;
991         xdst.right  = This->currentDesc.Width;
992     }
993
994     if (SrcRect)
995     {
996         xsrc = *SrcRect;
997     }
998     else
999     {
1000         if (Src)
1001         {
1002             xsrc.top    = 0;
1003             xsrc.bottom = Src->currentDesc.Height;
1004             xsrc.left   = 0;
1005             xsrc.right  = Src->currentDesc.Width;
1006         }
1007         else
1008         {
1009             memset(&xsrc,0,sizeof(xsrc));
1010         }
1011     }
1012
1013     /* The easy case : the source-less blits.... */
1014     if (Src == NULL && DestRect)
1015     {
1016         RECT full_rect;
1017         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1018
1019         full_rect.left   = 0;
1020         full_rect.top    = 0;
1021         full_rect.right  = This->currentDesc.Width;
1022         full_rect.bottom = This->currentDesc.Height;
1023         IntersectRect(&temp_rect, &full_rect, DestRect);
1024         xdst = temp_rect;
1025     }
1026     else if (DestRect)
1027     {
1028         /* Only handle clipping on the destination rectangle */
1029         int clip_horiz = (DestRect->left < 0) || (DestRect->right  > (int) This->currentDesc.Width );
1030         int clip_vert  = (DestRect->top  < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1031         if (clip_vert || clip_horiz)
1032         {
1033             /* Now check if this is a special case or not... */
1034             if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1035                    (((DestRect->right  - DestRect->left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
1036                    (Flags & WINEDDBLT_DDFX))
1037             {
1038                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1039                 return  WINED3D_OK;
1040             }
1041
1042             if (clip_horiz)
1043             {
1044                 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1045                 if (DestRect->right > This->currentDesc.Width)
1046                 {
1047                     xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1048                     xdst.right = (int) This->currentDesc.Width;
1049                 }
1050             }
1051             if (clip_vert)
1052             {
1053                 if (DestRect->top < 0)
1054                 {
1055                     xsrc.top -= DestRect->top;
1056                     xdst.top = 0;
1057                 }
1058                 if (DestRect->bottom > This->currentDesc.Height)
1059                 {
1060                     xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1061                     xdst.bottom = (int) This->currentDesc.Height;
1062                 }
1063             }
1064             /* And check if after clipping something is still to be done... */
1065             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
1066                  (xdst.top   >= (int) This->currentDesc.Height)  ||
1067                  (xdst.left  >= (int) This->currentDesc.Width)   ||
1068                  (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
1069                  (xsrc.top >= (int) Src->currentDesc.Height)     ||
1070                  (xsrc.left >= (int) Src->currentDesc.Width))
1071             {
1072                 TRACE("Nothing to be done after clipping !\n");
1073                 return  WINED3D_OK;
1074             }
1075         }
1076     }
1077
1078     if (Src == This)
1079     {
1080         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1081         slock = dlock;
1082         sEntry = This->resource.format_desc;
1083         dEntry = sEntry;
1084     }
1085     else
1086     {
1087         dEntry = This->resource.format_desc;
1088         if (Src)
1089         {
1090             if (This->resource.format_desc->format != Src->resource.format_desc->format)
1091             {
1092                 Src = surface_convert_format(Src, dEntry->format);
1093                 if(!Src) {
1094                     /* The conv function writes a FIXME */
1095                     WARN("Cannot convert source surface format to dest format\n");
1096                     goto release;
1097                 }
1098             }
1099             IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1100             sEntry = Src->resource.format_desc;
1101         }
1102         else
1103         {
1104             sEntry = dEntry;
1105         }
1106         if (DestRect)
1107             IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1108         else
1109             IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1110     }
1111
1112     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1113
1114     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1115     {
1116         if (!DestRect || Src == This)
1117         {
1118             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1119             goto release;
1120         }
1121     }
1122
1123     bpp = This->resource.format_desc->byte_count;
1124     srcheight = xsrc.bottom - xsrc.top;
1125     srcwidth = xsrc.right - xsrc.left;
1126     dstheight = xdst.bottom - xdst.top;
1127     dstwidth = xdst.right - xdst.left;
1128     width = (xdst.right - xdst.left) * bpp;
1129
1130     assert(width <= dlock.Pitch);
1131
1132     if (DestRect && Src != This)
1133         dbuf = dlock.pBits;
1134     else
1135         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1136
1137     if (Flags & WINEDDBLT_WAIT)
1138     {
1139         Flags &= ~WINEDDBLT_WAIT;
1140     }
1141     if (Flags & WINEDDBLT_ASYNC)
1142     {
1143         static BOOL displayed = FALSE;
1144         if (!displayed)
1145             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1146         displayed = TRUE;
1147         Flags &= ~WINEDDBLT_ASYNC;
1148     }
1149     if (Flags & WINEDDBLT_DONOTWAIT)
1150     {
1151         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1152         static BOOL displayed = FALSE;
1153         if (!displayed)
1154             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1155         displayed = TRUE;
1156         Flags &= ~WINEDDBLT_DONOTWAIT;
1157     }
1158
1159     /* First, all the 'source-less' blits */
1160     if (Flags & WINEDDBLT_COLORFILL)
1161     {
1162         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1163                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1164         Flags &= ~WINEDDBLT_COLORFILL;
1165     }
1166
1167     if (Flags & WINEDDBLT_DEPTHFILL)
1168     {
1169         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1170     }
1171     if (Flags & WINEDDBLT_ROP)
1172     {
1173         /* Catch some degenerate cases here */
1174         switch(DDBltFx->dwROP)
1175         {
1176             case BLACKNESS:
1177                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1178                 break;
1179                 case 0xAA0029: /* No-op */
1180                     break;
1181             case WHITENESS:
1182                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1183                 break;
1184                 case SRCCOPY: /* well, we do that below ? */
1185                     break;
1186             default:
1187                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1188                 goto error;
1189         }
1190         Flags &= ~WINEDDBLT_ROP;
1191     }
1192     if (Flags & WINEDDBLT_DDROPS)
1193     {
1194         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1195     }
1196     /* Now the 'with source' blits */
1197     if (Src)
1198     {
1199         const BYTE *sbase;
1200         int sx, xinc, sy, yinc;
1201
1202         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1203             goto release;
1204         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1205         xinc = (srcwidth << 16) / dstwidth;
1206         yinc = (srcheight << 16) / dstheight;
1207
1208         if (!Flags)
1209         {
1210             /* No effects, we can cheat here */
1211             if (dstwidth == srcwidth)
1212             {
1213                 if (dstheight == srcheight)
1214                 {
1215                     /* No stretching in either direction. This needs to be as
1216                     * fast as possible */
1217                     sbuf = sbase;
1218
1219                     /* check for overlapping surfaces */
1220                     if (Src != This || xdst.top < xsrc.top ||
1221                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1222                     {
1223                         /* no overlap, or dst above src, so copy from top downwards */
1224                         for (y = 0; y < dstheight; y++)
1225                         {
1226                             memcpy(dbuf, sbuf, width);
1227                             sbuf += slock.Pitch;
1228                             dbuf += dlock.Pitch;
1229                         }
1230                     }
1231                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1232                     {
1233                         sbuf += (slock.Pitch*dstheight);
1234                         dbuf += (dlock.Pitch*dstheight);
1235                         for (y = 0; y < dstheight; y++)
1236                         {
1237                             sbuf -= slock.Pitch;
1238                             dbuf -= dlock.Pitch;
1239                             memcpy(dbuf, sbuf, width);
1240                         }
1241                     }
1242                     else /* src and dst overlapping on the same line, use memmove */
1243                     {
1244                         for (y = 0; y < dstheight; y++)
1245                         {
1246                             memmove(dbuf, sbuf, width);
1247                             sbuf += slock.Pitch;
1248                             dbuf += dlock.Pitch;
1249                         }
1250                     }
1251                 } else {
1252                     /* Stretching in Y direction only */
1253                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1254                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1255                         memcpy(dbuf, sbuf, width);
1256                         dbuf += dlock.Pitch;
1257                     }
1258                 }
1259             }
1260             else
1261             {
1262                 /* Stretching in X direction */
1263                 int last_sy = -1;
1264                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1265                 {
1266                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1267
1268                     if ((sy >> 16) == (last_sy >> 16))
1269                     {
1270                         /* this sourcerow is the same as last sourcerow -
1271                         * copy already stretched row
1272                         */
1273                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1274                     }
1275                     else
1276                     {
1277 #define STRETCH_ROW(type) { \
1278                         const type *s = (const type *)sbuf; \
1279                         type *d = (type *)dbuf; \
1280                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1281                         d[x] = s[sx >> 16]; \
1282                         break; }
1283
1284                         switch(bpp)
1285                         {
1286                             case 1: STRETCH_ROW(BYTE)
1287                                     case 2: STRETCH_ROW(WORD)
1288                                             case 4: STRETCH_ROW(DWORD)
1289                             case 3:
1290                             {
1291                                 const BYTE *s;
1292                                 BYTE *d = dbuf;
1293                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1294                                 {
1295                                     DWORD pixel;
1296
1297                                     s = sbuf+3*(sx>>16);
1298                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1299                                     d[0] = (pixel    )&0xff;
1300                                     d[1] = (pixel>> 8)&0xff;
1301                                     d[2] = (pixel>>16)&0xff;
1302                                     d+=3;
1303                                 }
1304                                 break;
1305                             }
1306                             default:
1307                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1308                                 ret = WINED3DERR_NOTAVAILABLE;
1309                                 goto error;
1310                         }
1311 #undef STRETCH_ROW
1312                     }
1313                     dbuf += dlock.Pitch;
1314                     last_sy = sy;
1315                 }
1316             }
1317         }
1318         else
1319         {
1320             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1321             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1322             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1323             if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1324             {
1325                 /* The color keying flags are checked for correctness in ddraw */
1326                 if (Flags & WINEDDBLT_KEYSRC)
1327                 {
1328                     keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1329                     keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1330                 }
1331                 else  if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1332                 {
1333                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1334                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1335                 }
1336
1337                 if (Flags & WINEDDBLT_KEYDEST)
1338                 {
1339                     /* Destination color keys are taken from the source surface ! */
1340                     destkeylow  = Src->DestBltCKey.dwColorSpaceLowValue;
1341                     destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1342                 }
1343                 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1344                 {
1345                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1346                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1347                 }
1348
1349                 if(bpp == 1)
1350                 {
1351                     keymask = 0xff;
1352                 }
1353                 else
1354                 {
1355                     keymask = sEntry->red_mask
1356                             | sEntry->green_mask
1357                             | sEntry->blue_mask;
1358                 }
1359                 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1360             }
1361
1362             if (Flags & WINEDDBLT_DDFX)
1363             {
1364                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1365                 LONG tmpxy;
1366                 dTopLeft     = dbuf;
1367                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1368                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1369                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1370
1371                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1372                 {
1373                     /* I don't think we need to do anything about this flag */
1374                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1375                 }
1376                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1377                 {
1378                     tmp          = dTopRight;
1379                     dTopRight    = dTopLeft;
1380                     dTopLeft     = tmp;
1381                     tmp          = dBottomRight;
1382                     dBottomRight = dBottomLeft;
1383                     dBottomLeft  = tmp;
1384                     dstxinc = dstxinc *-1;
1385                 }
1386                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1387                 {
1388                     tmp          = dTopLeft;
1389                     dTopLeft     = dBottomLeft;
1390                     dBottomLeft  = tmp;
1391                     tmp          = dTopRight;
1392                     dTopRight    = dBottomRight;
1393                     dBottomRight = tmp;
1394                     dstyinc = dstyinc *-1;
1395                 }
1396                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1397                 {
1398                     /* I don't think we need to do anything about this flag */
1399                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1400                 }
1401                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1402                 {
1403                     tmp          = dBottomRight;
1404                     dBottomRight = dTopLeft;
1405                     dTopLeft     = tmp;
1406                     tmp          = dBottomLeft;
1407                     dBottomLeft  = dTopRight;
1408                     dTopRight    = tmp;
1409                     dstxinc = dstxinc * -1;
1410                     dstyinc = dstyinc * -1;
1411                 }
1412                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1413                 {
1414                     tmp          = dTopLeft;
1415                     dTopLeft     = dBottomLeft;
1416                     dBottomLeft  = dBottomRight;
1417                     dBottomRight = dTopRight;
1418                     dTopRight    = tmp;
1419                     tmpxy   = dstxinc;
1420                     dstxinc = dstyinc;
1421                     dstyinc = tmpxy;
1422                     dstxinc = dstxinc * -1;
1423                 }
1424                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1425                 {
1426                     tmp          = dTopLeft;
1427                     dTopLeft     = dTopRight;
1428                     dTopRight    = dBottomRight;
1429                     dBottomRight = dBottomLeft;
1430                     dBottomLeft  = tmp;
1431                     tmpxy   = dstxinc;
1432                     dstxinc = dstyinc;
1433                     dstyinc = tmpxy;
1434                     dstyinc = dstyinc * -1;
1435                 }
1436                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1437                 {
1438                     /* I don't think we need to do anything about this flag */
1439                     WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1440                 }
1441                 dbuf = dTopLeft;
1442                 Flags &= ~(WINEDDBLT_DDFX);
1443             }
1444
1445 #define COPY_COLORKEY_FX(type) { \
1446             const type *s; \
1447             type *d = (type *)dbuf, *dx, tmp; \
1448             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1449             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1450             dx = d; \
1451             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1452             tmp = s[sx >> 16]; \
1453             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1454             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1455             dx[0] = tmp; \
1456         } \
1457             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1458         } \
1459             d = (type*)(((LPBYTE)d)+dstyinc); \
1460         } \
1461             break; }
1462
1463             switch (bpp) {
1464                 case 1: COPY_COLORKEY_FX(BYTE)
1465                         case 2: COPY_COLORKEY_FX(WORD)
1466                                 case 4: COPY_COLORKEY_FX(DWORD)
1467                 case 3:
1468                 {
1469                     const BYTE *s;
1470                     BYTE *d = dbuf, *dx;
1471                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1472                     {
1473                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1474                         dx = d;
1475                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1476                         {
1477                             DWORD pixel, dpixel = 0;
1478                             s = sbuf+3*(sx>>16);
1479                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1480                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1481                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1482                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1483                             {
1484                                 dx[0] = (pixel    )&0xff;
1485                                 dx[1] = (pixel>> 8)&0xff;
1486                                 dx[2] = (pixel>>16)&0xff;
1487                             }
1488                             dx+= dstxinc;
1489                         }
1490                         d += dstyinc;
1491                     }
1492                     break;
1493                 }
1494                 default:
1495                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1496                           (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1497                     ret = WINED3DERR_NOTAVAILABLE;
1498                     goto error;
1499 #undef COPY_COLORKEY_FX
1500             }
1501         }
1502     }
1503
1504 error:
1505     if (Flags && FIXME_ON(d3d_surface))
1506     {
1507         FIXME("\tUnsupported flags: %08x\n", Flags);
1508     }
1509
1510 release:
1511     IWineD3DSurface_UnlockRect(iface);
1512     if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1513     /* Release the converted surface if any */
1514     if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1515     return ret;
1516 }
1517
1518 /*****************************************************************************
1519  * IWineD3DSurface::BltFast, SW emulation version
1520  *
1521  * This is the software implementation of BltFast, as used by GDI surfaces
1522  * and as a fallback for OpenGL surfaces. This code is taken from the old
1523  * DirectDraw code, and was originally written by TransGaming.
1524  *
1525  * Params:
1526  *  dstx:
1527  *  dsty:
1528  *  Source: Source surface to copy from
1529  *  rsrc: Source rectangle
1530  *  trans: Some Flags
1531  *
1532  * Returns:
1533  *  WINED3D_OK on success
1534  *
1535  *****************************************************************************/
1536 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1537         IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1538 {
1539     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1540     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1541
1542     int                 bpp, w, h, x, y;
1543     WINED3DLOCKED_RECT  dlock,slock;
1544     HRESULT             ret = WINED3D_OK;
1545     RECT                rsrc2;
1546     RECT                lock_src, lock_dst, lock_union;
1547     const BYTE          *sbuf;
1548     BYTE                *dbuf;
1549     const struct GlPixelFormatDesc *sEntry, *dEntry;
1550
1551     if (TRACE_ON(d3d_surface))
1552     {
1553         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1554
1555         if (rsrc)
1556         {
1557             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1558                   rsrc->right,rsrc->bottom);
1559         }
1560         else
1561         {
1562             TRACE(" srcrect: NULL\n");
1563         }
1564     }
1565
1566     if ((This->Flags & SFLAG_LOCKED) ||
1567             (Src->Flags & SFLAG_LOCKED))
1568     {
1569         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1570         return WINEDDERR_SURFACEBUSY;
1571     }
1572
1573     if (!rsrc)
1574     {
1575         WARN("rsrc is NULL!\n");
1576         rsrc2.left = 0;
1577         rsrc2.top = 0;
1578         rsrc2.right = Src->currentDesc.Width;
1579         rsrc2.bottom = Src->currentDesc.Height;
1580         rsrc = &rsrc2;
1581     }
1582
1583     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1584     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1585          (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1586          (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1587          (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1588          (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1589     {
1590         WARN("Application gave us bad source rectangle for BltFast.\n");
1591         return WINEDDERR_INVALIDRECT;
1592     }
1593
1594     h = rsrc->bottom - rsrc->top;
1595     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1596     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1597     if (h <= 0) return WINEDDERR_INVALIDRECT;
1598
1599     w = rsrc->right - rsrc->left;
1600     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1601     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1602     if (w <= 0) return WINEDDERR_INVALIDRECT;
1603
1604     /* Now compute the locking rectangle... */
1605     lock_src.left = rsrc->left;
1606     lock_src.top = rsrc->top;
1607     lock_src.right = lock_src.left + w;
1608     lock_src.bottom = lock_src.top + h;
1609
1610     lock_dst.left = dstx;
1611     lock_dst.top = dsty;
1612     lock_dst.right = dstx + w;
1613     lock_dst.bottom = dsty + h;
1614
1615     bpp = This->resource.format_desc->byte_count;
1616
1617     /* We need to lock the surfaces, or we won't get refreshes when done. */
1618     if (Src == This)
1619     {
1620         int pitch;
1621
1622         UnionRect(&lock_union, &lock_src, &lock_dst);
1623
1624         /* Lock the union of the two rectangles */
1625         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1626         if(ret != WINED3D_OK) goto error;
1627
1628         pitch = dlock.Pitch;
1629         slock.Pitch = dlock.Pitch;
1630
1631         /* Since slock was originally copied from this surface's description, we can just reuse it */
1632         assert(This->resource.allocatedMemory != NULL);
1633         sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1634         dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1635         sEntry = Src->resource.format_desc;
1636         dEntry = sEntry;
1637     }
1638     else
1639     {
1640         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1641         if(ret != WINED3D_OK) goto error;
1642         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1643         if(ret != WINED3D_OK) goto error;
1644
1645         sbuf = slock.pBits;
1646         dbuf = dlock.pBits;
1647         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1648
1649         sEntry = Src->resource.format_desc;
1650         dEntry = This->resource.format_desc;
1651     }
1652
1653     /* Handle compressed surfaces first... */
1654     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1655     {
1656         UINT row_block_count;
1657
1658         TRACE("compressed -> compressed copy\n");
1659         if (trans)
1660             FIXME("trans arg not supported when a compressed surface is involved\n");
1661         if (dstx || dsty)
1662             FIXME("offset for destination surface is not supported\n");
1663         if (Src->resource.format_desc->format != This->resource.format_desc->format)
1664         {
1665             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1666             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1667             goto error;
1668         }
1669
1670         row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1671         for (y = 0; y < h; y += dEntry->block_height)
1672         {
1673             memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1674             dbuf += dlock.Pitch;
1675             sbuf += slock.Pitch;
1676         }
1677
1678         goto error;
1679     }
1680     if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1681     {
1682         /* TODO: Use the libtxc_dxtn.so shared library to do
1683          * software decompression
1684          */
1685         ERR("Software decompression not supported.\n");
1686         goto error;
1687     }
1688
1689     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1690     {
1691         DWORD keylow, keyhigh;
1692         TRACE("Color keyed copy\n");
1693         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1694         {
1695             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1696             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1697         }
1698         else
1699         {
1700             /* I'm not sure if this is correct */
1701             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1702             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1703             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1704         }
1705
1706 #define COPYBOX_COLORKEY(type) { \
1707         const type *s = (const type *)sbuf; \
1708         type *d = (type *)dbuf; \
1709         type tmp; \
1710         for (y = 0; y < h; y++) { \
1711         for (x = 0; x < w; x++) { \
1712         tmp = s[x]; \
1713         if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1714     } \
1715         s = (const type *)((const BYTE *)s + slock.Pitch); \
1716         d = (type *)((BYTE *)d + dlock.Pitch); \
1717     } \
1718         break; \
1719     }
1720
1721         switch (bpp) {
1722             case 1: COPYBOX_COLORKEY(BYTE)
1723                     case 2: COPYBOX_COLORKEY(WORD)
1724                             case 4: COPYBOX_COLORKEY(DWORD)
1725             case 3:
1726             {
1727                 const BYTE *s;
1728                 BYTE *d;
1729                 DWORD tmp;
1730                 s = sbuf;
1731                 d = dbuf;
1732                 for (y = 0; y < h; y++)
1733                 {
1734                     for (x = 0; x < w * 3; x += 3)
1735                     {
1736                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1737                         if (tmp < keylow || tmp > keyhigh)
1738                         {
1739                             d[x + 0] = s[x + 0];
1740                             d[x + 1] = s[x + 1];
1741                             d[x + 2] = s[x + 2];
1742                         }
1743                     }
1744                     s += slock.Pitch;
1745                     d += dlock.Pitch;
1746                 }
1747                 break;
1748             }
1749             default:
1750                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1751                 ret = WINED3DERR_NOTAVAILABLE;
1752                 goto error;
1753         }
1754 #undef COPYBOX_COLORKEY
1755         TRACE("Copy Done\n");
1756     }
1757     else
1758     {
1759         int width = w * bpp;
1760         INT sbufpitch, dbufpitch;
1761
1762         TRACE("NO color key copy\n");
1763         /* Handle overlapping surfaces */
1764         if (sbuf < dbuf)
1765         {
1766             sbuf += (h - 1) * slock.Pitch;
1767             dbuf += (h - 1) * dlock.Pitch;
1768             sbufpitch = -slock.Pitch;
1769             dbufpitch = -dlock.Pitch;
1770         }
1771         else
1772         {
1773             sbufpitch = slock.Pitch;
1774             dbufpitch = dlock.Pitch;
1775         }
1776         for (y = 0; y < h; y++)
1777         {
1778             /* This is pretty easy, a line for line memcpy */
1779             memmove(dbuf, sbuf, width);
1780             sbuf += sbufpitch;
1781             dbuf += dbufpitch;
1782         }
1783         TRACE("Copy done\n");
1784     }
1785
1786 error:
1787     if (Src == This)
1788     {
1789         IWineD3DSurface_UnlockRect(iface);
1790     }
1791     else
1792     {
1793         IWineD3DSurface_UnlockRect(iface);
1794         IWineD3DSurface_UnlockRect(Source);
1795     }
1796
1797     return ret;
1798 }
1799
1800 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1801 {
1802     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1803
1804     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1805           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1806
1807     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1808
1809     if (NULL == pRect)
1810     {
1811         pLockedRect->pBits = This->resource.allocatedMemory;
1812         This->lockedRect.left   = 0;
1813         This->lockedRect.top    = 0;
1814         This->lockedRect.right  = This->currentDesc.Width;
1815         This->lockedRect.bottom = This->currentDesc.Height;
1816
1817         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1818               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1819               This->lockedRect.right, This->lockedRect.bottom);
1820     }
1821     else
1822     {
1823         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1824               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1825
1826         /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1827          * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1828          * slightly different meaning compared to regular textures. For DXTn
1829          * textures Pitch is the size of a row of blocks, 4 high and "width"
1830          * long. The x offset is calculated differently as well, since moving 4
1831          * pixels to the right actually moves an entire 4x4 block to right, ie
1832          * 16 bytes (8 in case of DXT1). */
1833         if (This->resource.format_desc->format == WINED3DFMT_DXT1)
1834         {
1835             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1836         }
1837         else if (This->resource.format_desc->format == WINED3DFMT_DXT2
1838                 || This->resource.format_desc->format == WINED3DFMT_DXT3
1839                 || This->resource.format_desc->format == WINED3DFMT_DXT4
1840                 || This->resource.format_desc->format == WINED3DFMT_DXT5)
1841         {
1842             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1843         }
1844         else
1845         {
1846             pLockedRect->pBits = This->resource.allocatedMemory +
1847                     (pLockedRect->Pitch * pRect->top) +
1848                     (pRect->left * This->resource.format_desc->byte_count);
1849         }
1850         This->lockedRect.left   = pRect->left;
1851         This->lockedRect.top    = pRect->top;
1852         This->lockedRect.right  = pRect->right;
1853         This->lockedRect.bottom = pRect->bottom;
1854     }
1855
1856     /* No dirtifying is needed for this surface implementation */
1857     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1858
1859     return WINED3D_OK;
1860 }
1861
1862 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1863     ERR("Should not be called on base texture\n");
1864     return;
1865 }
1866
1867 /* TODO: think about moving this down to resource? */
1868 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1869 {
1870     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1871
1872     /* This should only be called for sysmem textures, it may be a good idea
1873      * to extend this to all pools at some point in the future  */
1874     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1875     {
1876         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1877     }
1878     return This->resource.allocatedMemory;
1879 }