wined3d: Handle per-texture max LOD level.
[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  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
34
35 /* See also float_16_to_32() in wined3d_private.h */
36 static inline unsigned short float_32_to_16(const float *in)
37 {
38     int exp = 0;
39     float tmp = fabs(*in);
40     unsigned int mantissa;
41     unsigned short ret;
42
43     /* Deal with special numbers */
44     if (*in == 0.0f) return 0x0000;
45     if(isnan(*in)) return 0x7C01;
46     if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
47
48     if(tmp < pow(2, 10)) {
49         do
50         {
51             tmp = tmp * 2.0f;
52             exp--;
53         }while(tmp < pow(2, 10));
54     } else if(tmp >= pow(2, 11)) {
55         do
56         {
57             tmp /= 2.0f;
58             exp++;
59         }while(tmp >= pow(2, 11));
60     }
61
62     mantissa = (unsigned int) tmp;
63     if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
64
65     exp += 10;  /* Normalize the mantissa */
66     exp += 15;  /* Exponent is encoded with excess 15 */
67
68     if(exp > 30) { /* too big */
69         ret = 0x7c00; /* INF */
70     } else if(exp <= 0) {
71         /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
72         while(exp <= 0) {
73             mantissa = mantissa >> 1;
74             exp++;
75         }
76         ret = mantissa & 0x3ff;
77     } else {
78         ret = (exp << 10) | (mantissa & 0x3ff);
79     }
80
81     ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
82     return ret;
83 }
84
85
86 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
87
88 /* *******************************************
89    IWineD3DSurface IUnknown parts follow
90    ******************************************* */
91 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
92 {
93     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
94     /* Warn ,but be nice about things */
95     TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
96
97     if (IsEqualGUID(riid, &IID_IUnknown)
98         || IsEqualGUID(riid, &IID_IWineD3DBase)
99         || IsEqualGUID(riid, &IID_IWineD3DResource)
100         || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
101         IUnknown_AddRef((IUnknown*)iface);
102         *ppobj = This;
103         return S_OK;
104         }
105         *ppobj = NULL;
106         return E_NOINTERFACE;
107 }
108
109 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
110     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
111     ULONG ref = InterlockedIncrement(&This->resource.ref);
112     TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
113     return ref;
114 }
115
116 /* ****************************************************
117    IWineD3DSurface IWineD3DResource parts follow
118    **************************************************** */
119 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
120     return resource_get_device((IWineD3DResource *)iface, ppDevice);
121 }
122
123 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
124     return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
125 }
126
127 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
128     return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
129 }
130
131 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
132     return resource_free_private_data((IWineD3DResource *)iface, refguid);
133 }
134
135 DWORD   WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
136     return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
137 }
138
139 DWORD   WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
140     return resource_get_priority((IWineD3DResource *)iface);
141 }
142
143 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
144     TRACE("(%p) : calling resourceimpl_GetType\n", iface);
145     return resource_get_type((IWineD3DResource *)iface);
146 }
147
148 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
149     TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
150     return resource_get_parent((IWineD3DResource *)iface, pParent);
151 }
152
153 /* ******************************************************
154    IWineD3DSurface IWineD3DSurface parts follow
155    ****************************************************** */
156
157 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
158     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
159     IWineD3DBase *container = 0;
160
161     TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
162
163     if (!ppContainer) {
164         ERR("Called without a valid ppContainer.\n");
165     }
166
167     /* Standalone surfaces return the device as container. */
168     if (This->container) {
169         container = This->container;
170     } else {
171         container = (IWineD3DBase *)This->resource.wineD3DDevice;
172     }
173
174     TRACE("Relaying to QueryInterface\n");
175     return IUnknown_QueryInterface(container, riid, ppContainer);
176 }
177
178 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
179     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
180
181     TRACE("(%p) : copying into %p\n", This, pDesc);
182
183     pDesc->format = This->resource.format_desc->format;
184     pDesc->resource_type = This->resource.resourceType;
185     pDesc->usage = This->resource.usage;
186     pDesc->pool = This->resource.pool;
187     pDesc->size = This->resource.size; /* dx8 only */
188     pDesc->multisample_type = This->currentDesc.MultiSampleType;
189     pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
190     pDesc->width = This->currentDesc.Width;
191     pDesc->height = This->currentDesc.Height;
192
193     return WINED3D_OK;
194 }
195
196 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
197     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
198     TRACE("(%p)->(%x)\n", This, Flags);
199
200     switch (Flags)
201     {
202         case WINEDDGBS_CANBLT:
203         case WINEDDGBS_ISBLTDONE:
204             return WINED3D_OK;
205
206         default:
207             return WINED3DERR_INVALIDCALL;
208     }
209 }
210
211 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
212     /* XXX: DDERR_INVALIDSURFACETYPE */
213
214     TRACE("(%p)->(%08x)\n",iface,Flags);
215     switch (Flags) {
216         case WINEDDGFS_CANFLIP:
217         case WINEDDGFS_ISFLIPDONE:
218             return WINED3D_OK;
219
220         default:
221             return WINED3DERR_INVALIDCALL;
222     }
223 }
224
225 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
226     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
227     TRACE("(%p)\n", This);
228
229     /* D3D8 and 9 loose full devices, ddraw only surfaces */
230     return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
231 }
232
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
234     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235     TRACE("(%p)\n", This);
236
237     /* So far we don't lose anything :) */
238     This->Flags &= ~SFLAG_LOST;
239     return WINED3D_OK;
240 }
241
242 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
243     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
244     IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
245     TRACE("(%p)->(%p)\n", This, Pal);
246
247     if(This->palette == PalImpl) {
248         TRACE("Nop palette change\n");
249         return WINED3D_OK;
250     }
251
252     if(This->palette != NULL)
253         if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
254             This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
255
256     This->palette = PalImpl;
257
258     if(PalImpl != NULL) {
259         if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
260             (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
261         }
262
263         return IWineD3DSurface_RealizePalette(iface);
264     }
265     else return WINED3D_OK;
266 }
267
268 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
269 {
270     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
271     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
272
273     if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
274         FIXME(" colorkey value not supported (%08x) !\n", Flags);
275         return WINED3DERR_INVALIDCALL;
276     }
277
278     /* Dirtify the surface, but only if a key was changed */
279     if(CKey) {
280         switch (Flags & ~WINEDDCKEY_COLORSPACE) {
281             case WINEDDCKEY_DESTBLT:
282                 This->DestBltCKey = *CKey;
283                 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
284                 break;
285
286             case WINEDDCKEY_DESTOVERLAY:
287                 This->DestOverlayCKey = *CKey;
288                 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
289                 break;
290
291             case WINEDDCKEY_SRCOVERLAY:
292                 This->SrcOverlayCKey = *CKey;
293                 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
294                 break;
295
296             case WINEDDCKEY_SRCBLT:
297                 This->SrcBltCKey = *CKey;
298                 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
299                 break;
300         }
301     }
302     else {
303         switch (Flags & ~WINEDDCKEY_COLORSPACE) {
304             case WINEDDCKEY_DESTBLT:
305                 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
306                 break;
307
308             case WINEDDCKEY_DESTOVERLAY:
309                 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
310                 break;
311
312             case WINEDDCKEY_SRCOVERLAY:
313                 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
314                 break;
315
316             case WINEDDCKEY_SRCBLT:
317                 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
318                 break;
319         }
320     }
321
322     return WINED3D_OK;
323 }
324
325 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
326     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
327     TRACE("(%p)->(%p)\n", This, Pal);
328
329     *Pal = (IWineD3DPalette *) This->palette;
330     return WINED3D_OK;
331 }
332
333 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
334     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
335     const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
336     DWORD ret;
337     TRACE("(%p)\n", This);
338
339     if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
340     {
341         /* Since compressed formats are block based, pitch means the amount of
342          * bytes to the next row of block rather than the next row of pixels. */
343         UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
344         ret = row_block_count * format_desc->block_byte_count;
345     }
346     else
347     {
348         unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
349         ret = This->resource.format_desc->byte_count * This->currentDesc.Width;  /* Bytes / row */
350         ret = (ret + alignment - 1) & ~(alignment - 1);
351     }
352     TRACE("(%p) Returning %d\n", This, ret);
353     return ret;
354 }
355
356 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
357     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
358     LONG w, h;
359
360     TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
361
362     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
363     {
364         TRACE("(%p): Not an overlay surface\n", This);
365         return WINEDDERR_NOTAOVERLAYSURFACE;
366     }
367
368     w = This->overlay_destrect.right - This->overlay_destrect.left;
369     h = This->overlay_destrect.bottom - This->overlay_destrect.top;
370     This->overlay_destrect.left = X;
371     This->overlay_destrect.top = Y;
372     This->overlay_destrect.right = X + w;
373     This->overlay_destrect.bottom = Y + h;
374
375     IWineD3DSurface_DrawOverlay(iface);
376
377     return WINED3D_OK;
378 }
379
380 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
381     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
382     HRESULT hr;
383
384     TRACE("(%p)->(%p,%p)\n", This, X, Y);
385
386     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
387     {
388         TRACE("(%p): Not an overlay surface\n", This);
389         return WINEDDERR_NOTAOVERLAYSURFACE;
390     }
391     if(This->overlay_dest == NULL) {
392         *X = 0; *Y = 0;
393         hr = WINEDDERR_OVERLAYNOTVISIBLE;
394     } else {
395         *X = This->overlay_destrect.left;
396         *Y = This->overlay_destrect.top;
397         hr = WINED3D_OK;
398     }
399
400     TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
401     return hr;
402 }
403
404 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
405     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
406     IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
407
408     FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
409
410     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
411     {
412         TRACE("(%p): Not an overlay surface\n", This);
413         return WINEDDERR_NOTAOVERLAYSURFACE;
414     }
415
416     return WINED3D_OK;
417 }
418
419 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
420         IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
421 {
422     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
423     IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
424     TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
425
426     if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
427     {
428         WARN("(%p): Not an overlay surface\n", This);
429         return WINEDDERR_NOTAOVERLAYSURFACE;
430     } else if(!DstSurface) {
431         WARN("(%p): Dest surface is NULL\n", This);
432         return WINED3DERR_INVALIDCALL;
433     }
434
435     if(SrcRect) {
436         This->overlay_srcrect = *SrcRect;
437     } else {
438         This->overlay_srcrect.left = 0;
439         This->overlay_srcrect.top = 0;
440         This->overlay_srcrect.right = This->currentDesc.Width;
441         This->overlay_srcrect.bottom = This->currentDesc.Height;
442     }
443
444     if(DstRect) {
445         This->overlay_destrect = *DstRect;
446     } else {
447         This->overlay_destrect.left = 0;
448         This->overlay_destrect.top = 0;
449         This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
450         This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
451     }
452
453     if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
454         list_remove(&This->overlay_entry);
455     }
456
457     if(Flags & WINEDDOVER_SHOW) {
458         if(This->overlay_dest != Dst) {
459             This->overlay_dest = Dst;
460             list_add_tail(&Dst->overlays, &This->overlay_entry);
461         }
462     } else if(Flags & WINEDDOVER_HIDE) {
463         /* tests show that the rectangles are erased on hide */
464         This->overlay_srcrect.left   = 0; This->overlay_srcrect.top     = 0;
465         This->overlay_srcrect.right  = 0; This->overlay_srcrect.bottom  = 0;
466         This->overlay_destrect.left  = 0; This->overlay_destrect.top    = 0;
467         This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
468         This->overlay_dest = NULL;
469     }
470
471     IWineD3DSurface_DrawOverlay(iface);
472
473     return WINED3D_OK;
474 }
475
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
477 {
478     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479     TRACE("(%p)->(%p)\n", This, clipper);
480
481     This->clipper = clipper;
482     return WINED3D_OK;
483 }
484
485 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
486 {
487     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
488     TRACE("(%p)->(%p)\n", This, clipper);
489
490     *clipper = This->clipper;
491     if(*clipper) {
492         IWineD3DClipper_AddRef(*clipper);
493     }
494     return WINED3D_OK;
495 }
496
497 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
498     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
499
500     TRACE("This %p, container %p\n", This, container);
501
502     /* We can't keep a reference to the container, since the container already keeps a reference to us. */
503
504     TRACE("Setting container to %p from %p\n", container, This->container);
505     This->container = container;
506
507     return WINED3D_OK;
508 }
509
510 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
511     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
512     const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
513             &This->resource.wineD3DDevice->adapter->gl_info);
514
515     if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
516     {
517         FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
518         return WINED3DERR_INVALIDCALL;
519     }
520
521     TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
522
523     This->resource.size = surface_calculate_size(format_desc, This->resource.wineD3DDevice->surface_alignment,
524             This->pow2Width, This->pow2Height);
525
526     This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
527
528     This->resource.format_desc = format_desc;
529
530     TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
531
532     return WINED3D_OK;
533 }
534
535 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
536     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
537     const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
538     int extraline = 0;
539     SYSTEM_INFO sysInfo;
540     BITMAPINFO* b_info;
541     HDC ddc;
542     DWORD *masks;
543     UINT usage;
544
545     switch (format_desc->byte_count)
546     {
547         case 2:
548         case 4:
549             /* Allocate extra space to store the RGB bit masks. */
550             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
551             break;
552
553         case 3:
554             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
555             break;
556
557         default:
558             /* Allocate extra space for a palette. */
559             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
560                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
561             break;
562     }
563
564     if (!b_info)
565         return E_OUTOFMEMORY;
566
567         /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
568     * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
569     * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
570     * add an extra line to the dib section
571         */
572     GetSystemInfo(&sysInfo);
573     if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
574         extraline = 1;
575         TRACE("Adding an extra line to the dib section\n");
576     }
577
578     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
579     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
580     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
581     b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
582     b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
583     b_info->bmiHeader.biPlanes = 1;
584     b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
585
586     b_info->bmiHeader.biXPelsPerMeter = 0;
587     b_info->bmiHeader.biYPelsPerMeter = 0;
588     b_info->bmiHeader.biClrUsed = 0;
589     b_info->bmiHeader.biClrImportant = 0;
590
591     /* Get the bit masks */
592     masks = (DWORD *)b_info->bmiColors;
593     switch (This->resource.format_desc->format)
594     {
595         case WINED3DFMT_R8G8B8:
596             usage = DIB_RGB_COLORS;
597             b_info->bmiHeader.biCompression = BI_RGB;
598             break;
599
600         case WINED3DFMT_X1R5G5B5:
601         case WINED3DFMT_A1R5G5B5:
602         case WINED3DFMT_A4R4G4B4:
603         case WINED3DFMT_X4R4G4B4:
604         case WINED3DFMT_R3G3B2:
605         case WINED3DFMT_A8R3G3B2:
606         case WINED3DFMT_R10G10B10A2_UNORM:
607         case WINED3DFMT_R8G8B8A8_UNORM:
608         case WINED3DFMT_X8B8G8R8:
609         case WINED3DFMT_A2R10G10B10:
610         case WINED3DFMT_R5G6B5:
611         case WINED3DFMT_R16G16B16A16_UNORM:
612             usage = 0;
613             b_info->bmiHeader.biCompression = BI_BITFIELDS;
614             masks[0] = format_desc->red_mask;
615             masks[1] = format_desc->green_mask;
616             masks[2] = format_desc->blue_mask;
617             break;
618
619         default:
620             /* Don't know palette */
621             b_info->bmiHeader.biCompression = BI_RGB;
622             usage = 0;
623             break;
624     }
625
626     ddc = GetDC(0);
627     if (ddc == 0) {
628         HeapFree(GetProcessHeap(), 0, b_info);
629         return HRESULT_FROM_WIN32(GetLastError());
630     }
631
632     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);
633     This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
634     ReleaseDC(0, ddc);
635
636     if (!This->dib.DIBsection) {
637         ERR("CreateDIBSection failed!\n");
638         HeapFree(GetProcessHeap(), 0, b_info);
639         return HRESULT_FROM_WIN32(GetLastError());
640     }
641
642     TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
643     /* copy the existing surface to the dib section */
644     if(This->resource.allocatedMemory) {
645         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,  This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
646     } else {
647         /* This is to make LockRect read the gl Texture although memory is allocated */
648         This->Flags &= ~SFLAG_INSYSMEM;
649     }
650     This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
651
652     HeapFree(GetProcessHeap(), 0, b_info);
653
654     /* Now allocate a HDC */
655     This->hDC = CreateCompatibleDC(0);
656     This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
657     TRACE("using wined3d palette %p\n", This->palette);
658     SelectPalette(This->hDC,
659                   This->palette ? This->palette->hpal : 0,
660                   FALSE);
661
662     This->Flags |= SFLAG_DIBSECTION;
663
664     HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
665     This->resource.heapMemory = NULL;
666
667     return WINED3D_OK;
668 }
669
670 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
671                               unsigned int w, unsigned int h)
672 {
673     unsigned int x, y;
674     const float *src_f;
675     unsigned short *dst_s;
676
677     TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
678     for(y = 0; y < h; y++) {
679         src_f = (const float *)(src + y * pitch_in);
680         dst_s = (unsigned short *) (dst + y * pitch_out);
681         for(x = 0; x < w; x++) {
682             dst_s[x] = float_32_to_16(src_f + x);
683         }
684     }
685 }
686
687 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
688         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
689 {
690     static const unsigned char convert_5to8[] =
691     {
692         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
693         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
694         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
695         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
696     };
697     static const unsigned char convert_6to8[] =
698     {
699         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
700         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
701         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
702         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
703         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
704         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
705         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
706         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
707     };
708     unsigned int x, y;
709
710     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
711
712     for (y = 0; y < h; ++y)
713     {
714         const WORD *src_line = (const WORD *)(src + y * pitch_in);
715         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
716         for (x = 0; x < w; ++x)
717         {
718             WORD pixel = src_line[x];
719             dst_line[x] = 0xff000000
720                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
721                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
722                     | convert_5to8[(pixel & 0x001f)];
723         }
724     }
725 }
726
727 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
728         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
729 {
730     unsigned int x, y;
731
732     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
733
734     for (y = 0; y < h; ++y)
735     {
736         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
737         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
738
739         for (x = 0; x < w; ++x)
740         {
741             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
742         }
743     }
744 }
745
746 struct d3dfmt_convertor_desc {
747     WINED3DFORMAT from, to;
748     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
749 };
750
751 static const struct d3dfmt_convertor_desc convertors[] =
752 {
753     {WINED3DFMT_R32_FLOAT,  WINED3DFMT_R16_FLOAT,   convert_r32_float_r16_float},
754     {WINED3DFMT_R5G6B5,     WINED3DFMT_X8R8G8B8,    convert_r5g6b5_x8r8g8b8},
755     {WINED3DFMT_A8R8G8B8,   WINED3DFMT_X8R8G8B8,    convert_a8r8g8b8_x8r8g8b8},
756 };
757
758 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
759 {
760     unsigned int i;
761     for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
762         if(convertors[i].from == from && convertors[i].to == to) {
763             return &convertors[i];
764         }
765     }
766     return NULL;
767 }
768
769 /*****************************************************************************
770  * surface_convert_format
771  *
772  * Creates a duplicate of a surface in a different format. Is used by Blt to
773  * blit between surfaces with different formats
774  *
775  * Parameters
776  *  source: Source surface
777  *  fmt: Requested destination format
778  *
779  *****************************************************************************/
780 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
781     IWineD3DSurface *ret = NULL;
782     const struct d3dfmt_convertor_desc *conv;
783     WINED3DLOCKED_RECT lock_src, lock_dst;
784     HRESULT hr;
785
786     conv = find_convertor(source->resource.format_desc->format, to_fmt);
787     if(!conv) {
788         FIXME("Cannot find a conversion function from format %s to %s\n",
789               debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
790         return NULL;
791     }
792
793     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice, source->currentDesc.Width,
794             source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard  */, 0 /* level */, &ret,
795             0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
796             0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
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         TRACE("Color keyed copy\n");
1698         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1699         {
1700             keylow  = Src->SrcBltCKey.dwColorSpaceLowValue;
1701             keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1702         }
1703         else
1704         {
1705             /* I'm not sure if this is correct */
1706             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1707             keylow  = This->DestBltCKey.dwColorSpaceLowValue;
1708             keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1709         }
1710
1711 #define COPYBOX_COLORKEY(type) { \
1712         const type *s = (const type *)sbuf; \
1713         type *d = (type *)dbuf; \
1714         type tmp; \
1715         for (y = 0; y < h; y++) { \
1716         for (x = 0; x < w; x++) { \
1717         tmp = s[x]; \
1718         if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1719     } \
1720         s = (const type *)((const BYTE *)s + slock.Pitch); \
1721         d = (type *)((BYTE *)d + dlock.Pitch); \
1722     } \
1723         break; \
1724     }
1725
1726         switch (bpp) {
1727             case 1: COPYBOX_COLORKEY(BYTE)
1728                     case 2: COPYBOX_COLORKEY(WORD)
1729                             case 4: COPYBOX_COLORKEY(DWORD)
1730             case 3:
1731             {
1732                 const BYTE *s;
1733                 BYTE *d;
1734                 DWORD tmp;
1735                 s = sbuf;
1736                 d = dbuf;
1737                 for (y = 0; y < h; y++)
1738                 {
1739                     for (x = 0; x < w * 3; x += 3)
1740                     {
1741                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1742                         if (tmp < keylow || tmp > keyhigh)
1743                         {
1744                             d[x + 0] = s[x + 0];
1745                             d[x + 1] = s[x + 1];
1746                             d[x + 2] = s[x + 2];
1747                         }
1748                     }
1749                     s += slock.Pitch;
1750                     d += dlock.Pitch;
1751                 }
1752                 break;
1753             }
1754             default:
1755                 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1756                 ret = WINED3DERR_NOTAVAILABLE;
1757                 goto error;
1758         }
1759 #undef COPYBOX_COLORKEY
1760         TRACE("Copy Done\n");
1761     }
1762     else
1763     {
1764         int width = w * bpp;
1765         INT sbufpitch, dbufpitch;
1766
1767         TRACE("NO color key copy\n");
1768         /* Handle overlapping surfaces */
1769         if (sbuf < dbuf)
1770         {
1771             sbuf += (h - 1) * slock.Pitch;
1772             dbuf += (h - 1) * dlock.Pitch;
1773             sbufpitch = -slock.Pitch;
1774             dbufpitch = -dlock.Pitch;
1775         }
1776         else
1777         {
1778             sbufpitch = slock.Pitch;
1779             dbufpitch = dlock.Pitch;
1780         }
1781         for (y = 0; y < h; y++)
1782         {
1783             /* This is pretty easy, a line for line memcpy */
1784             memmove(dbuf, sbuf, width);
1785             sbuf += sbufpitch;
1786             dbuf += dbufpitch;
1787         }
1788         TRACE("Copy done\n");
1789     }
1790
1791 error:
1792     if (Src == This)
1793     {
1794         IWineD3DSurface_UnlockRect(iface);
1795     }
1796     else
1797     {
1798         IWineD3DSurface_UnlockRect(iface);
1799         IWineD3DSurface_UnlockRect(Source);
1800     }
1801
1802     return ret;
1803 }
1804
1805 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1806 {
1807     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1808
1809     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1810           This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1811
1812     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1813
1814     if (NULL == pRect)
1815     {
1816         pLockedRect->pBits = This->resource.allocatedMemory;
1817         This->lockedRect.left   = 0;
1818         This->lockedRect.top    = 0;
1819         This->lockedRect.right  = This->currentDesc.Width;
1820         This->lockedRect.bottom = This->currentDesc.Height;
1821
1822         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1823               &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1824               This->lockedRect.right, This->lockedRect.bottom);
1825     }
1826     else
1827     {
1828         const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1829
1830         TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1831               pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1832
1833         if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1834         {
1835             /* Compressed textures are block based, so calculate the offset of
1836              * the block that contains the top-left pixel of the locked rectangle. */
1837             pLockedRect->pBits = This->resource.allocatedMemory
1838                     + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1839                     + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1840         }
1841         else
1842         {
1843             pLockedRect->pBits = This->resource.allocatedMemory +
1844                     (pLockedRect->Pitch * pRect->top) +
1845                     (pRect->left * format_desc->byte_count);
1846         }
1847         This->lockedRect.left   = pRect->left;
1848         This->lockedRect.top    = pRect->top;
1849         This->lockedRect.right  = pRect->right;
1850         This->lockedRect.bottom = pRect->bottom;
1851     }
1852
1853     /* No dirtifying is needed for this surface implementation */
1854     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1855
1856     return WINED3D_OK;
1857 }
1858
1859 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1860     ERR("Should not be called on base texture\n");
1861     return;
1862 }
1863
1864 /* TODO: think about moving this down to resource? */
1865 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1866 {
1867     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1868
1869     /* This should only be called for sysmem textures, it may be a good idea
1870      * to extend this to all pools at some point in the future  */
1871     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1872     {
1873         FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1874     }
1875     return This->resource.allocatedMemory;
1876 }