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