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