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