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