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