wined3d: Use the format info to calculate compressed surface size in IWineD3DBaseSurf...
[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     }
525     else if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
526     {
527         UINT row_block_count = (This->pow2Width + format_desc->block_width - 1) / format_desc->block_width;
528         UINT row_count = (This->pow2Height + format_desc->block_height - 1) / format_desc->block_height;
529         This->resource.size = row_count * row_block_count * format_desc->block_byte_count;
530     }
531     else
532     {
533         unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
534         This->resource.size = ((This->pow2Width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1);
535         This->resource.size *= This->pow2Height;
536     }
537
538     This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
539
540     This->resource.format_desc = format_desc;
541
542     TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
543
544     return WINED3D_OK;
545 }
546
547 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
548     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
549     const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
550     int extraline = 0;
551     SYSTEM_INFO sysInfo;
552     BITMAPINFO* b_info;
553     HDC ddc;
554     DWORD *masks;
555     UINT usage;
556
557     switch (format_desc->byte_count)
558     {
559         case 2:
560         case 4:
561             /* Allocate extra space to store the RGB bit masks. */
562             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
563             break;
564
565         case 3:
566             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
567             break;
568
569         default:
570             /* Allocate extra space for a palette. */
571             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
572                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
573             break;
574     }
575
576     if (!b_info)
577         return E_OUTOFMEMORY;
578
579         /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
580     * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
581     * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
582     * add an extra line to the dib section
583         */
584     GetSystemInfo(&sysInfo);
585     if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
586         extraline = 1;
587         TRACE("Adding an extra line to the dib section\n");
588     }
589
590     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
591     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
592     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
593     b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
594     b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
595     b_info->bmiHeader.biPlanes = 1;
596     b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
597
598     b_info->bmiHeader.biXPelsPerMeter = 0;
599     b_info->bmiHeader.biYPelsPerMeter = 0;
600     b_info->bmiHeader.biClrUsed = 0;
601     b_info->bmiHeader.biClrImportant = 0;
602
603     /* Get the bit masks */
604     masks = (DWORD *)b_info->bmiColors;
605     switch (This->resource.format_desc->format)
606     {
607         case WINED3DFMT_R8G8B8:
608             usage = DIB_RGB_COLORS;
609             b_info->bmiHeader.biCompression = BI_RGB;
610             break;
611
612         case WINED3DFMT_X1R5G5B5:
613         case WINED3DFMT_A1R5G5B5:
614         case WINED3DFMT_A4R4G4B4:
615         case WINED3DFMT_X4R4G4B4:
616         case WINED3DFMT_R3G3B2:
617         case WINED3DFMT_A8R3G3B2:
618         case WINED3DFMT_R10G10B10A2_UNORM:
619         case WINED3DFMT_R8G8B8A8_UNORM:
620         case WINED3DFMT_X8B8G8R8:
621         case WINED3DFMT_A2R10G10B10:
622         case WINED3DFMT_R5G6B5:
623         case WINED3DFMT_R16G16B16A16_UNORM:
624             usage = 0;
625             b_info->bmiHeader.biCompression = BI_BITFIELDS;
626             masks[0] = format_desc->red_mask;
627             masks[1] = format_desc->green_mask;
628             masks[2] = format_desc->blue_mask;
629             break;
630
631         default:
632             /* Don't know palette */
633             b_info->bmiHeader.biCompression = BI_RGB;
634             usage = 0;
635             break;
636     }
637
638     ddc = GetDC(0);
639     if (ddc == 0) {
640         HeapFree(GetProcessHeap(), 0, b_info);
641         return HRESULT_FROM_WIN32(GetLastError());
642     }
643
644     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);
645     This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
646     ReleaseDC(0, ddc);
647
648     if (!This->dib.DIBsection) {
649         ERR("CreateDIBSection failed!\n");
650         HeapFree(GetProcessHeap(), 0, b_info);
651         return HRESULT_FROM_WIN32(GetLastError());
652     }
653
654     TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
655     /* copy the existing surface to the dib section */
656     if(This->resource.allocatedMemory) {
657         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,  This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
658     } else {
659         /* This is to make LockRect read the gl Texture although memory is allocated */
660         This->Flags &= ~SFLAG_INSYSMEM;
661     }
662     This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
663
664     HeapFree(GetProcessHeap(), 0, b_info);
665
666     /* Now allocate a HDC */
667     This->hDC = CreateCompatibleDC(0);
668     This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
669     TRACE("using wined3d palette %p\n", This->palette);
670     SelectPalette(This->hDC,
671                   This->palette ? This->palette->hpal : 0,
672                   FALSE);
673
674     This->Flags |= SFLAG_DIBSECTION;
675
676     HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
677     This->resource.heapMemory = NULL;
678
679     return WINED3D_OK;
680 }
681
682 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
683                               unsigned int w, unsigned int h)
684 {
685     unsigned int x, y;
686     const float *src_f;
687     unsigned short *dst_s;
688
689     TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
690     for(y = 0; y < h; y++) {
691         src_f = (const float *)(src + y * pitch_in);
692         dst_s = (unsigned short *) (dst + y * pitch_out);
693         for(x = 0; x < w; x++) {
694             dst_s[x] = float_32_to_16(src_f + x);
695         }
696     }
697 }
698
699 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
700         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
701 {
702     static const unsigned char convert_5to8[] =
703     {
704         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
705         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
706         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
707         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
708     };
709     static const unsigned char convert_6to8[] =
710     {
711         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
712         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
713         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
714         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
715         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
716         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
717         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
718         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
719     };
720     unsigned int x, y;
721
722     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
723
724     for (y = 0; y < h; ++y)
725     {
726         const WORD *src_line = (const WORD *)(src + y * pitch_in);
727         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
728         for (x = 0; x < w; ++x)
729         {
730             WORD pixel = src_line[x];
731             dst_line[x] = 0xff000000
732                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
733                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
734                     | convert_5to8[(pixel & 0x001f)];
735         }
736     }
737 }
738
739 struct d3dfmt_convertor_desc {
740     WINED3DFORMAT from, to;
741     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
742 };
743
744 static const struct d3dfmt_convertor_desc convertors[] =
745 {
746     {WINED3DFMT_R32_FLOAT,  WINED3DFMT_R16_FLOAT,   convert_r32_float_r16_float},
747     {WINED3DFMT_R5G6B5,     WINED3DFMT_X8R8G8B8,    convert_r5g6b5_x8r8g8b8},
748 };
749
750 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
751 {
752     unsigned int i;
753     for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
754         if(convertors[i].from == from && convertors[i].to == to) {
755             return &convertors[i];
756         }
757     }
758     return NULL;
759 }
760
761 /*****************************************************************************
762  * surface_convert_format
763  *
764  * Creates a duplicate of a surface in a different format. Is used by Blt to
765  * blit between surfaces with different formats
766  *
767  * Parameters
768  *  source: Source surface
769  *  fmt: Requested destination format
770  *
771  *****************************************************************************/
772 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
773     IWineD3DSurface *ret = NULL;
774     const struct d3dfmt_convertor_desc *conv;
775     WINED3DLOCKED_RECT lock_src, lock_dst;
776     HRESULT hr;
777
778     conv = find_convertor(source->resource.format_desc->format, to_fmt);
779     if(!conv) {
780         FIXME("Cannot find a conversion function from format %s to %s\n",
781               debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
782         return NULL;
783     }
784
785     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice,
786             source->currentDesc.Width, source->currentDesc.Height, to_fmt, TRUE /* lockable */,
787             TRUE /* discard  */, 0 /* level */, &ret, WINED3DRTYPE_SURFACE, 0 /* usage */,
788             WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
789             0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
790     if(!ret) {
791         ERR("Failed to create a destination surface for conversion\n");
792         return NULL;
793     }
794
795     memset(&lock_src, 0, sizeof(lock_src));
796     memset(&lock_dst, 0, sizeof(lock_dst));
797
798     hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
799     if(FAILED(hr)) {
800         ERR("Failed to lock the source surface\n");
801         IWineD3DSurface_Release(ret);
802         return NULL;
803     }
804     hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
805     if(FAILED(hr)) {
806         ERR("Failed to lock the dest surface\n");
807         IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
808         IWineD3DSurface_Release(ret);
809         return NULL;
810     }
811
812     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
813                   source->currentDesc.Width, source->currentDesc.Height);
814
815     IWineD3DSurface_UnlockRect(ret);
816     IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
817
818     return (IWineD3DSurfaceImpl *) ret;
819 }
820
821 /*****************************************************************************
822  * _Blt_ColorFill
823  *
824  * Helper function that fills a memory area with a specific color
825  *
826  * Params:
827  *  buf: memory address to start filling at
828  *  width, height: Dimensions of the area to fill
829  *  bpp: Bit depth of the surface
830  *  lPitch: pitch of the surface
831  *  color: Color to fill with
832  *
833  *****************************************************************************/
834 static HRESULT
835         _Blt_ColorFill(BYTE *buf,
836                        int width, int height,
837                        int bpp, LONG lPitch,
838                        DWORD color)
839 {
840     int x, y;
841     LPBYTE first;
842
843     /* Do first row */
844
845 #define COLORFILL_ROW(type) \
846     { \
847     type *d = (type *) buf; \
848     for (x = 0; x < width; x++) \
849     d[x] = (type) color; \
850     break; \
851 }
852     switch(bpp)
853     {
854         case 1: COLORFILL_ROW(BYTE)
855                 case 2: COLORFILL_ROW(WORD)
856         case 3:
857         {
858             BYTE *d = buf;
859             for (x = 0; x < width; x++,d+=3)
860             {
861                 d[0] = (color    ) & 0xFF;
862                 d[1] = (color>> 8) & 0xFF;
863                 d[2] = (color>>16) & 0xFF;
864             }
865             break;
866         }
867         case 4: COLORFILL_ROW(DWORD)
868         default:
869             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
870             return WINED3DERR_NOTAVAILABLE;
871     }
872
873 #undef COLORFILL_ROW
874
875     /* Now copy first row */
876     first = buf;
877     for (y = 1; y < height; y++)
878     {
879         buf += lPitch;
880         memcpy(buf, first, width * bpp);
881     }
882     return WINED3D_OK;
883 }
884
885 /*****************************************************************************
886  * IWineD3DSurface::Blt, SW emulation version
887  *
888  * Performs blits to a surface, eigher from a source of source-less blts
889  * This is the main functionality of DirectDraw
890  *
891  * Params:
892  *  DestRect: Destination rectangle to write to
893  *  SrcSurface: Source surface, can be NULL
894  *  SrcRect: Source rectangle
895  *****************************************************************************/
896 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
897         const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
898 {
899     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
900     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
901     RECT        xdst,xsrc;
902     HRESULT     ret = WINED3D_OK;
903     WINED3DLOCKED_RECT  dlock, slock;
904     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
905     const struct GlPixelFormatDesc *sEntry, *dEntry;
906     int x, y;
907     const BYTE *sbuf;
908     BYTE *dbuf;
909     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
910
911     if (TRACE_ON(d3d_surface))
912     {
913         if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
914             DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
915         if (SrcRect) TRACE("\tsrcrect  :%dx%d-%dx%d\n",
916             SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
917 #if 0
918         TRACE("\tflags: ");
919                       DDRAW_dump_DDBLT(Flags);
920                       if (Flags & WINEDDBLT_DDFX)
921               {
922                       TRACE("\tblitfx: ");
923                       DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
924     }
925 #endif
926     }
927
928     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
929     {
930         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
931         return WINEDDERR_SURFACEBUSY;
932     }
933
934     if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
935         /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
936         FIXME("Filters not supported in software blit\n");
937     }
938
939     /* First check for the validity of source / destination rectangles. This was
940      * verified using a test application + by MSDN.
941      */
942     if ((Src != NULL) && (SrcRect != NULL) &&
943          ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
944          (SrcRect->top     > Src->currentDesc.Height)||(SrcRect->top    < 0) ||
945          (SrcRect->left    > Src->currentDesc.Width) ||(SrcRect->left   < 0) ||
946          (SrcRect->right   > Src->currentDesc.Width) ||(SrcRect->right  < 0) ||
947          (SrcRect->right   < SrcRect->left)          ||(SrcRect->bottom < SrcRect->top)))
948     {
949         WARN("Application gave us bad source rectangle for Blt.\n");
950         return WINEDDERR_INVALIDRECT;
951     }
952     /* For the Destination rect, it can be out of bounds on the condition that a clipper
953      * is set for the given surface.
954      */
955     if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
956          ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
957          (DestRect->top     > This->currentDesc.Height)||(DestRect->top    < 0) ||
958          (DestRect->left    > This->currentDesc.Width) ||(DestRect->left   < 0) ||
959          (DestRect->right   > This->currentDesc.Width) ||(DestRect->right  < 0) ||
960          (DestRect->right   < DestRect->left)          ||(DestRect->bottom < DestRect->top)))
961     {
962         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
963         return WINEDDERR_INVALIDRECT;
964     }
965
966     /* Now handle negative values in the rectangles. Warning: only supported for now
967     in the 'simple' cases (ie not in any stretching / rotation cases).
968
969     First, the case where nothing is to be done.
970     */
971     if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0)  ||
972           (DestRect->top    >= (int) This->currentDesc.Height) ||
973           (DestRect->left   >= (int) This->currentDesc.Width))) ||
974           ((Src != NULL) && (SrcRect != NULL) &&
975           ((SrcRect->bottom <= 0) || (SrcRect->right <= 0)     ||
976           (SrcRect->top >= (int) Src->currentDesc.Height) ||
977           (SrcRect->left >= (int) Src->currentDesc.Width))  ))
978     {
979         TRACE("Nothing to be done !\n");
980         return  WINED3D_OK;
981     }
982
983     if (DestRect)
984     {
985         xdst = *DestRect;
986     }
987     else
988     {
989         xdst.top    = 0;
990         xdst.bottom = This->currentDesc.Height;
991         xdst.left   = 0;
992         xdst.right  = This->currentDesc.Width;
993     }
994
995     if (SrcRect)
996     {
997         xsrc = *SrcRect;
998     }
999     else
1000     {
1001         if (Src)
1002         {
1003             xsrc.top    = 0;
1004             xsrc.bottom = Src->currentDesc.Height;
1005             xsrc.left   = 0;
1006             xsrc.right  = Src->currentDesc.Width;
1007         }
1008         else
1009         {
1010             memset(&xsrc,0,sizeof(xsrc));
1011         }
1012     }
1013
1014     /* The easy case : the source-less blits.... */
1015     if (Src == NULL && DestRect)
1016     {
1017         RECT full_rect;
1018         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1019
1020         full_rect.left   = 0;
1021         full_rect.top    = 0;
1022         full_rect.right  = This->currentDesc.Width;
1023         full_rect.bottom = This->currentDesc.Height;
1024         IntersectRect(&temp_rect, &full_rect, DestRect);
1025         xdst = temp_rect;
1026     }
1027     else if (DestRect)
1028     {
1029         /* Only handle clipping on the destination rectangle */
1030         int clip_horiz = (DestRect->left < 0) || (DestRect->right  > (int) This->currentDesc.Width );
1031         int clip_vert  = (DestRect->top  < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1032         if (clip_vert || clip_horiz)
1033         {
1034             /* Now check if this is a special case or not... */
1035             if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1036                    (((DestRect->right  - DestRect->left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
1037                    (Flags & WINEDDBLT_DDFX))
1038             {
1039                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1040                 return  WINED3D_OK;
1041             }
1042
1043             if (clip_horiz)
1044             {
1045                 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1046                 if (DestRect->right > This->currentDesc.Width)
1047                 {
1048                     xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1049                     xdst.right = (int) This->currentDesc.Width;
1050                 }
1051             }
1052             if (clip_vert)
1053             {
1054                 if (DestRect->top < 0)
1055                 {
1056                     xsrc.top -= DestRect->top;
1057                     xdst.top = 0;
1058                 }
1059                 if (DestRect->bottom > This->currentDesc.Height)
1060                 {
1061                     xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1062                     xdst.bottom = (int) This->currentDesc.Height;
1063                 }
1064             }
1065             /* And check if after clipping something is still to be done... */
1066             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
1067                  (xdst.top   >= (int) This->currentDesc.Height)  ||
1068                  (xdst.left  >= (int) This->currentDesc.Width)   ||
1069                  (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
1070                  (xsrc.top >= (int) Src->currentDesc.Height)     ||
1071                  (xsrc.left >= (int) Src->currentDesc.Width))
1072             {
1073                 TRACE("Nothing to be done after clipping !\n");
1074                 return  WINED3D_OK;
1075             }
1076         }
1077     }
1078
1079     if (Src == This)
1080     {
1081         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1082         slock = dlock;
1083         sEntry = This->resource.format_desc;
1084         dEntry = sEntry;
1085     }
1086     else
1087     {
1088         dEntry = This->resource.format_desc;
1089         if (Src)
1090         {
1091             if (This->resource.format_desc->format != Src->resource.format_desc->format)
1092             {
1093                 Src = surface_convert_format(Src, dEntry->format);
1094                 if(!Src) {
1095                     /* The conv function writes a FIXME */
1096                     WARN("Cannot convert source surface format to dest format\n");
1097                     goto release;
1098                 }
1099             }
1100             IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1101             sEntry = Src->resource.format_desc;
1102         }
1103         else
1104         {
1105             sEntry = dEntry;
1106         }
1107         if (DestRect)
1108             IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1109         else
1110             IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1111     }
1112
1113     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1114
1115     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1116     {
1117         if (!DestRect || Src == This)
1118         {
1119             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1120             goto release;
1121         }
1122     }
1123
1124     bpp = This->resource.format_desc->byte_count;
1125     srcheight = xsrc.bottom - xsrc.top;
1126     srcwidth = xsrc.right - xsrc.left;
1127     dstheight = xdst.bottom - xdst.top;
1128     dstwidth = xdst.right - xdst.left;
1129     width = (xdst.right - xdst.left) * bpp;
1130
1131     assert(width <= dlock.Pitch);
1132
1133     if (DestRect && Src != This)
1134         dbuf = dlock.pBits;
1135     else
1136         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1137
1138     if (Flags & WINEDDBLT_WAIT)
1139     {
1140         Flags &= ~WINEDDBLT_WAIT;
1141     }
1142     if (Flags & WINEDDBLT_ASYNC)
1143     {
1144         static BOOL displayed = FALSE;
1145         if (!displayed)
1146             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1147         displayed = TRUE;
1148         Flags &= ~WINEDDBLT_ASYNC;
1149     }
1150     if (Flags & WINEDDBLT_DONOTWAIT)
1151     {
1152         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1153         static BOOL displayed = FALSE;
1154         if (!displayed)
1155             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1156         displayed = TRUE;
1157         Flags &= ~WINEDDBLT_DONOTWAIT;
1158     }
1159
1160     /* First, all the 'source-less' blits */
1161     if (Flags & WINEDDBLT_COLORFILL)
1162     {
1163         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1164                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1165         Flags &= ~WINEDDBLT_COLORFILL;
1166     }
1167
1168     if (Flags & WINEDDBLT_DEPTHFILL)
1169     {
1170         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1171     }
1172     if (Flags & WINEDDBLT_ROP)
1173     {
1174         /* Catch some degenerate cases here */
1175         switch(DDBltFx->dwROP)
1176         {
1177             case BLACKNESS:
1178                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1179                 break;
1180                 case 0xAA0029: /* No-op */
1181                     break;
1182             case WHITENESS:
1183                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1184                 break;
1185                 case SRCCOPY: /* well, we do that below ? */
1186                     break;
1187             default:
1188                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1189                 goto error;
1190         }
1191         Flags &= ~WINEDDBLT_ROP;
1192     }
1193     if (Flags & WINEDDBLT_DDROPS)
1194     {
1195         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1196     }
1197     /* Now the 'with source' blits */
1198     if (Src)
1199     {
1200         const BYTE *sbase;
1201         int sx, xinc, sy, yinc;
1202
1203         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1204             goto release;
1205         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1206         xinc = (srcwidth << 16) / dstwidth;
1207         yinc = (srcheight << 16) / dstheight;
1208
1209         if (!Flags)
1210         {
1211             /* No effects, we can cheat here */
1212             if (dstwidth == srcwidth)
1213             {
1214                 if (dstheight == srcheight)
1215                 {
1216                     /* No stretching in either direction. This needs to be as
1217                     * fast as possible */
1218                     sbuf = sbase;
1219
1220                     /* check for overlapping surfaces */
1221                     if (Src != This || xdst.top < xsrc.top ||
1222                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1223                     {
1224                         /* no overlap, or dst above src, so copy from top downwards */
1225                         for (y = 0; y < dstheight; y++)
1226                         {
1227                             memcpy(dbuf, sbuf, width);
1228                             sbuf += slock.Pitch;
1229                             dbuf += dlock.Pitch;
1230                         }
1231                     }
1232                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1233                     {
1234                         sbuf += (slock.Pitch*dstheight);
1235                         dbuf += (dlock.Pitch*dstheight);
1236                         for (y = 0; y < dstheight; y++)
1237                         {
1238                             sbuf -= slock.Pitch;
1239                             dbuf -= dlock.Pitch;
1240                             memcpy(dbuf, sbuf, width);
1241                         }
1242                     }
1243                     else /* src and dst overlapping on the same line, use memmove */
1244                     {
1245                         for (y = 0; y < dstheight; y++)
1246                         {
1247                             memmove(dbuf, sbuf, width);
1248                             sbuf += slock.Pitch;
1249                             dbuf += dlock.Pitch;
1250                         }
1251                     }
1252                 } else {
1253                     /* Stretching in Y direction only */
1254                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1255                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1256                         memcpy(dbuf, sbuf, width);
1257                         dbuf += dlock.Pitch;
1258                     }
1259                 }
1260             }
1261             else
1262             {
1263                 /* Stretching in X direction */
1264                 int last_sy = -1;
1265                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1266                 {
1267                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1268
1269                     if ((sy >> 16) == (last_sy >> 16))
1270                     {
1271                         /* this sourcerow is the same as last sourcerow -
1272                         * copy already stretched row
1273                         */
1274                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1275                     }
1276                     else
1277                     {
1278 #define STRETCH_ROW(type) { \
1279                         const type *s = (const type *)sbuf; \
1280                         type *d = (type *)dbuf; \
1281                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1282                         d[x] = s[sx >> 16]; \
1283                         break; }
1284
1285                         switch(bpp)
1286                         {
1287                             case 1: STRETCH_ROW(BYTE)
1288                                     case 2: STRETCH_ROW(WORD)
1289                                             case 4: STRETCH_ROW(DWORD)
1290                             case 3:
1291                             {
1292                                 const BYTE *s;
1293                                 BYTE *d = dbuf;
1294                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1295                                 {
1296                                     DWORD pixel;
1297
1298                                     s = sbuf+3*(sx>>16);
1299                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1300                                     d[0] = (pixel    )&0xff;
1301                                     d[1] = (pixel>> 8)&0xff;
1302                                     d[2] = (pixel>>16)&0xff;
1303                                     d+=3;
1304                                 }
1305                                 break;
1306                             }
1307                             default:
1308                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1309                                 ret = WINED3DERR_NOTAVAILABLE;
1310                                 goto error;
1311                         }
1312 #undef STRETCH_ROW
1313                     }
1314                     dbuf += dlock.Pitch;
1315                     last_sy = sy;
1316                 }
1317             }
1318         }
1319         else
1320         {
1321             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1322             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1323             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1324             if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1325             {
1326                 /* The color keying flags are checked for correctness in ddraw */
1327                 if (Flags & WINEDDBLT_KEYSRC)
1328                 {
1329                     keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1330                     keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1331                 }
1332                 else  if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1333                 {
1334                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1335                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1336                 }
1337
1338                 if (Flags & WINEDDBLT_KEYDEST)
1339                 {
1340                     /* Destination color keys are taken from the source surface ! */
1341                     destkeylow  = Src->DestBltCKey.dwColorSpaceLowValue;
1342                     destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1343                 }
1344                 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1345                 {
1346                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1347                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1348                 }
1349
1350                 if(bpp == 1)
1351                 {
1352                     keymask = 0xff;
1353                 }
1354                 else
1355                 {
1356                     keymask = sEntry->red_mask
1357                             | sEntry->green_mask
1358                             | sEntry->blue_mask;
1359                 }
1360                 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1361             }
1362
1363             if (Flags & WINEDDBLT_DDFX)
1364             {
1365                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1366                 LONG tmpxy;
1367                 dTopLeft     = dbuf;
1368                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1369                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1370                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1371
1372                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1373                 {
1374                     /* I don't think we need to do anything about this flag */
1375                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1376                 }
1377                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1378                 {
1379                     tmp          = dTopRight;
1380                     dTopRight    = dTopLeft;
1381                     dTopLeft     = tmp;
1382                     tmp          = dBottomRight;
1383                     dBottomRight = dBottomLeft;
1384                     dBottomLeft  = tmp;
1385                     dstxinc = dstxinc *-1;
1386                 }
1387                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1388                 {
1389                     tmp          = dTopLeft;
1390                     dTopLeft     = dBottomLeft;
1391                     dBottomLeft  = tmp;
1392                     tmp          = dTopRight;
1393                     dTopRight    = dBottomRight;
1394                     dBottomRight = tmp;
1395                     dstyinc = dstyinc *-1;
1396                 }
1397                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1398                 {
1399                     /* I don't think we need to do anything about this flag */
1400                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1401                 }
1402                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1403                 {
1404                     tmp          = dBottomRight;
1405                     dBottomRight = dTopLeft;
1406                     dTopLeft     = tmp;
1407                     tmp          = dBottomLeft;
1408                     dBottomLeft  = dTopRight;
1409                     dTopRight    = tmp;
1410                     dstxinc = dstxinc * -1;
1411                     dstyinc = dstyinc * -1;
1412                 }
1413                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1414                 {
1415                     tmp          = dTopLeft;
1416                     dTopLeft     = dBottomLeft;
1417                     dBottomLeft  = dBottomRight;
1418                     dBottomRight = dTopRight;
1419                     dTopRight    = tmp;
1420                     tmpxy   = dstxinc;
1421                     dstxinc = dstyinc;
1422                     dstyinc = tmpxy;
1423                     dstxinc = dstxinc * -1;
1424                 }
1425                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1426                 {
1427                     tmp          = dTopLeft;
1428                     dTopLeft     = dTopRight;
1429                     dTopRight    = dBottomRight;
1430                     dBottomRight = dBottomLeft;
1431                     dBottomLeft  = tmp;
1432                     tmpxy   = dstxinc;
1433                     dstxinc = dstyinc;
1434                     dstyinc = tmpxy;
1435                     dstyinc = dstyinc * -1;
1436                 }
1437                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1438                 {
1439                     /* I don't think we need to do anything about this flag */
1440                     WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1441                 }
1442                 dbuf = dTopLeft;
1443                 Flags &= ~(WINEDDBLT_DDFX);
1444             }
1445
1446 #define COPY_COLORKEY_FX(type) { \
1447             const type *s; \
1448             type *d = (type *)dbuf, *dx, tmp; \
1449             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1450             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1451             dx = d; \
1452             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1453             tmp = s[sx >> 16]; \
1454             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1455             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1456             dx[0] = tmp; \
1457         } \
1458             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1459         } \
1460             d = (type*)(((LPBYTE)d)+dstyinc); \
1461         } \
1462             break; }
1463
1464             switch (bpp) {
1465                 case 1: COPY_COLORKEY_FX(BYTE)
1466                         case 2: COPY_COLORKEY_FX(WORD)
1467                                 case 4: COPY_COLORKEY_FX(DWORD)
1468                 case 3:
1469                 {
1470                     const BYTE *s;
1471                     BYTE *d = dbuf, *dx;
1472                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1473                     {
1474                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1475                         dx = d;
1476                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1477                         {
1478                             DWORD pixel, dpixel = 0;
1479                             s = sbuf+3*(sx>>16);
1480                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1481                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1482                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1483                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1484                             {
1485                                 dx[0] = (pixel    )&0xff;
1486                                 dx[1] = (pixel>> 8)&0xff;
1487                                 dx[2] = (pixel>>16)&0xff;
1488                             }
1489                             dx+= dstxinc;
1490                         }
1491                         d += dstyinc;
1492                     }
1493                     break;
1494                 }
1495                 default:
1496                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1497                           (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1498                     ret = WINED3DERR_NOTAVAILABLE;
1499                     goto error;
1500 #undef COPY_COLORKEY_FX
1501             }
1502         }
1503     }
1504
1505 error:
1506     if (Flags && FIXME_ON(d3d_surface))
1507     {
1508         FIXME("\tUnsupported flags: %08x\n", Flags);
1509     }
1510
1511 release:
1512     IWineD3DSurface_UnlockRect(iface);
1513     if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1514     /* Release the converted surface if any */
1515     if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1516     return ret;
1517 }
1518
1519 /*****************************************************************************
1520  * IWineD3DSurface::BltFast, SW emulation version
1521  *
1522  * This is the software implementation of BltFast, as used by GDI surfaces
1523  * and as a fallback for OpenGL surfaces. This code is taken from the old
1524  * DirectDraw code, and was originally written by TransGaming.
1525  *
1526  * Params:
1527  *  dstx:
1528  *  dsty:
1529  *  Source: Source surface to copy from
1530  *  rsrc: Source rectangle
1531  *  trans: Some Flags
1532  *
1533  * Returns:
1534  *  WINED3D_OK on success
1535  *
1536  *****************************************************************************/
1537 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1538         IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1539 {
1540     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1541     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1542
1543     int                 bpp, w, h, x, y;
1544     WINED3DLOCKED_RECT  dlock,slock;
1545     HRESULT             ret = WINED3D_OK;
1546     RECT                rsrc2;
1547     RECT                lock_src, lock_dst, lock_union;
1548     const BYTE          *sbuf;
1549     BYTE                *dbuf;
1550     const struct GlPixelFormatDesc *sEntry, *dEntry;
1551
1552     if (TRACE_ON(d3d_surface))
1553     {
1554         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1555
1556         if (rsrc)
1557         {
1558             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1559                   rsrc->right,rsrc->bottom);
1560         }
1561         else
1562         {
1563             TRACE(" srcrect: NULL\n");
1564         }
1565     }
1566
1567     if ((This->Flags & SFLAG_LOCKED) ||
1568             (Src->Flags & SFLAG_LOCKED))
1569     {
1570         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1571         return WINEDDERR_SURFACEBUSY;
1572     }
1573
1574     if (!rsrc)
1575     {
1576         WARN("rsrc is NULL!\n");
1577         rsrc2.left = 0;
1578         rsrc2.top = 0;
1579         rsrc2.right = Src->currentDesc.Width;
1580         rsrc2.bottom = Src->currentDesc.Height;
1581         rsrc = &rsrc2;
1582     }
1583
1584     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1585     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1586          (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1587          (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1588          (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1589          (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1590     {
1591         WARN("Application gave us bad source rectangle for BltFast.\n");
1592         return WINEDDERR_INVALIDRECT;
1593     }
1594
1595     h = rsrc->bottom - rsrc->top;
1596     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1597     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1598     if (h <= 0) return WINEDDERR_INVALIDRECT;
1599
1600     w = rsrc->right - rsrc->left;
1601     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1602     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1603     if (w <= 0) return WINEDDERR_INVALIDRECT;
1604
1605     /* Now compute the locking rectangle... */
1606     lock_src.left = rsrc->left;
1607     lock_src.top = rsrc->top;
1608     lock_src.right = lock_src.left + w;
1609     lock_src.bottom = lock_src.top + h;
1610
1611     lock_dst.left = dstx;
1612     lock_dst.top = dsty;
1613     lock_dst.right = dstx + w;
1614     lock_dst.bottom = dsty + h;
1615
1616     bpp = This->resource.format_desc->byte_count;
1617
1618     /* We need to lock the surfaces, or we won't get refreshes when done. */
1619     if (Src == This)
1620     {
1621         int pitch;
1622
1623         UnionRect(&lock_union, &lock_src, &lock_dst);
1624
1625         /* Lock the union of the two rectangles */
1626         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1627         if(ret != WINED3D_OK) goto error;
1628
1629         pitch = dlock.Pitch;
1630         slock.Pitch = dlock.Pitch;
1631
1632         /* Since slock was originally copied from this surface's description, we can just reuse it */
1633         assert(This->resource.allocatedMemory != NULL);
1634         sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1635         dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1636         sEntry = Src->resource.format_desc;
1637         dEntry = sEntry;
1638     }
1639     else
1640     {
1641         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1642         if(ret != WINED3D_OK) goto error;
1643         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1644         if(ret != WINED3D_OK) goto error;
1645
1646         sbuf = slock.pBits;
1647         dbuf = dlock.pBits;
1648         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1649
1650         sEntry = Src->resource.format_desc;
1651         dEntry = This->resource.format_desc;
1652     }
1653
1654     /* Handle compressed surfaces first... */
1655     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1656     {
1657         UINT row_block_count;
1658
1659         TRACE("compressed -> compressed copy\n");
1660         if (trans)
1661             FIXME("trans arg not supported when a compressed surface is involved\n");
1662         if (dstx || dsty)
1663             FIXME("offset for destination surface is not supported\n");
1664         if (Src->resource.format_desc->format != This->resource.format_desc->format)
1665         {
1666             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1667             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1668             goto error;
1669         }
1670
1671         row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1672         for (y = 0; y < h; y += dEntry->block_height)
1673         {
1674             memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1675             dbuf += dlock.Pitch;
1676             sbuf += slock.Pitch;
1677         }
1678
1679         goto error;
1680     }
1681     if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1682     {
1683         /* TODO: Use the libtxc_dxtn.so shared library to do
1684          * software decompression
1685          */
1686         ERR("Software decompression not supported.\n");
1687         goto error;
1688     }
1689
1690     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1691     {
1692         DWORD keylow, keyhigh;
1693         TRACE("Color keyed copy\n");
1694         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1695         {
1696             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1697             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1698         }
1699         else
1700         {
1701             /* I'm not sure if this is correct */
1702             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1703             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1704             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1705         }
1706
1707 #define COPYBOX_COLORKEY(type) { \
1708         const type *s = (const type *)sbuf; \
1709         type *d = (type *)dbuf; \
1710         type tmp; \
1711         for (y = 0; y < h; y++) { \
1712         for (x = 0; x < w; x++) { \
1713         tmp = s[x]; \
1714         if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1715     } \
1716         s = (const type *)((const BYTE *)s + slock.Pitch); \
1717         d = (type *)((BYTE *)d + dlock.Pitch); \
1718     } \
1719         break; \
1720     }
1721
1722         switch (bpp) {
1723             case 1: COPYBOX_COLORKEY(BYTE)
1724                     case 2: COPYBOX_COLORKEY(WORD)
1725                             case 4: COPYBOX_COLORKEY(DWORD)
1726             case 3:
1727             {
1728                 const BYTE *s;
1729                 BYTE *d;
1730                 DWORD tmp;
1731                 s = sbuf;
1732                 d = dbuf;
1733                 for (y = 0; y < h; y++)
1734                 {
1735                     for (x = 0; x < w * 3; x += 3)
1736                     {
1737                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1738                         if (tmp < keylow || tmp > keyhigh)
1739                         {
1740                             d[x + 0] = s[x + 0];
1741                             d[x + 1] = s[x + 1];
1742                             d[x + 2] = s[x + 2];
1743                         }
1744                     }
1745                     s += slock.Pitch;
1746                     d += dlock.Pitch;
1747                 }
1748                 break;
1749             }
1750             default:
1751                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1752                 ret = WINED3DERR_NOTAVAILABLE;
1753                 goto error;
1754         }
1755 #undef COPYBOX_COLORKEY
1756         TRACE("Copy Done\n");
1757     }
1758     else
1759     {
1760         int width = w * bpp;
1761         INT sbufpitch, dbufpitch;
1762
1763         TRACE("NO color key copy\n");
1764         /* Handle overlapping surfaces */
1765         if (sbuf < dbuf)
1766         {
1767             sbuf += (h - 1) * slock.Pitch;
1768             dbuf += (h - 1) * dlock.Pitch;
1769             sbufpitch = -slock.Pitch;
1770             dbufpitch = -dlock.Pitch;
1771         }
1772         else
1773         {
1774             sbufpitch = slock.Pitch;
1775             dbufpitch = dlock.Pitch;
1776         }
1777         for (y = 0; y < h; y++)
1778         {
1779             /* This is pretty easy, a line for line memcpy */
1780             memmove(dbuf, sbuf, width);
1781             sbuf += sbufpitch;
1782             dbuf += dbufpitch;
1783         }
1784         TRACE("Copy done\n");
1785     }
1786
1787 error:
1788     if (Src == This)
1789     {
1790         IWineD3DSurface_UnlockRect(iface);
1791     }
1792     else
1793     {
1794         IWineD3DSurface_UnlockRect(iface);
1795         IWineD3DSurface_UnlockRect(Source);
1796     }
1797
1798     return ret;
1799 }
1800
1801 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1802 {
1803     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1804
1805     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1806           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1807
1808     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1809
1810     if (NULL == pRect)
1811     {
1812         pLockedRect->pBits = This->resource.allocatedMemory;
1813         This->lockedRect.left   = 0;
1814         This->lockedRect.top    = 0;
1815         This->lockedRect.right  = This->currentDesc.Width;
1816         This->lockedRect.bottom = This->currentDesc.Height;
1817
1818         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1819               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1820               This->lockedRect.right, This->lockedRect.bottom);
1821     }
1822     else
1823     {
1824         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1825               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1826
1827         /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1828          * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1829          * slightly different meaning compared to regular textures. For DXTn
1830          * textures Pitch is the size of a row of blocks, 4 high and "width"
1831          * long. The x offset is calculated differently as well, since moving 4
1832          * pixels to the right actually moves an entire 4x4 block to right, ie
1833          * 16 bytes (8 in case of DXT1). */
1834         if (This->resource.format_desc->format == WINED3DFMT_DXT1)
1835         {
1836             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1837         }
1838         else if (This->resource.format_desc->format == WINED3DFMT_DXT2
1839                 || This->resource.format_desc->format == WINED3DFMT_DXT3
1840                 || This->resource.format_desc->format == WINED3DFMT_DXT4
1841                 || This->resource.format_desc->format == WINED3DFMT_DXT5)
1842         {
1843             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1844         }
1845         else
1846         {
1847             pLockedRect->pBits = This->resource.allocatedMemory +
1848                     (pLockedRect->Pitch * pRect->top) +
1849                     (pRect->left * This->resource.format_desc->byte_count);
1850         }
1851         This->lockedRect.left   = pRect->left;
1852         This->lockedRect.top    = pRect->top;
1853         This->lockedRect.right  = pRect->right;
1854         This->lockedRect.bottom = pRect->bottom;
1855     }
1856
1857     /* No dirtifying is needed for this surface implementation */
1858     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1859
1860     return WINED3D_OK;
1861 }
1862
1863 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1864     ERR("Should not be called on base texture\n");
1865     return;
1866 }
1867
1868 /* TODO: think about moving this down to resource? */
1869 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1870 {
1871     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1872
1873     /* This should only be called for sysmem textures, it may be a good idea
1874      * to extend this to all pools at some point in the future  */
1875     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1876     {
1877         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1878     }
1879     return This->resource.allocatedMemory;
1880 }