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