wined3d: Remove some redundant returns.
[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 GlPixelFormatDesc *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 GlPixelFormatDesc *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 GlPixelFormatDesc *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 struct d3dfmt_convertor_desc {
746     WINED3DFORMAT from, to;
747     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
748 };
749
750 static const struct d3dfmt_convertor_desc convertors[] =
751 {
752     {WINED3DFMT_R32_FLOAT,      WINED3DFMT_R16_FLOAT,       convert_r32_float_r16_float},
753     {WINED3DFMT_B5G6R5_UNORM,   WINED3DFMT_B8G8R8X8_UNORM,  convert_r5g6b5_x8r8g8b8},
754     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
755 };
756
757 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
758 {
759     unsigned int i;
760     for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
761         if(convertors[i].from == from && convertors[i].to == to) {
762             return &convertors[i];
763         }
764     }
765     return NULL;
766 }
767
768 /*****************************************************************************
769  * surface_convert_format
770  *
771  * Creates a duplicate of a surface in a different format. Is used by Blt to
772  * blit between surfaces with different formats
773  *
774  * Parameters
775  *  source: Source surface
776  *  fmt: Requested destination format
777  *
778  *****************************************************************************/
779 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
780     IWineD3DSurface *ret = NULL;
781     const struct d3dfmt_convertor_desc *conv;
782     WINED3DLOCKED_RECT lock_src, lock_dst;
783     HRESULT hr;
784
785     conv = find_convertor(source->resource.format_desc->format, to_fmt);
786     if(!conv) {
787         FIXME("Cannot find a conversion function from format %s to %s\n",
788               debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
789         return NULL;
790     }
791
792     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
793             source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard  */, 0 /* level */, &ret,
794             0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
795             0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
796             NULL /* parent */, &wined3d_null_parent_ops);
797     if(!ret) {
798         ERR("Failed to create a destination surface for conversion\n");
799         return NULL;
800     }
801
802     memset(&lock_src, 0, sizeof(lock_src));
803     memset(&lock_dst, 0, sizeof(lock_dst));
804
805     hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
806     if(FAILED(hr)) {
807         ERR("Failed to lock the source surface\n");
808         IWineD3DSurface_Release(ret);
809         return NULL;
810     }
811     hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
812     if(FAILED(hr)) {
813         ERR("Failed to lock the dest surface\n");
814         IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
815         IWineD3DSurface_Release(ret);
816         return NULL;
817     }
818
819     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
820                   source->currentDesc.Width, source->currentDesc.Height);
821
822     IWineD3DSurface_UnlockRect(ret);
823     IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
824
825     return (IWineD3DSurfaceImpl *) ret;
826 }
827
828 /*****************************************************************************
829  * _Blt_ColorFill
830  *
831  * Helper function that fills a memory area with a specific color
832  *
833  * Params:
834  *  buf: memory address to start filling at
835  *  width, height: Dimensions of the area to fill
836  *  bpp: Bit depth of the surface
837  *  lPitch: pitch of the surface
838  *  color: Color to fill with
839  *
840  *****************************************************************************/
841 static HRESULT
842         _Blt_ColorFill(BYTE *buf,
843                        int width, int height,
844                        int bpp, LONG lPitch,
845                        DWORD color)
846 {
847     int x, y;
848     LPBYTE first;
849
850     /* Do first row */
851
852 #define COLORFILL_ROW(type) \
853     { \
854     type *d = (type *) buf; \
855     for (x = 0; x < width; x++) \
856     d[x] = (type) color; \
857     break; \
858 }
859     switch(bpp)
860     {
861         case 1: COLORFILL_ROW(BYTE)
862                 case 2: COLORFILL_ROW(WORD)
863         case 3:
864         {
865             BYTE *d = buf;
866             for (x = 0; x < width; x++,d+=3)
867             {
868                 d[0] = (color    ) & 0xFF;
869                 d[1] = (color>> 8) & 0xFF;
870                 d[2] = (color>>16) & 0xFF;
871             }
872             break;
873         }
874         case 4: COLORFILL_ROW(DWORD)
875         default:
876             FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
877             return WINED3DERR_NOTAVAILABLE;
878     }
879
880 #undef COLORFILL_ROW
881
882     /* Now copy first row */
883     first = buf;
884     for (y = 1; y < height; y++)
885     {
886         buf += lPitch;
887         memcpy(buf, first, width * bpp);
888     }
889     return WINED3D_OK;
890 }
891
892 /*****************************************************************************
893  * IWineD3DSurface::Blt, SW emulation version
894  *
895  * Performs blits to a surface, eigher from a source of source-less blts
896  * This is the main functionality of DirectDraw
897  *
898  * Params:
899  *  DestRect: Destination rectangle to write to
900  *  SrcSurface: Source surface, can be NULL
901  *  SrcRect: Source rectangle
902  *****************************************************************************/
903 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
904         const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
905 {
906     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
907     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
908     RECT        xdst,xsrc;
909     HRESULT     ret = WINED3D_OK;
910     WINED3DLOCKED_RECT  dlock, slock;
911     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
912     const struct GlPixelFormatDesc *sEntry, *dEntry;
913     int x, y;
914     const BYTE *sbuf;
915     BYTE *dbuf;
916     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
917
918     if (TRACE_ON(d3d_surface))
919     {
920         if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
921             DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
922         if (SrcRect) TRACE("\tsrcrect  :%dx%d-%dx%d\n",
923             SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
924 #if 0
925         TRACE("\tflags: ");
926                       DDRAW_dump_DDBLT(Flags);
927                       if (Flags & WINEDDBLT_DDFX)
928               {
929                       TRACE("\tblitfx: ");
930                       DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
931     }
932 #endif
933     }
934
935     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
936     {
937         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
938         return WINEDDERR_SURFACEBUSY;
939     }
940
941     if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
942         /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
943         FIXME("Filters not supported in software blit\n");
944     }
945
946     /* First check for the validity of source / destination rectangles. This was
947      * verified using a test application + by MSDN.
948      */
949     if ((Src != NULL) && (SrcRect != NULL) &&
950          ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
951          (SrcRect->top     > Src->currentDesc.Height)||(SrcRect->top    < 0) ||
952          (SrcRect->left    > Src->currentDesc.Width) ||(SrcRect->left   < 0) ||
953          (SrcRect->right   > Src->currentDesc.Width) ||(SrcRect->right  < 0) ||
954          (SrcRect->right   < SrcRect->left)          ||(SrcRect->bottom < SrcRect->top)))
955     {
956         WARN("Application gave us bad source rectangle for Blt.\n");
957         return WINEDDERR_INVALIDRECT;
958     }
959     /* For the Destination rect, it can be out of bounds on the condition that a clipper
960      * is set for the given surface.
961      */
962     if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
963          ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
964          (DestRect->top     > This->currentDesc.Height)||(DestRect->top    < 0) ||
965          (DestRect->left    > This->currentDesc.Width) ||(DestRect->left   < 0) ||
966          (DestRect->right   > This->currentDesc.Width) ||(DestRect->right  < 0) ||
967          (DestRect->right   < DestRect->left)          ||(DestRect->bottom < DestRect->top)))
968     {
969         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
970         return WINEDDERR_INVALIDRECT;
971     }
972
973     /* Now handle negative values in the rectangles. Warning: only supported for now
974     in the 'simple' cases (ie not in any stretching / rotation cases).
975
976     First, the case where nothing is to be done.
977     */
978     if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0)  ||
979           (DestRect->top    >= (int) This->currentDesc.Height) ||
980           (DestRect->left   >= (int) This->currentDesc.Width))) ||
981           ((Src != NULL) && (SrcRect != NULL) &&
982           ((SrcRect->bottom <= 0) || (SrcRect->right <= 0)     ||
983           (SrcRect->top >= (int) Src->currentDesc.Height) ||
984           (SrcRect->left >= (int) Src->currentDesc.Width))  ))
985     {
986         TRACE("Nothing to be done !\n");
987         return  WINED3D_OK;
988     }
989
990     if (DestRect)
991     {
992         xdst = *DestRect;
993     }
994     else
995     {
996         xdst.top    = 0;
997         xdst.bottom = This->currentDesc.Height;
998         xdst.left   = 0;
999         xdst.right  = This->currentDesc.Width;
1000     }
1001
1002     if (SrcRect)
1003     {
1004         xsrc = *SrcRect;
1005     }
1006     else
1007     {
1008         if (Src)
1009         {
1010             xsrc.top    = 0;
1011             xsrc.bottom = Src->currentDesc.Height;
1012             xsrc.left   = 0;
1013             xsrc.right  = Src->currentDesc.Width;
1014         }
1015         else
1016         {
1017             memset(&xsrc,0,sizeof(xsrc));
1018         }
1019     }
1020
1021     /* The easy case : the source-less blits.... */
1022     if (Src == NULL && DestRect)
1023     {
1024         RECT full_rect;
1025         RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1026
1027         full_rect.left   = 0;
1028         full_rect.top    = 0;
1029         full_rect.right  = This->currentDesc.Width;
1030         full_rect.bottom = This->currentDesc.Height;
1031         IntersectRect(&temp_rect, &full_rect, DestRect);
1032         xdst = temp_rect;
1033     }
1034     else if (DestRect)
1035     {
1036         /* Only handle clipping on the destination rectangle */
1037         int clip_horiz = (DestRect->left < 0) || (DestRect->right  > (int) This->currentDesc.Width );
1038         int clip_vert  = (DestRect->top  < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1039         if (clip_vert || clip_horiz)
1040         {
1041             /* Now check if this is a special case or not... */
1042             if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1043                    (((DestRect->right  - DestRect->left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
1044                    (Flags & WINEDDBLT_DDFX))
1045             {
1046                 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1047                 return  WINED3D_OK;
1048             }
1049
1050             if (clip_horiz)
1051             {
1052                 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1053                 if (DestRect->right > This->currentDesc.Width)
1054                 {
1055                     xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1056                     xdst.right = (int) This->currentDesc.Width;
1057                 }
1058             }
1059             if (clip_vert)
1060             {
1061                 if (DestRect->top < 0)
1062                 {
1063                     xsrc.top -= DestRect->top;
1064                     xdst.top = 0;
1065                 }
1066                 if (DestRect->bottom > This->currentDesc.Height)
1067                 {
1068                     xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1069                     xdst.bottom = (int) This->currentDesc.Height;
1070                 }
1071             }
1072             /* And check if after clipping something is still to be done... */
1073             if ((xdst.bottom <= 0)   || (xdst.right <= 0)       ||
1074                  (xdst.top   >= (int) This->currentDesc.Height)  ||
1075                  (xdst.left  >= (int) This->currentDesc.Width)   ||
1076                  (xsrc.bottom <= 0)   || (xsrc.right <= 0)       ||
1077                  (xsrc.top >= (int) Src->currentDesc.Height)     ||
1078                  (xsrc.left >= (int) Src->currentDesc.Width))
1079             {
1080                 TRACE("Nothing to be done after clipping !\n");
1081                 return  WINED3D_OK;
1082             }
1083         }
1084     }
1085
1086     if (Src == This)
1087     {
1088         IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1089         slock = dlock;
1090         sEntry = This->resource.format_desc;
1091         dEntry = sEntry;
1092     }
1093     else
1094     {
1095         dEntry = This->resource.format_desc;
1096         if (Src)
1097         {
1098             if (This->resource.format_desc->format != Src->resource.format_desc->format)
1099             {
1100                 Src = surface_convert_format(Src, dEntry->format);
1101                 if(!Src) {
1102                     /* The conv function writes a FIXME */
1103                     WARN("Cannot convert source surface format to dest format\n");
1104                     goto release;
1105                 }
1106             }
1107             IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1108             sEntry = Src->resource.format_desc;
1109         }
1110         else
1111         {
1112             sEntry = dEntry;
1113         }
1114         if (DestRect)
1115             IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1116         else
1117             IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1118     }
1119
1120     if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1121
1122     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1123     {
1124         if (!DestRect || Src == This)
1125         {
1126             memcpy(dlock.pBits, slock.pBits, This->resource.size);
1127             goto release;
1128         }
1129     }
1130
1131     bpp = This->resource.format_desc->byte_count;
1132     srcheight = xsrc.bottom - xsrc.top;
1133     srcwidth = xsrc.right - xsrc.left;
1134     dstheight = xdst.bottom - xdst.top;
1135     dstwidth = xdst.right - xdst.left;
1136     width = (xdst.right - xdst.left) * bpp;
1137
1138     if (DestRect && Src != This)
1139         dbuf = dlock.pBits;
1140     else
1141         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1142
1143     if (Flags & WINEDDBLT_WAIT)
1144     {
1145         Flags &= ~WINEDDBLT_WAIT;
1146     }
1147     if (Flags & WINEDDBLT_ASYNC)
1148     {
1149         static BOOL displayed = FALSE;
1150         if (!displayed)
1151             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1152         displayed = TRUE;
1153         Flags &= ~WINEDDBLT_ASYNC;
1154     }
1155     if (Flags & WINEDDBLT_DONOTWAIT)
1156     {
1157         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1158         static BOOL displayed = FALSE;
1159         if (!displayed)
1160             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1161         displayed = TRUE;
1162         Flags &= ~WINEDDBLT_DONOTWAIT;
1163     }
1164
1165     /* First, all the 'source-less' blits */
1166     if (Flags & WINEDDBLT_COLORFILL)
1167     {
1168         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1169                              dlock.Pitch, DDBltFx->u5.dwFillColor);
1170         Flags &= ~WINEDDBLT_COLORFILL;
1171     }
1172
1173     if (Flags & WINEDDBLT_DEPTHFILL)
1174     {
1175         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1176     }
1177     if (Flags & WINEDDBLT_ROP)
1178     {
1179         /* Catch some degenerate cases here */
1180         switch(DDBltFx->dwROP)
1181         {
1182             case BLACKNESS:
1183                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1184                 break;
1185                 case 0xAA0029: /* No-op */
1186                     break;
1187             case WHITENESS:
1188                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1189                 break;
1190                 case SRCCOPY: /* well, we do that below ? */
1191                     break;
1192             default:
1193                 FIXME("Unsupported raster op: %08x  Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1194                 goto error;
1195         }
1196         Flags &= ~WINEDDBLT_ROP;
1197     }
1198     if (Flags & WINEDDBLT_DDROPS)
1199     {
1200         FIXME("\tDdraw Raster Ops: %08x  Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1201     }
1202     /* Now the 'with source' blits */
1203     if (Src)
1204     {
1205         const BYTE *sbase;
1206         int sx, xinc, sy, yinc;
1207
1208         if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1209             goto release;
1210         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1211         xinc = (srcwidth << 16) / dstwidth;
1212         yinc = (srcheight << 16) / dstheight;
1213
1214         if (!Flags)
1215         {
1216             /* No effects, we can cheat here */
1217             if (dstwidth == srcwidth)
1218             {
1219                 if (dstheight == srcheight)
1220                 {
1221                     /* No stretching in either direction. This needs to be as
1222                     * fast as possible */
1223                     sbuf = sbase;
1224
1225                     /* check for overlapping surfaces */
1226                     if (Src != This || xdst.top < xsrc.top ||
1227                         xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1228                     {
1229                         /* no overlap, or dst above src, so copy from top downwards */
1230                         for (y = 0; y < dstheight; y++)
1231                         {
1232                             memcpy(dbuf, sbuf, width);
1233                             sbuf += slock.Pitch;
1234                             dbuf += dlock.Pitch;
1235                         }
1236                     }
1237                     else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
1238                     {
1239                         sbuf += (slock.Pitch*dstheight);
1240                         dbuf += (dlock.Pitch*dstheight);
1241                         for (y = 0; y < dstheight; y++)
1242                         {
1243                             sbuf -= slock.Pitch;
1244                             dbuf -= dlock.Pitch;
1245                             memcpy(dbuf, sbuf, width);
1246                         }
1247                     }
1248                     else /* src and dst overlapping on the same line, use memmove */
1249                     {
1250                         for (y = 0; y < dstheight; y++)
1251                         {
1252                             memmove(dbuf, sbuf, width);
1253                             sbuf += slock.Pitch;
1254                             dbuf += dlock.Pitch;
1255                         }
1256                     }
1257                 } else {
1258                     /* Stretching in Y direction only */
1259                     for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1260                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1261                         memcpy(dbuf, sbuf, width);
1262                         dbuf += dlock.Pitch;
1263                     }
1264                 }
1265             }
1266             else
1267             {
1268                 /* Stretching in X direction */
1269                 int last_sy = -1;
1270                 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1271                 {
1272                     sbuf = sbase + (sy >> 16) * slock.Pitch;
1273
1274                     if ((sy >> 16) == (last_sy >> 16))
1275                     {
1276                         /* this sourcerow is the same as last sourcerow -
1277                         * copy already stretched row
1278                         */
1279                         memcpy(dbuf, dbuf - dlock.Pitch, width);
1280                     }
1281                     else
1282                     {
1283 #define STRETCH_ROW(type) { \
1284                         const type *s = (const type *)sbuf; \
1285                         type *d = (type *)dbuf; \
1286                         for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1287                         d[x] = s[sx >> 16]; \
1288                         break; }
1289
1290                         switch(bpp)
1291                         {
1292                             case 1: STRETCH_ROW(BYTE)
1293                                     case 2: STRETCH_ROW(WORD)
1294                                             case 4: STRETCH_ROW(DWORD)
1295                             case 3:
1296                             {
1297                                 const BYTE *s;
1298                                 BYTE *d = dbuf;
1299                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1300                                 {
1301                                     DWORD pixel;
1302
1303                                     s = sbuf+3*(sx>>16);
1304                                     pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1305                                     d[0] = (pixel    )&0xff;
1306                                     d[1] = (pixel>> 8)&0xff;
1307                                     d[2] = (pixel>>16)&0xff;
1308                                     d+=3;
1309                                 }
1310                                 break;
1311                             }
1312                             default:
1313                                 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1314                                 ret = WINED3DERR_NOTAVAILABLE;
1315                                 goto error;
1316                         }
1317 #undef STRETCH_ROW
1318                     }
1319                     dbuf += dlock.Pitch;
1320                     last_sy = sy;
1321                 }
1322             }
1323         }
1324         else
1325         {
1326             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1327             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1328             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1329             if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1330             {
1331                 /* The color keying flags are checked for correctness in ddraw */
1332                 if (Flags & WINEDDBLT_KEYSRC)
1333                 {
1334                     keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1335                     keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1336                 }
1337                 else  if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1338                 {
1339                     keylow  = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1340                     keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1341                 }
1342
1343                 if (Flags & WINEDDBLT_KEYDEST)
1344                 {
1345                     /* Destination color keys are taken from the source surface ! */
1346                     destkeylow  = Src->DestBltCKey.dwColorSpaceLowValue;
1347                     destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1348                 }
1349                 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1350                 {
1351                     destkeylow  = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1352                     destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1353                 }
1354
1355                 if(bpp == 1)
1356                 {
1357                     keymask = 0xff;
1358                 }
1359                 else
1360                 {
1361                     keymask = sEntry->red_mask
1362                             | sEntry->green_mask
1363                             | sEntry->blue_mask;
1364                 }
1365                 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1366             }
1367
1368             if (Flags & WINEDDBLT_DDFX)
1369             {
1370                 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1371                 LONG tmpxy;
1372                 dTopLeft     = dbuf;
1373                 dTopRight    = dbuf+((dstwidth-1)*bpp);
1374                 dBottomLeft  = dTopLeft+((dstheight-1)*dlock.Pitch);
1375                 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1376
1377                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1378                 {
1379                     /* I don't think we need to do anything about this flag */
1380                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1381                 }
1382                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1383                 {
1384                     tmp          = dTopRight;
1385                     dTopRight    = dTopLeft;
1386                     dTopLeft     = tmp;
1387                     tmp          = dBottomRight;
1388                     dBottomRight = dBottomLeft;
1389                     dBottomLeft  = tmp;
1390                     dstxinc = dstxinc *-1;
1391                 }
1392                 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1393                 {
1394                     tmp          = dTopLeft;
1395                     dTopLeft     = dBottomLeft;
1396                     dBottomLeft  = tmp;
1397                     tmp          = dTopRight;
1398                     dTopRight    = dBottomRight;
1399                     dBottomRight = tmp;
1400                     dstyinc = dstyinc *-1;
1401                 }
1402                 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1403                 {
1404                     /* I don't think we need to do anything about this flag */
1405                     WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1406                 }
1407                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1408                 {
1409                     tmp          = dBottomRight;
1410                     dBottomRight = dTopLeft;
1411                     dTopLeft     = tmp;
1412                     tmp          = dBottomLeft;
1413                     dBottomLeft  = dTopRight;
1414                     dTopRight    = tmp;
1415                     dstxinc = dstxinc * -1;
1416                     dstyinc = dstyinc * -1;
1417                 }
1418                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1419                 {
1420                     tmp          = dTopLeft;
1421                     dTopLeft     = dBottomLeft;
1422                     dBottomLeft  = dBottomRight;
1423                     dBottomRight = dTopRight;
1424                     dTopRight    = tmp;
1425                     tmpxy   = dstxinc;
1426                     dstxinc = dstyinc;
1427                     dstyinc = tmpxy;
1428                     dstxinc = dstxinc * -1;
1429                 }
1430                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1431                 {
1432                     tmp          = dTopLeft;
1433                     dTopLeft     = dTopRight;
1434                     dTopRight    = dBottomRight;
1435                     dBottomRight = dBottomLeft;
1436                     dBottomLeft  = tmp;
1437                     tmpxy   = dstxinc;
1438                     dstxinc = dstyinc;
1439                     dstyinc = tmpxy;
1440                     dstyinc = dstyinc * -1;
1441                 }
1442                 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1443                 {
1444                     /* I don't think we need to do anything about this flag */
1445                     WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1446                 }
1447                 dbuf = dTopLeft;
1448                 Flags &= ~(WINEDDBLT_DDFX);
1449             }
1450
1451 #define COPY_COLORKEY_FX(type) { \
1452             const type *s; \
1453             type *d = (type *)dbuf, *dx, tmp; \
1454             for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1455             s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1456             dx = d; \
1457             for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1458             tmp = s[sx >> 16]; \
1459             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1460             ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1461             dx[0] = tmp; \
1462         } \
1463             dx = (type*)(((LPBYTE)dx)+dstxinc); \
1464         } \
1465             d = (type*)(((LPBYTE)d)+dstyinc); \
1466         } \
1467             break; }
1468
1469             switch (bpp) {
1470                 case 1: COPY_COLORKEY_FX(BYTE)
1471                         case 2: COPY_COLORKEY_FX(WORD)
1472                                 case 4: COPY_COLORKEY_FX(DWORD)
1473                 case 3:
1474                 {
1475                     const BYTE *s;
1476                     BYTE *d = dbuf, *dx;
1477                     for (y = sy = 0; y < dstheight; y++, sy += yinc)
1478                     {
1479                         sbuf = sbase + (sy >> 16) * slock.Pitch;
1480                         dx = d;
1481                         for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1482                         {
1483                             DWORD pixel, dpixel = 0;
1484                             s = sbuf+3*(sx>>16);
1485                             pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1486                             dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1487                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1488                                   ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1489                             {
1490                                 dx[0] = (pixel    )&0xff;
1491                                 dx[1] = (pixel>> 8)&0xff;
1492                                 dx[2] = (pixel>>16)&0xff;
1493                             }
1494                             dx+= dstxinc;
1495                         }
1496                         d += dstyinc;
1497                     }
1498                     break;
1499                 }
1500                 default:
1501                     FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1502                           (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1503                     ret = WINED3DERR_NOTAVAILABLE;
1504                     goto error;
1505 #undef COPY_COLORKEY_FX
1506             }
1507         }
1508     }
1509
1510 error:
1511     if (Flags && FIXME_ON(d3d_surface))
1512     {
1513         FIXME("\tUnsupported flags: %08x\n", Flags);
1514     }
1515
1516 release:
1517     IWineD3DSurface_UnlockRect(iface);
1518     if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1519     /* Release the converted surface if any */
1520     if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1521     return ret;
1522 }
1523
1524 /*****************************************************************************
1525  * IWineD3DSurface::BltFast, SW emulation version
1526  *
1527  * This is the software implementation of BltFast, as used by GDI surfaces
1528  * and as a fallback for OpenGL surfaces. This code is taken from the old
1529  * DirectDraw code, and was originally written by TransGaming.
1530  *
1531  * Params:
1532  *  dstx:
1533  *  dsty:
1534  *  Source: Source surface to copy from
1535  *  rsrc: Source rectangle
1536  *  trans: Some Flags
1537  *
1538  * Returns:
1539  *  WINED3D_OK on success
1540  *
1541  *****************************************************************************/
1542 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1543         IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1544 {
1545     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1546     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1547
1548     int                 bpp, w, h, x, y;
1549     WINED3DLOCKED_RECT  dlock,slock;
1550     HRESULT             ret = WINED3D_OK;
1551     RECT                rsrc2;
1552     RECT                lock_src, lock_dst, lock_union;
1553     const BYTE          *sbuf;
1554     BYTE                *dbuf;
1555     const struct GlPixelFormatDesc *sEntry, *dEntry;
1556
1557     if (TRACE_ON(d3d_surface))
1558     {
1559         TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1560
1561         if (rsrc)
1562         {
1563             TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1564                   rsrc->right,rsrc->bottom);
1565         }
1566         else
1567         {
1568             TRACE(" srcrect: NULL\n");
1569         }
1570     }
1571
1572     if ((This->Flags & SFLAG_LOCKED) ||
1573             (Src->Flags & SFLAG_LOCKED))
1574     {
1575         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1576         return WINEDDERR_SURFACEBUSY;
1577     }
1578
1579     if (!rsrc)
1580     {
1581         WARN("rsrc is NULL!\n");
1582         rsrc2.left = 0;
1583         rsrc2.top = 0;
1584         rsrc2.right = Src->currentDesc.Width;
1585         rsrc2.bottom = Src->currentDesc.Height;
1586         rsrc = &rsrc2;
1587     }
1588
1589     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1590     if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1591          (rsrc->top    > Src->currentDesc.Height) || (rsrc->top    < 0) ||
1592          (rsrc->left   > Src->currentDesc.Width)  || (rsrc->left   < 0) ||
1593          (rsrc->right  > Src->currentDesc.Width)  || (rsrc->right  < 0) ||
1594          (rsrc->right  < rsrc->left)              || (rsrc->bottom < rsrc->top))
1595     {
1596         WARN("Application gave us bad source rectangle for BltFast.\n");
1597         return WINEDDERR_INVALIDRECT;
1598     }
1599
1600     h = rsrc->bottom - rsrc->top;
1601     if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1602     if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1603     if (h <= 0) return WINEDDERR_INVALIDRECT;
1604
1605     w = rsrc->right - rsrc->left;
1606     if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1607     if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1608     if (w <= 0) return WINEDDERR_INVALIDRECT;
1609
1610     /* Now compute the locking rectangle... */
1611     lock_src.left = rsrc->left;
1612     lock_src.top = rsrc->top;
1613     lock_src.right = lock_src.left + w;
1614     lock_src.bottom = lock_src.top + h;
1615
1616     lock_dst.left = dstx;
1617     lock_dst.top = dsty;
1618     lock_dst.right = dstx + w;
1619     lock_dst.bottom = dsty + h;
1620
1621     bpp = This->resource.format_desc->byte_count;
1622
1623     /* We need to lock the surfaces, or we won't get refreshes when done. */
1624     if (Src == This)
1625     {
1626         int pitch;
1627
1628         UnionRect(&lock_union, &lock_src, &lock_dst);
1629
1630         /* Lock the union of the two rectangles */
1631         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1632         if(ret != WINED3D_OK) goto error;
1633
1634         pitch = dlock.Pitch;
1635         slock.Pitch = dlock.Pitch;
1636
1637         /* Since slock was originally copied from this surface's description, we can just reuse it */
1638         sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1639         dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1640         sEntry = Src->resource.format_desc;
1641         dEntry = sEntry;
1642     }
1643     else
1644     {
1645         ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1646         if(ret != WINED3D_OK) goto error;
1647         ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1648         if(ret != WINED3D_OK) goto error;
1649
1650         sbuf = slock.pBits;
1651         dbuf = dlock.pBits;
1652         TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1653
1654         sEntry = Src->resource.format_desc;
1655         dEntry = This->resource.format_desc;
1656     }
1657
1658     /* Handle compressed surfaces first... */
1659     if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1660     {
1661         UINT row_block_count;
1662
1663         TRACE("compressed -> compressed copy\n");
1664         if (trans)
1665             FIXME("trans arg not supported when a compressed surface is involved\n");
1666         if (dstx || dsty)
1667             FIXME("offset for destination surface is not supported\n");
1668         if (Src->resource.format_desc->format != This->resource.format_desc->format)
1669         {
1670             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1671             ret = WINED3DERR_WRONGTEXTUREFORMAT;
1672             goto error;
1673         }
1674
1675         row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1676         for (y = 0; y < h; y += dEntry->block_height)
1677         {
1678             memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1679             dbuf += dlock.Pitch;
1680             sbuf += slock.Pitch;
1681         }
1682
1683         goto error;
1684     }
1685     if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1686     {
1687         /* TODO: Use the libtxc_dxtn.so shared library to do
1688          * software decompression
1689          */
1690         ERR("Software decompression not supported.\n");
1691         goto error;
1692     }
1693
1694     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1695     {
1696         DWORD keylow, keyhigh;
1697         DWORD mask = Src->resource.format_desc->red_mask |
1698                      Src->resource.format_desc->green_mask |
1699                      Src->resource.format_desc->blue_mask;
1700
1701         /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1702         if(!mask && bpp==1)
1703             mask = 0xff;
1704
1705         TRACE("Color keyed copy\n");
1706         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1707         {
1708             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1709             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1710         }
1711         else
1712         {
1713             /* I'm not sure if this is correct */
1714             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1715             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1716             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1717         }
1718
1719 #define COPYBOX_COLORKEY(type) { \
1720         const type *s = (const type *)sbuf; \
1721         type *d = (type *)dbuf; \
1722         type tmp; \
1723         for (y = 0; y < h; y++) { \
1724         for (x = 0; x < w; x++) { \
1725         tmp = s[x]; \
1726         if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1727     } \
1728         s = (const type *)((const BYTE *)s + slock.Pitch); \
1729         d = (type *)((BYTE *)d + dlock.Pitch); \
1730     } \
1731         break; \
1732     }
1733
1734         switch (bpp) {
1735             case 1: COPYBOX_COLORKEY(BYTE)
1736                     case 2: COPYBOX_COLORKEY(WORD)
1737                             case 4: COPYBOX_COLORKEY(DWORD)
1738             case 3:
1739             {
1740                 const BYTE *s;
1741                 BYTE *d;
1742                 DWORD tmp;
1743                 s = sbuf;
1744                 d = dbuf;
1745                 for (y = 0; y < h; y++)
1746                 {
1747                     for (x = 0; x < w * 3; x += 3)
1748                     {
1749                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1750                         if (tmp < keylow || tmp > keyhigh)
1751                         {
1752                             d[x + 0] = s[x + 0];
1753                             d[x + 1] = s[x + 1];
1754                             d[x + 2] = s[x + 2];
1755                         }
1756                     }
1757                     s += slock.Pitch;
1758                     d += dlock.Pitch;
1759                 }
1760                 break;
1761             }
1762             default:
1763                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1764                 ret = WINED3DERR_NOTAVAILABLE;
1765                 goto error;
1766         }
1767 #undef COPYBOX_COLORKEY
1768         TRACE("Copy Done\n");
1769     }
1770     else
1771     {
1772         int width = w * bpp;
1773         INT sbufpitch, dbufpitch;
1774
1775         TRACE("NO color key copy\n");
1776         /* Handle overlapping surfaces */
1777         if (sbuf < dbuf)
1778         {
1779             sbuf += (h - 1) * slock.Pitch;
1780             dbuf += (h - 1) * dlock.Pitch;
1781             sbufpitch = -slock.Pitch;
1782             dbufpitch = -dlock.Pitch;
1783         }
1784         else
1785         {
1786             sbufpitch = slock.Pitch;
1787             dbufpitch = dlock.Pitch;
1788         }
1789         for (y = 0; y < h; y++)
1790         {
1791             /* This is pretty easy, a line for line memcpy */
1792             memmove(dbuf, sbuf, width);
1793             sbuf += sbufpitch;
1794             dbuf += dbufpitch;
1795         }
1796         TRACE("Copy done\n");
1797     }
1798
1799 error:
1800     if (Src == This)
1801     {
1802         IWineD3DSurface_UnlockRect(iface);
1803     }
1804     else
1805     {
1806         IWineD3DSurface_UnlockRect(iface);
1807         IWineD3DSurface_UnlockRect(Source);
1808     }
1809
1810     return ret;
1811 }
1812
1813 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1814 {
1815     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1816
1817     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1818           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1819
1820     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1821
1822     if (NULL == pRect)
1823     {
1824         pLockedRect->pBits = This->resource.allocatedMemory;
1825         This->lockedRect.left   = 0;
1826         This->lockedRect.top    = 0;
1827         This->lockedRect.right  = This->currentDesc.Width;
1828         This->lockedRect.bottom = This->currentDesc.Height;
1829
1830         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1831               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1832               This->lockedRect.right, This->lockedRect.bottom);
1833     }
1834     else
1835     {
1836         const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1837
1838         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1839               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1840
1841         if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1842         {
1843             /* Compressed textures are block based, so calculate the offset of
1844              * the block that contains the top-left pixel of the locked rectangle. */
1845             pLockedRect->pBits = This->resource.allocatedMemory
1846                     + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1847                     + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1848         }
1849         else
1850         {
1851             pLockedRect->pBits = This->resource.allocatedMemory +
1852                     (pLockedRect->Pitch * pRect->top) +
1853                     (pRect->left * format_desc->byte_count);
1854         }
1855         This->lockedRect.left   = pRect->left;
1856         This->lockedRect.top    = pRect->top;
1857         This->lockedRect.right  = pRect->right;
1858         This->lockedRect.bottom = pRect->bottom;
1859     }
1860
1861     /* No dirtifying is needed for this surface implementation */
1862     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1863
1864     return WINED3D_OK;
1865 }
1866
1867 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1868     ERR("Should not be called on base texture\n");
1869 }
1870
1871 /* TODO: think about moving this down to resource? */
1872 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1873 {
1874     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1875
1876     /* This should only be called for sysmem textures, it may be a good idea
1877      * to extend this to all pools at some point in the future  */
1878     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1879     {
1880         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1881     }
1882     return This->resource.allocatedMemory;
1883 }