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