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