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