push c6bab2db4fc296bd36abf8f7d9cf443d4a73048e
[wine/hacks.git] / dlls / wined3d / surface_base.c
blobd487f80e10a5534e060b2e611553941439a44740
1 /*
2 * IWineD3DSurface Implementation of management(non-rendering) functions
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
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.
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.
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
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 #include <assert.h>
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37 /* See also float_16_to_32() in wined3d_private.h */
38 static inline unsigned short float_32_to_16(const float *in)
40 int exp = 0;
41 float tmp = fabs(*in);
42 unsigned int mantissa;
43 unsigned short ret;
45 /* Deal with special numbers */
46 if(*in == 0.0) return 0x0000;
47 if(isnan(*in)) return 0x7C01;
48 if(isinf(*in)) return (*in < 0.0 ? 0xFC00 : 0x7c00);
50 if(tmp < pow(2, 10)) {
53 tmp = tmp * 2.0;
54 exp--;
55 }while(tmp < pow(2, 10));
56 } else if(tmp >= pow(2, 11)) {
59 tmp /= 2.0;
60 exp++;
61 }while(tmp >= pow(2, 11));
64 mantissa = (unsigned int) tmp;
65 if(tmp - mantissa >= 0.5) mantissa++; /* round to nearest, away from zero */
67 exp += 10; /* Normalize the mantissa */
68 exp += 15; /* Exponent is encoded with excess 15 */
70 if(exp > 30) { /* too big */
71 ret = 0x7c00; /* INF */
72 } else if(exp <= 0) {
73 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
74 while(exp <= 0) {
75 mantissa = mantissa >> 1;
76 exp++;
78 ret = mantissa & 0x3ff;
79 } else {
80 ret = (exp << 10) | (mantissa & 0x3ff);
83 ret |= ((*in < 0.0 ? 1 : 0) << 15); /* Add the sign */
84 return ret;
88 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
90 /* *******************************************
91 IWineD3DSurface IUnknown parts follow
92 ******************************************* */
93 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
95 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
96 /* Warn ,but be nice about things */
97 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
99 if (IsEqualGUID(riid, &IID_IUnknown)
100 || IsEqualGUID(riid, &IID_IWineD3DBase)
101 || IsEqualGUID(riid, &IID_IWineD3DResource)
102 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
103 IUnknown_AddRef((IUnknown*)iface);
104 *ppobj = This;
105 return S_OK;
107 *ppobj = NULL;
108 return E_NOINTERFACE;
111 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
112 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
113 ULONG ref = InterlockedIncrement(&This->resource.ref);
114 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
115 return ref;
118 /* ****************************************************
119 IWineD3DSurface IWineD3DResource parts follow
120 **************************************************** */
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
122 return resource_get_device((IWineD3DResource *)iface, ppDevice);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
126 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
129 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
130 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
133 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
134 return resource_free_private_data((IWineD3DResource *)iface, refguid);
137 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
138 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
141 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
142 return resource_get_priority((IWineD3DResource *)iface);
145 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
146 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
147 return resource_get_type((IWineD3DResource *)iface);
150 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
151 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
152 return resource_get_parent((IWineD3DResource *)iface, pParent);
155 /* ******************************************************
156 IWineD3DSurface IWineD3DSurface parts follow
157 ****************************************************** */
159 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
160 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
161 IWineD3DBase *container = 0;
163 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
165 if (!ppContainer) {
166 ERR("Called without a valid ppContainer.\n");
169 /* Standalone surfaces return the device as container. */
170 if (This->container) {
171 container = This->container;
172 } else {
173 container = (IWineD3DBase *)This->resource.wineD3DDevice;
176 TRACE("Relaying to QueryInterface\n");
177 return IUnknown_QueryInterface(container, riid, ppContainer);
180 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
181 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
183 TRACE("(%p) : copying into %p\n", This, pDesc);
184 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format_desc->format;
185 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
186 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
187 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
188 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
189 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
190 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
191 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
192 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
193 return WINED3D_OK;
196 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
197 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
198 TRACE("(%p)->(%x)\n", This, Flags);
200 switch (Flags)
202 case WINEDDGBS_CANBLT:
203 case WINEDDGBS_ISBLTDONE:
204 return WINED3D_OK;
206 default:
207 return WINED3DERR_INVALIDCALL;
211 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
212 /* XXX: DDERR_INVALIDSURFACETYPE */
214 TRACE("(%p)->(%08x)\n",iface,Flags);
215 switch (Flags) {
216 case WINEDDGFS_CANFLIP:
217 case WINEDDGFS_ISFLIPDONE:
218 return WINED3D_OK;
220 default:
221 return WINED3DERR_INVALIDCALL;
225 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
226 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
227 TRACE("(%p)\n", This);
229 /* D3D8 and 9 loose full devices, ddraw only surfaces */
230 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
234 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235 TRACE("(%p)\n", This);
237 /* So far we don't lose anything :) */
238 This->Flags &= ~SFLAG_LOST;
239 return WINED3D_OK;
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);
247 if(This->palette == PalImpl) {
248 TRACE("Nop palette change\n");
249 return WINED3D_OK;
252 if(This->palette != NULL)
253 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
254 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
256 This->palette = PalImpl;
258 if(PalImpl != NULL) {
259 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
260 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
263 return IWineD3DSurface_RealizePalette(iface);
265 else return WINED3D_OK;
268 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
270 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
271 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
273 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
274 FIXME(" colorkey value not supported (%08x) !\n", Flags);
275 return WINED3DERR_INVALIDCALL;
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;
286 case WINEDDCKEY_DESTOVERLAY:
287 This->DestOverlayCKey = *CKey;
288 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
289 break;
291 case WINEDDCKEY_SRCOVERLAY:
292 This->SrcOverlayCKey = *CKey;
293 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
294 break;
296 case WINEDDCKEY_SRCBLT:
297 This->SrcBltCKey = *CKey;
298 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
299 break;
302 else {
303 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
304 case WINEDDCKEY_DESTBLT:
305 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
306 break;
308 case WINEDDCKEY_DESTOVERLAY:
309 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
310 break;
312 case WINEDDCKEY_SRCOVERLAY:
313 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
314 break;
316 case WINEDDCKEY_SRCBLT:
317 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
318 break;
322 return WINED3D_OK;
325 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
326 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
327 TRACE("(%p)->(%p)\n", This, Pal);
329 *Pal = (IWineD3DPalette *) This->palette;
330 return WINED3D_OK;
333 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
334 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
335 WINED3DFORMAT format = This->resource.format_desc->format;
336 DWORD ret;
337 TRACE("(%p)\n", This);
339 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
340 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
341 ie pitch = (width/4) * bytes per block */
342 if (format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
343 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
344 else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
345 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
346 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
347 else {
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);
352 TRACE("(%p) Returning %d\n", This, ret);
353 return ret;
356 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
357 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
358 LONG w, h;
360 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
362 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
364 TRACE("(%p): Not an overlay surface\n", This);
365 return WINEDDERR_NOTAOVERLAYSURFACE;
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;
375 IWineD3DSurface_DrawOverlay(iface);
377 return WINED3D_OK;
380 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
381 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
382 HRESULT hr;
384 TRACE("(%p)->(%p,%p)\n", This, X, Y);
386 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
388 TRACE("(%p): Not an overlay surface\n", This);
389 return WINEDDERR_NOTAOVERLAYSURFACE;
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;
400 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
401 return hr;
404 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
406 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
408 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
410 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
412 TRACE("(%p): Not an overlay surface\n", This);
413 return WINEDDERR_NOTAOVERLAYSURFACE;
416 return WINED3D_OK;
419 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
420 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
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);
426 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
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;
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;
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;
453 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
454 list_remove(&This->overlay_entry);
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);
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;
471 IWineD3DSurface_DrawOverlay(iface);
473 return WINED3D_OK;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 This->clipper = clipper;
482 return WINED3D_OK;
485 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
487 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
488 TRACE("(%p)->(%p)\n", This, clipper);
490 *clipper = This->clipper;
491 if(*clipper) {
492 IWineD3DClipper_AddRef(*clipper);
494 return WINED3D_OK;
497 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
498 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
500 TRACE("This %p, container %p\n", This, container);
502 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
504 TRACE("Setting container to %p from %p\n", container, This->container);
505 This->container = container;
507 return WINED3D_OK;
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);
515 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
517 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
518 return WINED3DERR_INVALIDCALL;
521 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
522 if (format == WINED3DFMT_UNKNOWN) {
523 This->resource.size = 0;
524 } else if (format == WINED3DFMT_DXT1) {
525 /* DXT1 is half byte per pixel */
526 This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4)) >> 1;
528 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
529 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
530 This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4));
531 } else {
532 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
533 This->resource.size = ((This->pow2Width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1);
534 This->resource.size *= This->pow2Height;
537 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
539 This->resource.format_desc = format_desc;
541 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
543 return WINED3D_OK;
546 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
547 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
548 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
549 int extraline = 0;
550 SYSTEM_INFO sysInfo;
551 BITMAPINFO* b_info;
552 HDC ddc;
553 DWORD *masks;
554 UINT usage;
556 switch (format_desc->byte_count)
558 case 2:
559 case 4:
560 /* Allocate extra space to store the RGB bit masks. */
561 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
562 break;
564 case 3:
565 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
566 break;
568 default:
569 /* Allocate extra space for a palette. */
570 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
571 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
572 break;
575 if (!b_info)
576 return E_OUTOFMEMORY;
578 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
579 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
580 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
581 * add an extra line to the dib section
583 GetSystemInfo(&sysInfo);
584 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
585 extraline = 1;
586 TRACE("Adding an extra line to the dib section\n");
589 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
590 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
591 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
592 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
593 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
594 b_info->bmiHeader.biPlanes = 1;
595 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
597 b_info->bmiHeader.biXPelsPerMeter = 0;
598 b_info->bmiHeader.biYPelsPerMeter = 0;
599 b_info->bmiHeader.biClrUsed = 0;
600 b_info->bmiHeader.biClrImportant = 0;
602 /* Get the bit masks */
603 masks = (DWORD *)b_info->bmiColors;
604 switch (This->resource.format_desc->format)
606 case WINED3DFMT_R8G8B8:
607 usage = DIB_RGB_COLORS;
608 b_info->bmiHeader.biCompression = BI_RGB;
609 break;
611 case WINED3DFMT_X1R5G5B5:
612 case WINED3DFMT_A1R5G5B5:
613 case WINED3DFMT_A4R4G4B4:
614 case WINED3DFMT_X4R4G4B4:
615 case WINED3DFMT_R3G3B2:
616 case WINED3DFMT_A8R3G3B2:
617 case WINED3DFMT_R10G10B10A2_UNORM:
618 case WINED3DFMT_R8G8B8A8_UNORM:
619 case WINED3DFMT_X8B8G8R8:
620 case WINED3DFMT_A2R10G10B10:
621 case WINED3DFMT_R5G6B5:
622 case WINED3DFMT_R16G16B16A16_UNORM:
623 usage = 0;
624 b_info->bmiHeader.biCompression = BI_BITFIELDS;
625 masks[0] = format_desc->red_mask;
626 masks[1] = format_desc->green_mask;
627 masks[2] = format_desc->blue_mask;
628 break;
630 default:
631 /* Don't know palette */
632 b_info->bmiHeader.biCompression = BI_RGB;
633 usage = 0;
634 break;
637 ddc = GetDC(0);
638 if (ddc == 0) {
639 HeapFree(GetProcessHeap(), 0, b_info);
640 return HRESULT_FROM_WIN32(GetLastError());
643 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);
644 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
645 ReleaseDC(0, ddc);
647 if (!This->dib.DIBsection) {
648 ERR("CreateDIBSection failed!\n");
649 HeapFree(GetProcessHeap(), 0, b_info);
650 return HRESULT_FROM_WIN32(GetLastError());
653 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
654 /* copy the existing surface to the dib section */
655 if(This->resource.allocatedMemory) {
656 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
657 } else {
658 /* This is to make LockRect read the gl Texture although memory is allocated */
659 This->Flags &= ~SFLAG_INSYSMEM;
661 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
663 HeapFree(GetProcessHeap(), 0, b_info);
665 /* Now allocate a HDC */
666 This->hDC = CreateCompatibleDC(0);
667 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
668 TRACE("using wined3d palette %p\n", This->palette);
669 SelectPalette(This->hDC,
670 This->palette ? This->palette->hpal : 0,
671 FALSE);
673 This->Flags |= SFLAG_DIBSECTION;
675 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
676 This->resource.heapMemory = NULL;
678 return WINED3D_OK;
681 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
682 unsigned int w, unsigned int h)
684 unsigned int x, y;
685 const float *src_f;
686 unsigned short *dst_s;
688 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
689 for(y = 0; y < h; y++) {
690 src_f = (const float *)(src + y * pitch_in);
691 dst_s = (unsigned short *) (dst + y * pitch_out);
692 for(x = 0; x < w; x++) {
693 dst_s[x] = float_32_to_16(src_f + x);
698 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
699 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
701 static const unsigned char convert_5to8[] =
703 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
704 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
705 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
706 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
708 static const unsigned char convert_6to8[] =
710 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
711 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
712 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
713 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
714 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
715 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
716 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
717 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
719 unsigned int x, y;
721 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
723 for (y = 0; y < h; ++y)
725 const WORD *src_line = (const WORD *)(src + y * pitch_in);
726 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
727 for (x = 0; x < w; ++x)
729 WORD pixel = src_line[x];
730 dst_line[x] = 0xff000000
731 | convert_5to8[(pixel & 0xf800) >> 11] << 16
732 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
733 | convert_5to8[(pixel & 0x001f)];
738 struct d3dfmt_convertor_desc {
739 WINED3DFORMAT from, to;
740 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
743 static const struct d3dfmt_convertor_desc convertors[] =
745 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
746 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
749 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
751 unsigned int i;
752 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
753 if(convertors[i].from == from && convertors[i].to == to) {
754 return &convertors[i];
757 return NULL;
760 /*****************************************************************************
761 * surface_convert_format
763 * Creates a duplicate of a surface in a different format. Is used by Blt to
764 * blit between surfaces with different formats
766 * Parameters
767 * source: Source surface
768 * fmt: Requested destination format
770 *****************************************************************************/
771 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
772 IWineD3DSurface *ret = NULL;
773 const struct d3dfmt_convertor_desc *conv;
774 WINED3DLOCKED_RECT lock_src, lock_dst;
775 HRESULT hr;
777 conv = find_convertor(source->resource.format_desc->format, to_fmt);
778 if(!conv) {
779 FIXME("Cannot find a conversion function from format %s to %s\n",
780 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
781 return NULL;
784 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice,
785 source->currentDesc.Width, source->currentDesc.Height, to_fmt, TRUE /* lockable */,
786 TRUE /* discard */, 0 /* level */, &ret, WINED3DRTYPE_SURFACE, 0 /* usage */,
787 WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
788 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
789 if(!ret) {
790 ERR("Failed to create a destination surface for conversion\n");
791 return NULL;
794 memset(&lock_src, 0, sizeof(lock_src));
795 memset(&lock_dst, 0, sizeof(lock_dst));
797 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
798 if(FAILED(hr)) {
799 ERR("Failed to lock the source surface\n");
800 IWineD3DSurface_Release(ret);
801 return NULL;
803 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
804 if(FAILED(hr)) {
805 ERR("Failed to lock the dest surface\n");
806 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
807 IWineD3DSurface_Release(ret);
808 return NULL;
811 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
812 source->currentDesc.Width, source->currentDesc.Height);
814 IWineD3DSurface_UnlockRect(ret);
815 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
817 return (IWineD3DSurfaceImpl *) ret;
820 /*****************************************************************************
821 * _Blt_ColorFill
823 * Helper function that fills a memory area with a specific color
825 * Params:
826 * buf: memory address to start filling at
827 * width, height: Dimensions of the area to fill
828 * bpp: Bit depth of the surface
829 * lPitch: pitch of the surface
830 * color: Color to fill with
832 *****************************************************************************/
833 static HRESULT
834 _Blt_ColorFill(BYTE *buf,
835 int width, int height,
836 int bpp, LONG lPitch,
837 DWORD color)
839 int x, y;
840 LPBYTE first;
842 /* Do first row */
844 #define COLORFILL_ROW(type) \
846 type *d = (type *) buf; \
847 for (x = 0; x < width; x++) \
848 d[x] = (type) color; \
849 break; \
851 switch(bpp)
853 case 1: COLORFILL_ROW(BYTE)
854 case 2: COLORFILL_ROW(WORD)
855 case 3:
857 BYTE *d = buf;
858 for (x = 0; x < width; x++,d+=3)
860 d[0] = (color ) & 0xFF;
861 d[1] = (color>> 8) & 0xFF;
862 d[2] = (color>>16) & 0xFF;
864 break;
866 case 4: COLORFILL_ROW(DWORD)
867 default:
868 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
869 return WINED3DERR_NOTAVAILABLE;
872 #undef COLORFILL_ROW
874 /* Now copy first row */
875 first = buf;
876 for (y = 1; y < height; y++)
878 buf += lPitch;
879 memcpy(buf, first, width * bpp);
881 return WINED3D_OK;
884 /*****************************************************************************
885 * IWineD3DSurface::Blt, SW emulation version
887 * Performs blits to a surface, eigher from a source of source-less blts
888 * This is the main functionality of DirectDraw
890 * Params:
891 * DestRect: Destination rectangle to write to
892 * SrcSurface: Source surface, can be NULL
893 * SrcRect: Source rectangle
894 *****************************************************************************/
895 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
896 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
898 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
899 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
900 RECT xdst,xsrc;
901 HRESULT ret = WINED3D_OK;
902 WINED3DLOCKED_RECT dlock, slock;
903 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
904 const struct GlPixelFormatDesc *sEntry, *dEntry;
905 int x, y;
906 const BYTE *sbuf;
907 BYTE *dbuf;
908 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
910 if (TRACE_ON(d3d_surface))
912 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
913 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
914 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
915 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
916 #if 0
917 TRACE("\tflags: ");
918 DDRAW_dump_DDBLT(Flags);
919 if (Flags & WINEDDBLT_DDFX)
921 TRACE("\tblitfx: ");
922 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
924 #endif
927 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
929 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
930 return WINEDDERR_SURFACEBUSY;
933 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
934 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
935 FIXME("Filters not supported in software blit\n");
938 /* First check for the validity of source / destination rectangles. This was
939 * verified using a test application + by MSDN.
941 if ((Src != NULL) && (SrcRect != NULL) &&
942 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
943 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
944 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
945 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
946 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
948 WARN("Application gave us bad source rectangle for Blt.\n");
949 return WINEDDERR_INVALIDRECT;
951 /* For the Destination rect, it can be out of bounds on the condition that a clipper
952 * is set for the given surface.
954 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
955 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
956 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
957 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
958 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
959 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
961 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
962 return WINEDDERR_INVALIDRECT;
965 /* Now handle negative values in the rectangles. Warning: only supported for now
966 in the 'simple' cases (ie not in any stretching / rotation cases).
968 First, the case where nothing is to be done.
970 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
971 (DestRect->top >= (int) This->currentDesc.Height) ||
972 (DestRect->left >= (int) This->currentDesc.Width))) ||
973 ((Src != NULL) && (SrcRect != NULL) &&
974 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
975 (SrcRect->top >= (int) Src->currentDesc.Height) ||
976 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
978 TRACE("Nothing to be done !\n");
979 return WINED3D_OK;
982 if (DestRect)
984 xdst = *DestRect;
986 else
988 xdst.top = 0;
989 xdst.bottom = This->currentDesc.Height;
990 xdst.left = 0;
991 xdst.right = This->currentDesc.Width;
994 if (SrcRect)
996 xsrc = *SrcRect;
998 else
1000 if (Src)
1002 xsrc.top = 0;
1003 xsrc.bottom = Src->currentDesc.Height;
1004 xsrc.left = 0;
1005 xsrc.right = Src->currentDesc.Width;
1007 else
1009 memset(&xsrc,0,sizeof(xsrc));
1013 /* The easy case : the source-less blits.... */
1014 if (Src == NULL && DestRect)
1016 RECT full_rect;
1017 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1019 full_rect.left = 0;
1020 full_rect.top = 0;
1021 full_rect.right = This->currentDesc.Width;
1022 full_rect.bottom = This->currentDesc.Height;
1023 IntersectRect(&temp_rect, &full_rect, DestRect);
1024 xdst = temp_rect;
1026 else if (DestRect)
1028 /* Only handle clipping on the destination rectangle */
1029 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1030 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1031 if (clip_vert || clip_horiz)
1033 /* Now check if this is a special case or not... */
1034 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1035 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1036 (Flags & WINEDDBLT_DDFX))
1038 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1039 return WINED3D_OK;
1042 if (clip_horiz)
1044 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1045 if (DestRect->right > This->currentDesc.Width)
1047 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1048 xdst.right = (int) This->currentDesc.Width;
1051 if (clip_vert)
1053 if (DestRect->top < 0)
1055 xsrc.top -= DestRect->top;
1056 xdst.top = 0;
1058 if (DestRect->bottom > This->currentDesc.Height)
1060 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1061 xdst.bottom = (int) This->currentDesc.Height;
1064 /* And check if after clipping something is still to be done... */
1065 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1066 (xdst.top >= (int) This->currentDesc.Height) ||
1067 (xdst.left >= (int) This->currentDesc.Width) ||
1068 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1069 (xsrc.top >= (int) Src->currentDesc.Height) ||
1070 (xsrc.left >= (int) Src->currentDesc.Width))
1072 TRACE("Nothing to be done after clipping !\n");
1073 return WINED3D_OK;
1078 if (Src == This)
1080 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1081 slock = dlock;
1082 sEntry = This->resource.format_desc;
1083 dEntry = sEntry;
1085 else
1087 dEntry = This->resource.format_desc;
1088 if (Src)
1090 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1092 Src = surface_convert_format(Src, dEntry->format);
1093 if(!Src) {
1094 /* The conv function writes a FIXME */
1095 WARN("Cannot convert source surface format to dest format\n");
1096 goto release;
1099 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1100 sEntry = Src->resource.format_desc;
1102 else
1104 sEntry = dEntry;
1106 if (DestRect)
1107 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1108 else
1109 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1112 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1114 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1116 if (!DestRect || Src == This)
1118 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1119 goto release;
1123 bpp = This->resource.format_desc->byte_count;
1124 srcheight = xsrc.bottom - xsrc.top;
1125 srcwidth = xsrc.right - xsrc.left;
1126 dstheight = xdst.bottom - xdst.top;
1127 dstwidth = xdst.right - xdst.left;
1128 width = (xdst.right - xdst.left) * bpp;
1130 assert(width <= dlock.Pitch);
1132 if (DestRect && Src != This)
1133 dbuf = dlock.pBits;
1134 else
1135 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1137 if (Flags & WINEDDBLT_WAIT)
1139 Flags &= ~WINEDDBLT_WAIT;
1141 if (Flags & WINEDDBLT_ASYNC)
1143 static BOOL displayed = FALSE;
1144 if (!displayed)
1145 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1146 displayed = TRUE;
1147 Flags &= ~WINEDDBLT_ASYNC;
1149 if (Flags & WINEDDBLT_DONOTWAIT)
1151 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1152 static BOOL displayed = FALSE;
1153 if (!displayed)
1154 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1155 displayed = TRUE;
1156 Flags &= ~WINEDDBLT_DONOTWAIT;
1159 /* First, all the 'source-less' blits */
1160 if (Flags & WINEDDBLT_COLORFILL)
1162 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1163 dlock.Pitch, DDBltFx->u5.dwFillColor);
1164 Flags &= ~WINEDDBLT_COLORFILL;
1167 if (Flags & WINEDDBLT_DEPTHFILL)
1169 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1171 if (Flags & WINEDDBLT_ROP)
1173 /* Catch some degenerate cases here */
1174 switch(DDBltFx->dwROP)
1176 case BLACKNESS:
1177 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1178 break;
1179 case 0xAA0029: /* No-op */
1180 break;
1181 case WHITENESS:
1182 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1183 break;
1184 case SRCCOPY: /* well, we do that below ? */
1185 break;
1186 default:
1187 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1188 goto error;
1190 Flags &= ~WINEDDBLT_ROP;
1192 if (Flags & WINEDDBLT_DDROPS)
1194 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1196 /* Now the 'with source' blits */
1197 if (Src)
1199 const BYTE *sbase;
1200 int sx, xinc, sy, yinc;
1202 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1203 goto release;
1204 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1205 xinc = (srcwidth << 16) / dstwidth;
1206 yinc = (srcheight << 16) / dstheight;
1208 if (!Flags)
1210 /* No effects, we can cheat here */
1211 if (dstwidth == srcwidth)
1213 if (dstheight == srcheight)
1215 /* No stretching in either direction. This needs to be as
1216 * fast as possible */
1217 sbuf = sbase;
1219 /* check for overlapping surfaces */
1220 if (Src != This || xdst.top < xsrc.top ||
1221 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1223 /* no overlap, or dst above src, so copy from top downwards */
1224 for (y = 0; y < dstheight; y++)
1226 memcpy(dbuf, sbuf, width);
1227 sbuf += slock.Pitch;
1228 dbuf += dlock.Pitch;
1231 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1233 sbuf += (slock.Pitch*dstheight);
1234 dbuf += (dlock.Pitch*dstheight);
1235 for (y = 0; y < dstheight; y++)
1237 sbuf -= slock.Pitch;
1238 dbuf -= dlock.Pitch;
1239 memcpy(dbuf, sbuf, width);
1242 else /* src and dst overlapping on the same line, use memmove */
1244 for (y = 0; y < dstheight; y++)
1246 memmove(dbuf, sbuf, width);
1247 sbuf += slock.Pitch;
1248 dbuf += dlock.Pitch;
1251 } else {
1252 /* Stretching in Y direction only */
1253 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1254 sbuf = sbase + (sy >> 16) * slock.Pitch;
1255 memcpy(dbuf, sbuf, width);
1256 dbuf += dlock.Pitch;
1260 else
1262 /* Stretching in X direction */
1263 int last_sy = -1;
1264 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1266 sbuf = sbase + (sy >> 16) * slock.Pitch;
1268 if ((sy >> 16) == (last_sy >> 16))
1270 /* this sourcerow is the same as last sourcerow -
1271 * copy already stretched row
1273 memcpy(dbuf, dbuf - dlock.Pitch, width);
1275 else
1277 #define STRETCH_ROW(type) { \
1278 const type *s = (const type *)sbuf; \
1279 type *d = (type *)dbuf; \
1280 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1281 d[x] = s[sx >> 16]; \
1282 break; }
1284 switch(bpp)
1286 case 1: STRETCH_ROW(BYTE)
1287 case 2: STRETCH_ROW(WORD)
1288 case 4: STRETCH_ROW(DWORD)
1289 case 3:
1291 const BYTE *s;
1292 BYTE *d = dbuf;
1293 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1295 DWORD pixel;
1297 s = sbuf+3*(sx>>16);
1298 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1299 d[0] = (pixel )&0xff;
1300 d[1] = (pixel>> 8)&0xff;
1301 d[2] = (pixel>>16)&0xff;
1302 d+=3;
1304 break;
1306 default:
1307 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1308 ret = WINED3DERR_NOTAVAILABLE;
1309 goto error;
1311 #undef STRETCH_ROW
1313 dbuf += dlock.Pitch;
1314 last_sy = sy;
1318 else
1320 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1321 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1322 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1323 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1325 /* The color keying flags are checked for correctness in ddraw */
1326 if (Flags & WINEDDBLT_KEYSRC)
1328 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1329 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1331 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1333 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1334 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1337 if (Flags & WINEDDBLT_KEYDEST)
1339 /* Destination color keys are taken from the source surface ! */
1340 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1341 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1343 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1345 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1346 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1349 if(bpp == 1)
1351 keymask = 0xff;
1353 else
1355 keymask = sEntry->red_mask
1356 | sEntry->green_mask
1357 | sEntry->blue_mask;
1359 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1362 if (Flags & WINEDDBLT_DDFX)
1364 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1365 LONG tmpxy;
1366 dTopLeft = dbuf;
1367 dTopRight = dbuf+((dstwidth-1)*bpp);
1368 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1369 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1371 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1373 /* I don't think we need to do anything about this flag */
1374 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1376 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1378 tmp = dTopRight;
1379 dTopRight = dTopLeft;
1380 dTopLeft = tmp;
1381 tmp = dBottomRight;
1382 dBottomRight = dBottomLeft;
1383 dBottomLeft = tmp;
1384 dstxinc = dstxinc *-1;
1386 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1388 tmp = dTopLeft;
1389 dTopLeft = dBottomLeft;
1390 dBottomLeft = tmp;
1391 tmp = dTopRight;
1392 dTopRight = dBottomRight;
1393 dBottomRight = tmp;
1394 dstyinc = dstyinc *-1;
1396 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1398 /* I don't think we need to do anything about this flag */
1399 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1401 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1403 tmp = dBottomRight;
1404 dBottomRight = dTopLeft;
1405 dTopLeft = tmp;
1406 tmp = dBottomLeft;
1407 dBottomLeft = dTopRight;
1408 dTopRight = tmp;
1409 dstxinc = dstxinc * -1;
1410 dstyinc = dstyinc * -1;
1412 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1414 tmp = dTopLeft;
1415 dTopLeft = dBottomLeft;
1416 dBottomLeft = dBottomRight;
1417 dBottomRight = dTopRight;
1418 dTopRight = tmp;
1419 tmpxy = dstxinc;
1420 dstxinc = dstyinc;
1421 dstyinc = tmpxy;
1422 dstxinc = dstxinc * -1;
1424 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1426 tmp = dTopLeft;
1427 dTopLeft = dTopRight;
1428 dTopRight = dBottomRight;
1429 dBottomRight = dBottomLeft;
1430 dBottomLeft = tmp;
1431 tmpxy = dstxinc;
1432 dstxinc = dstyinc;
1433 dstyinc = tmpxy;
1434 dstyinc = dstyinc * -1;
1436 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1438 /* I don't think we need to do anything about this flag */
1439 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1441 dbuf = dTopLeft;
1442 Flags &= ~(WINEDDBLT_DDFX);
1445 #define COPY_COLORKEY_FX(type) { \
1446 const type *s; \
1447 type *d = (type *)dbuf, *dx, tmp; \
1448 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1449 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1450 dx = d; \
1451 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1452 tmp = s[sx >> 16]; \
1453 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1454 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1455 dx[0] = tmp; \
1457 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1459 d = (type*)(((LPBYTE)d)+dstyinc); \
1461 break; }
1463 switch (bpp) {
1464 case 1: COPY_COLORKEY_FX(BYTE)
1465 case 2: COPY_COLORKEY_FX(WORD)
1466 case 4: COPY_COLORKEY_FX(DWORD)
1467 case 3:
1469 const BYTE *s;
1470 BYTE *d = dbuf, *dx;
1471 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1473 sbuf = sbase + (sy >> 16) * slock.Pitch;
1474 dx = d;
1475 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1477 DWORD pixel, dpixel = 0;
1478 s = sbuf+3*(sx>>16);
1479 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1480 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1481 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1482 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1484 dx[0] = (pixel )&0xff;
1485 dx[1] = (pixel>> 8)&0xff;
1486 dx[2] = (pixel>>16)&0xff;
1488 dx+= dstxinc;
1490 d += dstyinc;
1492 break;
1494 default:
1495 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1496 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1497 ret = WINED3DERR_NOTAVAILABLE;
1498 goto error;
1499 #undef COPY_COLORKEY_FX
1504 error:
1505 if (Flags && FIXME_ON(d3d_surface))
1507 FIXME("\tUnsupported flags: %08x\n", Flags);
1510 release:
1511 IWineD3DSurface_UnlockRect(iface);
1512 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1513 /* Release the converted surface if any */
1514 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1515 return ret;
1518 /*****************************************************************************
1519 * IWineD3DSurface::BltFast, SW emulation version
1521 * This is the software implementation of BltFast, as used by GDI surfaces
1522 * and as a fallback for OpenGL surfaces. This code is taken from the old
1523 * DirectDraw code, and was originally written by TransGaming.
1525 * Params:
1526 * dstx:
1527 * dsty:
1528 * Source: Source surface to copy from
1529 * rsrc: Source rectangle
1530 * trans: Some Flags
1532 * Returns:
1533 * WINED3D_OK on success
1535 *****************************************************************************/
1536 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1537 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1539 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1540 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1542 int bpp, w, h, x, y;
1543 WINED3DLOCKED_RECT dlock,slock;
1544 HRESULT ret = WINED3D_OK;
1545 RECT rsrc2;
1546 RECT lock_src, lock_dst, lock_union;
1547 const BYTE *sbuf;
1548 BYTE *dbuf;
1549 const struct GlPixelFormatDesc *sEntry, *dEntry;
1551 if (TRACE_ON(d3d_surface))
1553 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1555 if (rsrc)
1557 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1558 rsrc->right,rsrc->bottom);
1560 else
1562 TRACE(" srcrect: NULL\n");
1566 if ((This->Flags & SFLAG_LOCKED) ||
1567 (Src->Flags & SFLAG_LOCKED))
1569 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1570 return WINEDDERR_SURFACEBUSY;
1573 if (!rsrc)
1575 WARN("rsrc is NULL!\n");
1576 rsrc2.left = 0;
1577 rsrc2.top = 0;
1578 rsrc2.right = Src->currentDesc.Width;
1579 rsrc2.bottom = Src->currentDesc.Height;
1580 rsrc = &rsrc2;
1583 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1584 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1585 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1586 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1587 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1588 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1590 WARN("Application gave us bad source rectangle for BltFast.\n");
1591 return WINEDDERR_INVALIDRECT;
1594 h = rsrc->bottom - rsrc->top;
1595 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1596 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1597 if (h <= 0) return WINEDDERR_INVALIDRECT;
1599 w = rsrc->right - rsrc->left;
1600 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1601 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1602 if (w <= 0) return WINEDDERR_INVALIDRECT;
1604 /* Now compute the locking rectangle... */
1605 lock_src.left = rsrc->left;
1606 lock_src.top = rsrc->top;
1607 lock_src.right = lock_src.left + w;
1608 lock_src.bottom = lock_src.top + h;
1610 lock_dst.left = dstx;
1611 lock_dst.top = dsty;
1612 lock_dst.right = dstx + w;
1613 lock_dst.bottom = dsty + h;
1615 bpp = This->resource.format_desc->byte_count;
1617 /* We need to lock the surfaces, or we won't get refreshes when done. */
1618 if (Src == This)
1620 int pitch;
1622 UnionRect(&lock_union, &lock_src, &lock_dst);
1624 /* Lock the union of the two rectangles */
1625 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1626 if(ret != WINED3D_OK) goto error;
1628 pitch = dlock.Pitch;
1629 slock.Pitch = dlock.Pitch;
1631 /* Since slock was originally copied from this surface's description, we can just reuse it */
1632 assert(This->resource.allocatedMemory != NULL);
1633 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1634 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1635 sEntry = Src->resource.format_desc;
1636 dEntry = sEntry;
1638 else
1640 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1641 if(ret != WINED3D_OK) goto error;
1642 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1643 if(ret != WINED3D_OK) goto error;
1645 sbuf = slock.pBits;
1646 dbuf = dlock.pBits;
1647 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1649 sEntry = Src->resource.format_desc;
1650 dEntry = This->resource.format_desc;
1653 /* Handle first the FOURCC surfaces... */
1654 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1656 UINT block_width;
1657 UINT block_height;
1658 UINT block_byte_size;
1660 TRACE("Fourcc -> Fourcc copy\n");
1661 if (trans)
1662 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1663 if (dstx || dsty)
1664 FIXME("offset for destination surface is not supported\n");
1665 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1667 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1668 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1669 goto error;
1672 if (This->resource.format_desc->format == WINED3DFMT_DXT1)
1674 block_width = 4;
1675 block_height = 4;
1676 block_byte_size = 8;
1678 else if (This->resource.format_desc->format == WINED3DFMT_DXT2
1679 || This->resource.format_desc->format == WINED3DFMT_DXT3
1680 || This->resource.format_desc->format == WINED3DFMT_DXT4
1681 || This->resource.format_desc->format == WINED3DFMT_DXT5)
1683 block_width = 4;
1684 block_height = 4;
1685 block_byte_size = 16;
1687 else
1689 FIXME("Unsupported FourCC format %s.\n", debug_d3dformat(This->resource.format_desc->format));
1690 block_width = 1;
1691 block_height = 1;
1692 block_byte_size = This->resource.format_desc->byte_count;
1695 for (y = 0; y < h; y += block_height)
1697 memcpy(dbuf, sbuf, (w / block_width) * block_byte_size);
1698 dbuf += dlock.Pitch;
1699 sbuf += slock.Pitch;
1702 goto error;
1704 if ((sEntry->Flags & WINED3DFMT_FLAG_FOURCC) && !(dEntry->Flags & WINED3DFMT_FLAG_FOURCC))
1706 /* TODO: Use the libtxc_dxtn.so shared library to do
1707 * software decompression
1709 ERR("DXTC decompression not supported by now\n");
1710 goto error;
1713 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1715 DWORD keylow, keyhigh;
1716 TRACE("Color keyed copy\n");
1717 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1719 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1720 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1722 else
1724 /* I'm not sure if this is correct */
1725 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1726 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1727 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1730 #define COPYBOX_COLORKEY(type) { \
1731 const type *s = (const type *)sbuf; \
1732 type *d = (type *)dbuf; \
1733 type tmp; \
1734 for (y = 0; y < h; y++) { \
1735 for (x = 0; x < w; x++) { \
1736 tmp = s[x]; \
1737 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1739 s = (const type *)((const BYTE *)s + slock.Pitch); \
1740 d = (type *)((BYTE *)d + dlock.Pitch); \
1742 break; \
1745 switch (bpp) {
1746 case 1: COPYBOX_COLORKEY(BYTE)
1747 case 2: COPYBOX_COLORKEY(WORD)
1748 case 4: COPYBOX_COLORKEY(DWORD)
1749 case 3:
1751 const BYTE *s;
1752 BYTE *d;
1753 DWORD tmp;
1754 s = sbuf;
1755 d = dbuf;
1756 for (y = 0; y < h; y++)
1758 for (x = 0; x < w * 3; x += 3)
1760 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1761 if (tmp < keylow || tmp > keyhigh)
1763 d[x + 0] = s[x + 0];
1764 d[x + 1] = s[x + 1];
1765 d[x + 2] = s[x + 2];
1768 s += slock.Pitch;
1769 d += dlock.Pitch;
1771 break;
1773 default:
1774 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1775 ret = WINED3DERR_NOTAVAILABLE;
1776 goto error;
1778 #undef COPYBOX_COLORKEY
1779 TRACE("Copy Done\n");
1781 else
1783 int width = w * bpp;
1784 INT sbufpitch, dbufpitch;
1786 TRACE("NO color key copy\n");
1787 /* Handle overlapping surfaces */
1788 if (sbuf < dbuf)
1790 sbuf += (h - 1) * slock.Pitch;
1791 dbuf += (h - 1) * dlock.Pitch;
1792 sbufpitch = -slock.Pitch;
1793 dbufpitch = -dlock.Pitch;
1795 else
1797 sbufpitch = slock.Pitch;
1798 dbufpitch = dlock.Pitch;
1800 for (y = 0; y < h; y++)
1802 /* This is pretty easy, a line for line memcpy */
1803 memmove(dbuf, sbuf, width);
1804 sbuf += sbufpitch;
1805 dbuf += dbufpitch;
1807 TRACE("Copy done\n");
1810 error:
1811 if (Src == This)
1813 IWineD3DSurface_UnlockRect(iface);
1815 else
1817 IWineD3DSurface_UnlockRect(iface);
1818 IWineD3DSurface_UnlockRect(Source);
1821 return ret;
1824 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1826 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1828 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1829 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1831 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1833 if (NULL == pRect)
1835 pLockedRect->pBits = This->resource.allocatedMemory;
1836 This->lockedRect.left = 0;
1837 This->lockedRect.top = 0;
1838 This->lockedRect.right = This->currentDesc.Width;
1839 This->lockedRect.bottom = This->currentDesc.Height;
1841 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1842 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1843 This->lockedRect.right, This->lockedRect.bottom);
1845 else
1847 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1848 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1850 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1851 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1852 * slightly different meaning compared to regular textures. For DXTn
1853 * textures Pitch is the size of a row of blocks, 4 high and "width"
1854 * long. The x offset is calculated differently as well, since moving 4
1855 * pixels to the right actually moves an entire 4x4 block to right, ie
1856 * 16 bytes (8 in case of DXT1). */
1857 if (This->resource.format_desc->format == WINED3DFMT_DXT1)
1859 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1861 else if (This->resource.format_desc->format == WINED3DFMT_DXT2
1862 || This->resource.format_desc->format == WINED3DFMT_DXT3
1863 || This->resource.format_desc->format == WINED3DFMT_DXT4
1864 || This->resource.format_desc->format == WINED3DFMT_DXT5)
1866 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1868 else
1870 pLockedRect->pBits = This->resource.allocatedMemory +
1871 (pLockedRect->Pitch * pRect->top) +
1872 (pRect->left * This->resource.format_desc->byte_count);
1874 This->lockedRect.left = pRect->left;
1875 This->lockedRect.top = pRect->top;
1876 This->lockedRect.right = pRect->right;
1877 This->lockedRect.bottom = pRect->bottom;
1880 /* No dirtifying is needed for this surface implementation */
1881 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1883 return WINED3D_OK;
1886 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1887 ERR("Should not be called on base texture\n");
1888 return;
1891 /* TODO: think about moving this down to resource? */
1892 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1894 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1896 /* This should only be called for sysmem textures, it may be a good idea
1897 * to extend this to all pools at some point in the future */
1898 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1900 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1902 return This->resource.allocatedMemory;