push c6fcfc519a04d046be60ec60e33d075a2146cc03
[wine/hacks.git] / dlls / wined3d / surface_base.c
blob70dee04c21b4ab012c2f6554d3086b3f95f50bec
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;
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 DWORD ret;
336 TRACE("(%p)\n", This);
338 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
339 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
340 ie pitch = (width/4) * bytes per block */
341 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
342 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
343 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
344 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
345 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
346 else {
347 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
348 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
349 ret = (ret + alignment - 1) & ~(alignment - 1);
351 TRACE("(%p) Returning %d\n", This, ret);
352 return ret;
355 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
356 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
357 LONG w, h;
359 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
361 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
363 TRACE("(%p): Not an overlay surface\n", This);
364 return WINEDDERR_NOTAOVERLAYSURFACE;
367 w = This->overlay_destrect.right - This->overlay_destrect.left;
368 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
369 This->overlay_destrect.left = X;
370 This->overlay_destrect.top = Y;
371 This->overlay_destrect.right = X + w;
372 This->overlay_destrect.bottom = Y + h;
374 IWineD3DSurface_DrawOverlay(iface);
376 return WINED3D_OK;
379 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
380 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
381 HRESULT hr;
383 TRACE("(%p)->(%p,%p)\n", This, X, Y);
385 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
387 TRACE("(%p): Not an overlay surface\n", This);
388 return WINEDDERR_NOTAOVERLAYSURFACE;
390 if(This->overlay_dest == NULL) {
391 *X = 0; *Y = 0;
392 hr = WINEDDERR_OVERLAYNOTVISIBLE;
393 } else {
394 *X = This->overlay_destrect.left;
395 *Y = This->overlay_destrect.top;
396 hr = WINED3D_OK;
399 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
400 return hr;
403 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
404 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
405 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
407 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
409 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
411 TRACE("(%p): Not an overlay surface\n", This);
412 return WINEDDERR_NOTAOVERLAYSURFACE;
415 return WINED3D_OK;
418 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
419 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
421 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
422 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
423 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
425 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
427 WARN("(%p): Not an overlay surface\n", This);
428 return WINEDDERR_NOTAOVERLAYSURFACE;
429 } else if(!DstSurface) {
430 WARN("(%p): Dest surface is NULL\n", This);
431 return WINED3DERR_INVALIDCALL;
434 if(SrcRect) {
435 This->overlay_srcrect = *SrcRect;
436 } else {
437 This->overlay_srcrect.left = 0;
438 This->overlay_srcrect.top = 0;
439 This->overlay_srcrect.right = This->currentDesc.Width;
440 This->overlay_srcrect.bottom = This->currentDesc.Height;
443 if(DstRect) {
444 This->overlay_destrect = *DstRect;
445 } else {
446 This->overlay_destrect.left = 0;
447 This->overlay_destrect.top = 0;
448 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
449 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
452 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
453 list_remove(&This->overlay_entry);
456 if(Flags & WINEDDOVER_SHOW) {
457 if(This->overlay_dest != Dst) {
458 This->overlay_dest = Dst;
459 list_add_tail(&Dst->overlays, &This->overlay_entry);
461 } else if(Flags & WINEDDOVER_HIDE) {
462 /* tests show that the rectangles are erased on hide */
463 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
464 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
465 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
466 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
467 This->overlay_dest = NULL;
470 IWineD3DSurface_DrawOverlay(iface);
472 return WINED3D_OK;
475 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
477 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
478 TRACE("(%p)->(%p)\n", This, clipper);
480 This->clipper = clipper;
481 return WINED3D_OK;
484 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
486 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
487 TRACE("(%p)->(%p)\n", This, clipper);
489 *clipper = This->clipper;
490 if(*clipper) {
491 IWineD3DClipper_AddRef(*clipper);
493 return WINED3D_OK;
496 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
497 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
499 TRACE("This %p, container %p\n", This, container);
501 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
503 TRACE("Setting container to %p from %p\n", container, This->container);
504 This->container = container;
506 return WINED3D_OK;
509 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
510 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
511 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(format, NULL, NULL);
513 if (This->resource.format != WINED3DFMT_UNKNOWN) {
514 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
515 return WINED3DERR_INVALIDCALL;
518 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
519 if (format == WINED3DFMT_UNKNOWN) {
520 This->resource.size = 0;
521 } else if (format == WINED3DFMT_DXT1) {
522 /* DXT1 is half byte per pixel */
523 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
525 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
526 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
527 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
528 } else {
529 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
530 This->resource.size = ((This->pow2Width * formatEntry->bpp) + alignment - 1) & ~(alignment - 1);
531 This->resource.size *= This->pow2Height;
534 if (format != WINED3DFMT_UNKNOWN) {
535 This->bytesPerPixel = formatEntry->bpp;
536 } else {
537 This->bytesPerPixel = 0;
540 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
542 This->resource.format = format;
544 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, This->bytesPerPixel);
546 return WINED3D_OK;
549 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
550 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
551 int extraline = 0;
552 SYSTEM_INFO sysInfo;
553 BITMAPINFO* b_info;
554 HDC ddc;
555 DWORD *masks;
556 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
557 UINT usage;
559 switch (This->bytesPerPixel) {
560 case 2:
561 case 4:
562 /* Allocate extra space to store the RGB bit masks. */
563 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
564 break;
566 case 3:
567 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
568 break;
570 default:
571 /* Allocate extra space for a palette. */
572 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
573 sizeof(BITMAPINFOHEADER)
574 + sizeof(RGBQUAD)
575 * (1 << (This->bytesPerPixel * 8)));
576 break;
579 if (!b_info)
580 return E_OUTOFMEMORY;
582 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
583 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
584 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
585 * add an extra line to the dib section
587 GetSystemInfo(&sysInfo);
588 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
589 extraline = 1;
590 TRACE("Adding an extra line to the dib section\n");
593 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
594 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
595 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel;
596 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
597 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
598 b_info->bmiHeader.biPlanes = 1;
599 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
601 b_info->bmiHeader.biXPelsPerMeter = 0;
602 b_info->bmiHeader.biYPelsPerMeter = 0;
603 b_info->bmiHeader.biClrUsed = 0;
604 b_info->bmiHeader.biClrImportant = 0;
606 /* Get the bit masks */
607 masks = (DWORD *)b_info->bmiColors;
608 switch (This->resource.format) {
609 case WINED3DFMT_R8G8B8:
610 usage = DIB_RGB_COLORS;
611 b_info->bmiHeader.biCompression = BI_RGB;
612 break;
614 case WINED3DFMT_X1R5G5B5:
615 case WINED3DFMT_A1R5G5B5:
616 case WINED3DFMT_A4R4G4B4:
617 case WINED3DFMT_X4R4G4B4:
618 case WINED3DFMT_R3G3B2:
619 case WINED3DFMT_A8R3G3B2:
620 case WINED3DFMT_A2B10G10R10:
621 case WINED3DFMT_A8B8G8R8:
622 case WINED3DFMT_X8B8G8R8:
623 case WINED3DFMT_A2R10G10B10:
624 case WINED3DFMT_R5G6B5:
625 case WINED3DFMT_A16B16G16R16:
626 usage = 0;
627 b_info->bmiHeader.biCompression = BI_BITFIELDS;
628 masks[0] = formatEntry->redMask;
629 masks[1] = formatEntry->greenMask;
630 masks[2] = formatEntry->blueMask;
631 break;
633 default:
634 /* Don't know palette */
635 b_info->bmiHeader.biCompression = BI_RGB;
636 usage = 0;
637 break;
640 ddc = GetDC(0);
641 if (ddc == 0) {
642 HeapFree(GetProcessHeap(), 0, b_info);
643 return HRESULT_FROM_WIN32(GetLastError());
646 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);
647 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
648 ReleaseDC(0, ddc);
650 if (!This->dib.DIBsection) {
651 ERR("CreateDIBSection failed!\n");
652 HeapFree(GetProcessHeap(), 0, b_info);
653 return HRESULT_FROM_WIN32(GetLastError());
656 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
657 /* copy the existing surface to the dib section */
658 if(This->resource.allocatedMemory) {
659 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
660 } else {
661 /* This is to make LockRect read the gl Texture although memory is allocated */
662 This->Flags &= ~SFLAG_INSYSMEM;
664 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
666 HeapFree(GetProcessHeap(), 0, b_info);
668 /* Now allocate a HDC */
669 This->hDC = CreateCompatibleDC(0);
670 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
671 TRACE("using wined3d palette %p\n", This->palette);
672 SelectPalette(This->hDC,
673 This->palette ? This->palette->hpal : 0,
674 FALSE);
676 This->Flags |= SFLAG_DIBSECTION;
678 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
679 This->resource.heapMemory = NULL;
681 return WINED3D_OK;
684 static void convert_r32f_r16f(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
685 unsigned int w, unsigned int h)
687 unsigned int x, y;
688 const float *src_f;
689 unsigned short *dst_s;
691 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
692 for(y = 0; y < h; y++) {
693 src_f = (const float *)(src + y * pitch_in);
694 dst_s = (unsigned short *) (dst + y * pitch_out);
695 for(x = 0; x < w; x++) {
696 dst_s[x] = float_32_to_16(src_f + x);
701 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
702 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
704 static const unsigned char convert_5to8[] =
706 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
707 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
708 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
709 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
711 static const unsigned char convert_6to8[] =
713 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
714 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
715 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
716 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
717 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
718 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
719 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
720 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
722 unsigned int x, y;
724 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
726 for (y = 0; y < h; ++y)
728 const WORD *src_line = (const WORD *)(src + y * pitch_in);
729 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
730 for (x = 0; x < w; ++x)
732 WORD pixel = src_line[x];
733 dst_line[x] = 0xff000000
734 | convert_5to8[(pixel & 0xf800) >> 11] << 16
735 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
736 | convert_5to8[(pixel & 0x001f)];
741 struct d3dfmt_convertor_desc {
742 WINED3DFORMAT from, to;
743 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
746 static const struct d3dfmt_convertor_desc convertors[] =
748 {WINED3DFMT_R32F, WINED3DFMT_R16F, convert_r32f_r16f},
749 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
752 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
754 unsigned int i;
755 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
756 if(convertors[i].from == from && convertors[i].to == to) {
757 return &convertors[i];
760 return NULL;
763 /*****************************************************************************
764 * surface_convert_format
766 * Creates a duplicate of a surface in a different format. Is used by Blt to
767 * blit between surfaces with different formats
769 * Parameters
770 * source: Source surface
771 * fmt: Requested destination format
773 *****************************************************************************/
774 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
775 IWineD3DSurface *ret = NULL;
776 const struct d3dfmt_convertor_desc *conv;
777 WINED3DLOCKED_RECT lock_src, lock_dst;
778 HRESULT hr;
780 conv = find_convertor(source->resource.format, to_fmt);
781 if(!conv) {
782 FIXME("Cannot find a conversion function from format %s to %s\n",
783 debug_d3dformat(source->resource.format), debug_d3dformat(to_fmt));
784 return NULL;
787 IWineD3DDevice_CreateSurface((IWineD3DDevice *) source->resource.wineD3DDevice,
788 source->currentDesc.Width,
789 source->currentDesc.Height,
790 to_fmt,
791 TRUE, /* lockable */
792 TRUE, /* discard */
793 0, /* level */
794 &ret,
795 WINED3DRTYPE_SURFACE,
796 0, /* usage */
797 WINED3DPOOL_SCRATCH,
798 WINED3DMULTISAMPLE_NONE, /* TODO: Multisampled conversion */
799 0, /* MultiSampleQuality */
800 NULL, /* SharedHandle */
801 IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
802 NULL); /* parent */
803 if(!ret) {
804 ERR("Failed to create a destination surface for conversion\n");
805 return NULL;
808 memset(&lock_src, 0, sizeof(lock_src));
809 memset(&lock_dst, 0, sizeof(lock_dst));
811 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
812 if(FAILED(hr)) {
813 ERR("Failed to lock the source surface\n");
814 IWineD3DSurface_Release(ret);
815 return NULL;
817 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
818 if(FAILED(hr)) {
819 ERR("Failed to lock the dest surface\n");
820 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
821 IWineD3DSurface_Release(ret);
822 return NULL;
825 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
826 source->currentDesc.Width, source->currentDesc.Height);
828 IWineD3DSurface_UnlockRect(ret);
829 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
831 return (IWineD3DSurfaceImpl *) ret;
834 /*****************************************************************************
835 * _Blt_ColorFill
837 * Helper function that fills a memory area with a specific color
839 * Params:
840 * buf: memory address to start filling at
841 * width, height: Dimensions of the area to fill
842 * bpp: Bit depth of the surface
843 * lPitch: pitch of the surface
844 * color: Color to fill with
846 *****************************************************************************/
847 static HRESULT
848 _Blt_ColorFill(BYTE *buf,
849 int width, int height,
850 int bpp, LONG lPitch,
851 DWORD color)
853 int x, y;
854 LPBYTE first;
856 /* Do first row */
858 #define COLORFILL_ROW(type) \
860 type *d = (type *) buf; \
861 for (x = 0; x < width; x++) \
862 d[x] = (type) color; \
863 break; \
865 switch(bpp)
867 case 1: COLORFILL_ROW(BYTE)
868 case 2: COLORFILL_ROW(WORD)
869 case 3:
871 BYTE *d = buf;
872 for (x = 0; x < width; x++,d+=3)
874 d[0] = (color ) & 0xFF;
875 d[1] = (color>> 8) & 0xFF;
876 d[2] = (color>>16) & 0xFF;
878 break;
880 case 4: COLORFILL_ROW(DWORD)
881 default:
882 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
883 return WINED3DERR_NOTAVAILABLE;
886 #undef COLORFILL_ROW
888 /* Now copy first row */
889 first = buf;
890 for (y = 1; y < height; y++)
892 buf += lPitch;
893 memcpy(buf, first, width * bpp);
895 return WINED3D_OK;
898 /*****************************************************************************
899 * IWineD3DSurface::Blt, SW emulation version
901 * Performs blits to a surface, eigher from a source of source-less blts
902 * This is the main functionality of DirectDraw
904 * Params:
905 * DestRect: Destination rectangle to write to
906 * SrcSurface: Source surface, can be NULL
907 * SrcRect: Source rectangle
908 *****************************************************************************/
909 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
910 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
912 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
913 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
914 RECT xdst,xsrc;
915 HRESULT ret = WINED3D_OK;
916 WINED3DLOCKED_RECT dlock, slock;
917 WINED3DFORMAT dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
918 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
919 int x, y;
920 const StaticPixelFormatDesc *sEntry, *dEntry;
921 const BYTE *sbuf;
922 BYTE *dbuf;
923 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
925 if (TRACE_ON(d3d_surface))
927 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
928 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
929 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
930 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
931 #if 0
932 TRACE("\tflags: ");
933 DDRAW_dump_DDBLT(Flags);
934 if (Flags & WINEDDBLT_DDFX)
936 TRACE("\tblitfx: ");
937 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
939 #endif
942 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
944 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
945 return WINEDDERR_SURFACEBUSY;
948 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
949 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
950 FIXME("Filters not supported in software blit\n");
953 /* First check for the validity of source / destination rectangles. This was
954 * verified using a test application + by MSDN.
956 if ((Src != NULL) && (SrcRect != NULL) &&
957 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
958 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
959 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
960 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
961 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
963 WARN("Application gave us bad source rectangle for Blt.\n");
964 return WINEDDERR_INVALIDRECT;
966 /* For the Destination rect, it can be out of bounds on the condition that a clipper
967 * is set for the given surface.
969 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
970 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
971 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
972 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
973 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
974 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
976 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
977 return WINEDDERR_INVALIDRECT;
980 /* Now handle negative values in the rectangles. Warning: only supported for now
981 in the 'simple' cases (ie not in any stretching / rotation cases).
983 First, the case where nothing is to be done.
985 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
986 (DestRect->top >= (int) This->currentDesc.Height) ||
987 (DestRect->left >= (int) This->currentDesc.Width))) ||
988 ((Src != NULL) && (SrcRect != NULL) &&
989 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
990 (SrcRect->top >= (int) Src->currentDesc.Height) ||
991 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
993 TRACE("Nothing to be done !\n");
994 return WINED3D_OK;
997 if (DestRect)
999 xdst = *DestRect;
1001 else
1003 xdst.top = 0;
1004 xdst.bottom = This->currentDesc.Height;
1005 xdst.left = 0;
1006 xdst.right = This->currentDesc.Width;
1009 if (SrcRect)
1011 xsrc = *SrcRect;
1013 else
1015 if (Src)
1017 xsrc.top = 0;
1018 xsrc.bottom = Src->currentDesc.Height;
1019 xsrc.left = 0;
1020 xsrc.right = Src->currentDesc.Width;
1022 else
1024 memset(&xsrc,0,sizeof(xsrc));
1028 /* The easy case : the source-less blits.... */
1029 if (Src == NULL && DestRect)
1031 RECT full_rect;
1032 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1034 full_rect.left = 0;
1035 full_rect.top = 0;
1036 full_rect.right = This->currentDesc.Width;
1037 full_rect.bottom = This->currentDesc.Height;
1038 IntersectRect(&temp_rect, &full_rect, DestRect);
1039 xdst = temp_rect;
1041 else if (DestRect)
1043 /* Only handle clipping on the destination rectangle */
1044 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1045 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1046 if (clip_vert || clip_horiz)
1048 /* Now check if this is a special case or not... */
1049 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1050 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1051 (Flags & WINEDDBLT_DDFX))
1053 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1054 return WINED3D_OK;
1057 if (clip_horiz)
1059 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1060 if (DestRect->right > This->currentDesc.Width)
1062 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1063 xdst.right = (int) This->currentDesc.Width;
1066 if (clip_vert)
1068 if (DestRect->top < 0)
1070 xsrc.top -= DestRect->top;
1071 xdst.top = 0;
1073 if (DestRect->bottom > This->currentDesc.Height)
1075 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1076 xdst.bottom = (int) This->currentDesc.Height;
1079 /* And check if after clipping something is still to be done... */
1080 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1081 (xdst.top >= (int) This->currentDesc.Height) ||
1082 (xdst.left >= (int) This->currentDesc.Width) ||
1083 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1084 (xsrc.top >= (int) Src->currentDesc.Height) ||
1085 (xsrc.left >= (int) Src->currentDesc.Width))
1087 TRACE("Nothing to be done after clipping !\n");
1088 return WINED3D_OK;
1093 if (Src == This)
1095 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1096 dfmt = This->resource.format;
1097 slock = dlock;
1098 sfmt = dfmt;
1099 sEntry = getFormatDescEntry(sfmt, NULL, NULL);
1100 dEntry = sEntry;
1102 else
1104 dfmt = This->resource.format;
1105 dEntry = getFormatDescEntry(dfmt, NULL, NULL);
1106 if (Src)
1108 if(This->resource.format != Src->resource.format) {
1109 Src = surface_convert_format(Src, dfmt);
1110 if(!Src) {
1111 /* The conv function writes a FIXME */
1112 WARN("Cannot convert source surface format to dest format\n");
1113 goto release;
1116 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1117 sfmt = Src->resource.format;
1119 sEntry = getFormatDescEntry(sfmt, NULL, NULL);
1120 if (DestRect)
1121 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1122 else
1123 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1126 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1128 if (sEntry->isFourcc && dEntry->isFourcc)
1130 if (!DestRect || Src == This)
1132 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1133 goto release;
1137 bpp = This->bytesPerPixel;
1138 srcheight = xsrc.bottom - xsrc.top;
1139 srcwidth = xsrc.right - xsrc.left;
1140 dstheight = xdst.bottom - xdst.top;
1141 dstwidth = xdst.right - xdst.left;
1142 width = (xdst.right - xdst.left) * bpp;
1144 assert(width <= dlock.Pitch);
1146 if (DestRect && Src != This)
1147 dbuf = (BYTE*)dlock.pBits;
1148 else
1149 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1151 if (Flags & WINEDDBLT_WAIT)
1153 Flags &= ~WINEDDBLT_WAIT;
1155 if (Flags & WINEDDBLT_ASYNC)
1157 static BOOL displayed = FALSE;
1158 if (!displayed)
1159 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1160 displayed = TRUE;
1161 Flags &= ~WINEDDBLT_ASYNC;
1163 if (Flags & WINEDDBLT_DONOTWAIT)
1165 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1166 static BOOL displayed = FALSE;
1167 if (!displayed)
1168 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1169 displayed = TRUE;
1170 Flags &= ~WINEDDBLT_DONOTWAIT;
1173 /* First, all the 'source-less' blits */
1174 if (Flags & WINEDDBLT_COLORFILL)
1176 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1177 dlock.Pitch, DDBltFx->u5.dwFillColor);
1178 Flags &= ~WINEDDBLT_COLORFILL;
1181 if (Flags & WINEDDBLT_DEPTHFILL)
1183 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1185 if (Flags & WINEDDBLT_ROP)
1187 /* Catch some degenerate cases here */
1188 switch(DDBltFx->dwROP)
1190 case BLACKNESS:
1191 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1192 break;
1193 case 0xAA0029: /* No-op */
1194 break;
1195 case WHITENESS:
1196 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1197 break;
1198 case SRCCOPY: /* well, we do that below ? */
1199 break;
1200 default:
1201 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1202 goto error;
1204 Flags &= ~WINEDDBLT_ROP;
1206 if (Flags & WINEDDBLT_DDROPS)
1208 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1210 /* Now the 'with source' blits */
1211 if (Src)
1213 const BYTE *sbase;
1214 int sx, xinc, sy, yinc;
1216 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1217 goto release;
1218 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1219 xinc = (srcwidth << 16) / dstwidth;
1220 yinc = (srcheight << 16) / dstheight;
1222 if (!Flags)
1224 /* No effects, we can cheat here */
1225 if (dstwidth == srcwidth)
1227 if (dstheight == srcheight)
1229 /* No stretching in either direction. This needs to be as
1230 * fast as possible */
1231 sbuf = sbase;
1233 /* check for overlapping surfaces */
1234 if (Src != This || xdst.top < xsrc.top ||
1235 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1237 /* no overlap, or dst above src, so copy from top downwards */
1238 for (y = 0; y < dstheight; y++)
1240 memcpy(dbuf, sbuf, width);
1241 sbuf += slock.Pitch;
1242 dbuf += dlock.Pitch;
1245 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1247 sbuf += (slock.Pitch*dstheight);
1248 dbuf += (dlock.Pitch*dstheight);
1249 for (y = 0; y < dstheight; y++)
1251 sbuf -= slock.Pitch;
1252 dbuf -= dlock.Pitch;
1253 memcpy(dbuf, sbuf, width);
1256 else /* src and dst overlapping on the same line, use memmove */
1258 for (y = 0; y < dstheight; y++)
1260 memmove(dbuf, sbuf, width);
1261 sbuf += slock.Pitch;
1262 dbuf += dlock.Pitch;
1265 } else {
1266 /* Stretching in Y direction only */
1267 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1268 sbuf = sbase + (sy >> 16) * slock.Pitch;
1269 memcpy(dbuf, sbuf, width);
1270 dbuf += dlock.Pitch;
1274 else
1276 /* Stretching in X direction */
1277 int last_sy = -1;
1278 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1280 sbuf = sbase + (sy >> 16) * slock.Pitch;
1282 if ((sy >> 16) == (last_sy >> 16))
1284 /* this sourcerow is the same as last sourcerow -
1285 * copy already stretched row
1287 memcpy(dbuf, dbuf - dlock.Pitch, width);
1289 else
1291 #define STRETCH_ROW(type) { \
1292 const type *s = (const type *)sbuf; \
1293 type *d = (type *)dbuf; \
1294 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1295 d[x] = s[sx >> 16]; \
1296 break; }
1298 switch(bpp)
1300 case 1: STRETCH_ROW(BYTE)
1301 case 2: STRETCH_ROW(WORD)
1302 case 4: STRETCH_ROW(DWORD)
1303 case 3:
1305 const BYTE *s;
1306 BYTE *d = dbuf;
1307 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1309 DWORD pixel;
1311 s = sbuf+3*(sx>>16);
1312 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1313 d[0] = (pixel )&0xff;
1314 d[1] = (pixel>> 8)&0xff;
1315 d[2] = (pixel>>16)&0xff;
1316 d+=3;
1318 break;
1320 default:
1321 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1322 ret = WINED3DERR_NOTAVAILABLE;
1323 goto error;
1325 #undef STRETCH_ROW
1327 dbuf += dlock.Pitch;
1328 last_sy = sy;
1332 else
1334 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1335 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1336 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1337 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1339 /* The color keying flags are checked for correctness in ddraw */
1340 if (Flags & WINEDDBLT_KEYSRC)
1342 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1343 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1345 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1347 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1348 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1351 if (Flags & WINEDDBLT_KEYDEST)
1353 /* Destination color keys are taken from the source surface ! */
1354 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1355 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1357 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1359 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1360 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1363 if(bpp == 1)
1365 keymask = 0xff;
1367 else
1369 keymask = sEntry->redMask |
1370 sEntry->greenMask |
1371 sEntry->blueMask;
1373 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1376 if (Flags & WINEDDBLT_DDFX)
1378 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1379 LONG tmpxy;
1380 dTopLeft = dbuf;
1381 dTopRight = dbuf+((dstwidth-1)*bpp);
1382 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1383 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1385 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1387 /* I don't think we need to do anything about this flag */
1388 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1390 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1392 tmp = dTopRight;
1393 dTopRight = dTopLeft;
1394 dTopLeft = tmp;
1395 tmp = dBottomRight;
1396 dBottomRight = dBottomLeft;
1397 dBottomLeft = tmp;
1398 dstxinc = dstxinc *-1;
1400 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1402 tmp = dTopLeft;
1403 dTopLeft = dBottomLeft;
1404 dBottomLeft = tmp;
1405 tmp = dTopRight;
1406 dTopRight = dBottomRight;
1407 dBottomRight = tmp;
1408 dstyinc = dstyinc *-1;
1410 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1412 /* I don't think we need to do anything about this flag */
1413 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1415 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1417 tmp = dBottomRight;
1418 dBottomRight = dTopLeft;
1419 dTopLeft = tmp;
1420 tmp = dBottomLeft;
1421 dBottomLeft = dTopRight;
1422 dTopRight = tmp;
1423 dstxinc = dstxinc * -1;
1424 dstyinc = dstyinc * -1;
1426 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1428 tmp = dTopLeft;
1429 dTopLeft = dBottomLeft;
1430 dBottomLeft = dBottomRight;
1431 dBottomRight = dTopRight;
1432 dTopRight = tmp;
1433 tmpxy = dstxinc;
1434 dstxinc = dstyinc;
1435 dstyinc = tmpxy;
1436 dstxinc = dstxinc * -1;
1438 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1440 tmp = dTopLeft;
1441 dTopLeft = dTopRight;
1442 dTopRight = dBottomRight;
1443 dBottomRight = dBottomLeft;
1444 dBottomLeft = tmp;
1445 tmpxy = dstxinc;
1446 dstxinc = dstyinc;
1447 dstyinc = tmpxy;
1448 dstyinc = dstyinc * -1;
1450 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1452 /* I don't think we need to do anything about this flag */
1453 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1455 dbuf = dTopLeft;
1456 Flags &= ~(WINEDDBLT_DDFX);
1459 #define COPY_COLORKEY_FX(type) { \
1460 const type *s; \
1461 type *d = (type *)dbuf, *dx, tmp; \
1462 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1463 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1464 dx = d; \
1465 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1466 tmp = s[sx >> 16]; \
1467 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1468 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1469 dx[0] = tmp; \
1471 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1473 d = (type*)(((LPBYTE)d)+dstyinc); \
1475 break; }
1477 switch (bpp) {
1478 case 1: COPY_COLORKEY_FX(BYTE)
1479 case 2: COPY_COLORKEY_FX(WORD)
1480 case 4: COPY_COLORKEY_FX(DWORD)
1481 case 3:
1483 const BYTE *s;
1484 BYTE *d = dbuf, *dx;
1485 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1487 sbuf = sbase + (sy >> 16) * slock.Pitch;
1488 dx = d;
1489 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1491 DWORD pixel, dpixel = 0;
1492 s = sbuf+3*(sx>>16);
1493 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1494 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1495 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1496 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1498 dx[0] = (pixel )&0xff;
1499 dx[1] = (pixel>> 8)&0xff;
1500 dx[2] = (pixel>>16)&0xff;
1502 dx+= dstxinc;
1504 d += dstyinc;
1506 break;
1508 default:
1509 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1510 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1511 ret = WINED3DERR_NOTAVAILABLE;
1512 goto error;
1513 #undef COPY_COLORKEY_FX
1518 error:
1519 if (Flags && FIXME_ON(d3d_surface))
1521 FIXME("\tUnsupported flags: %08x\n", Flags);
1524 release:
1525 IWineD3DSurface_UnlockRect(iface);
1526 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1527 /* Release the converted surface if any */
1528 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1529 return ret;
1532 /*****************************************************************************
1533 * IWineD3DSurface::BltFast, SW emulation version
1535 * This is the software implementation of BltFast, as used by GDI surfaces
1536 * and as a fallback for OpenGL surfaces. This code is taken from the old
1537 * DirectDraw code, and was originally written by TransGaming.
1539 * Params:
1540 * dstx:
1541 * dsty:
1542 * Source: Source surface to copy from
1543 * rsrc: Source rectangle
1544 * trans: Some Flags
1546 * Returns:
1547 * WINED3D_OK on success
1549 *****************************************************************************/
1550 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1551 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1553 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1554 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1556 int bpp, w, h, x, y;
1557 WINED3DLOCKED_RECT dlock,slock;
1558 HRESULT ret = WINED3D_OK;
1559 RECT rsrc2;
1560 RECT lock_src, lock_dst, lock_union;
1561 const BYTE *sbuf;
1562 BYTE *dbuf;
1563 const StaticPixelFormatDesc *sEntry, *dEntry;
1565 if (TRACE_ON(d3d_surface))
1567 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1569 if (rsrc)
1571 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1572 rsrc->right,rsrc->bottom);
1574 else
1576 TRACE(" srcrect: NULL\n");
1580 if ((This->Flags & SFLAG_LOCKED) ||
1581 (Src->Flags & SFLAG_LOCKED))
1583 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1584 return WINEDDERR_SURFACEBUSY;
1587 if (!rsrc)
1589 WARN("rsrc is NULL!\n");
1590 rsrc2.left = 0;
1591 rsrc2.top = 0;
1592 rsrc2.right = Src->currentDesc.Width;
1593 rsrc2.bottom = Src->currentDesc.Height;
1594 rsrc = &rsrc2;
1597 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1598 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1599 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1600 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1601 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1602 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1604 WARN("Application gave us bad source rectangle for BltFast.\n");
1605 return WINEDDERR_INVALIDRECT;
1608 h = rsrc->bottom - rsrc->top;
1609 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1610 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1611 if (h <= 0) return WINEDDERR_INVALIDRECT;
1613 w = rsrc->right - rsrc->left;
1614 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1615 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1616 if (w <= 0) return WINEDDERR_INVALIDRECT;
1618 /* Now compute the locking rectangle... */
1619 lock_src.left = rsrc->left;
1620 lock_src.top = rsrc->top;
1621 lock_src.right = lock_src.left + w;
1622 lock_src.bottom = lock_src.top + h;
1624 lock_dst.left = dstx;
1625 lock_dst.top = dsty;
1626 lock_dst.right = dstx + w;
1627 lock_dst.bottom = dsty + h;
1629 bpp = This->bytesPerPixel;
1631 /* We need to lock the surfaces, or we won't get refreshes when done. */
1632 if (Src == This)
1634 int pitch;
1636 UnionRect(&lock_union, &lock_src, &lock_dst);
1638 /* Lock the union of the two rectangles */
1639 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1640 if(ret != WINED3D_OK) goto error;
1642 pitch = dlock.Pitch;
1643 slock.Pitch = dlock.Pitch;
1645 /* Since slock was originally copied from this surface's description, we can just reuse it */
1646 assert(This->resource.allocatedMemory != NULL);
1647 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1648 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1649 sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL);
1650 dEntry = sEntry;
1652 else
1654 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1655 if(ret != WINED3D_OK) goto error;
1656 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1657 if(ret != WINED3D_OK) goto error;
1659 sbuf = slock.pBits;
1660 dbuf = dlock.pBits;
1661 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1663 sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL);
1664 dEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
1667 /* Handle first the FOURCC surfaces... */
1668 if (sEntry->isFourcc && dEntry->isFourcc)
1670 TRACE("Fourcc -> Fourcc copy\n");
1671 if (trans)
1672 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1673 if (dstx || dsty)
1674 FIXME("offset for destination surface is not supported\n");
1675 if (Src->resource.format != This->resource.format)
1677 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1678 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1679 goto error;
1681 /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1682 memcpy(dbuf, sbuf, This->resource.size);
1683 goto error;
1685 if (sEntry->isFourcc && !dEntry->isFourcc)
1687 /* TODO: Use the libtxc_dxtn.so shared library to do
1688 * software decompression
1690 ERR("DXTC decompression not supported by now\n");
1691 goto error;
1694 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1696 DWORD keylow, keyhigh;
1697 TRACE("Color keyed copy\n");
1698 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1700 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1701 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1703 else
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;
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; \
1720 s = (const type *)((const BYTE *)s + slock.Pitch); \
1721 d = (type *)((BYTE *)d + dlock.Pitch); \
1723 break; \
1726 switch (bpp) {
1727 case 1: COPYBOX_COLORKEY(BYTE)
1728 case 2: COPYBOX_COLORKEY(WORD)
1729 case 4: COPYBOX_COLORKEY(DWORD)
1730 case 3:
1732 const BYTE *s;
1733 BYTE *d;
1734 DWORD tmp;
1735 s = sbuf;
1736 d = dbuf;
1737 for (y = 0; y < h; y++)
1739 for (x = 0; x < w * 3; x += 3)
1741 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1742 if (tmp < keylow || tmp > keyhigh)
1744 d[x + 0] = s[x + 0];
1745 d[x + 1] = s[x + 1];
1746 d[x + 2] = s[x + 2];
1749 s += slock.Pitch;
1750 d += dlock.Pitch;
1752 break;
1754 default:
1755 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1756 ret = WINED3DERR_NOTAVAILABLE;
1757 goto error;
1759 #undef COPYBOX_COLORKEY
1760 TRACE("Copy Done\n");
1762 else
1764 int width = w * bpp;
1765 INT sbufpitch, dbufpitch;
1767 TRACE("NO color key copy\n");
1768 /* Handle overlapping surfaces */
1769 if (sbuf < dbuf)
1771 sbuf += (h - 1) * slock.Pitch;
1772 dbuf += (h - 1) * dlock.Pitch;
1773 sbufpitch = -slock.Pitch;
1774 dbufpitch = -dlock.Pitch;
1776 else
1778 sbufpitch = slock.Pitch;
1779 dbufpitch = dlock.Pitch;
1781 for (y = 0; y < h; y++)
1783 /* This is pretty easy, a line for line memcpy */
1784 memmove(dbuf, sbuf, width);
1785 sbuf += sbufpitch;
1786 dbuf += dbufpitch;
1788 TRACE("Copy done\n");
1791 error:
1792 if (Src == This)
1794 IWineD3DSurface_UnlockRect(iface);
1796 else
1798 IWineD3DSurface_UnlockRect(iface);
1799 IWineD3DSurface_UnlockRect(Source);
1802 return ret;
1805 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1807 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1809 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1810 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1812 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1814 if (NULL == pRect)
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;
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);
1826 else
1828 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1829 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1831 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1832 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1833 * slightly different meaning compared to regular textures. For DXTn
1834 * textures Pitch is the size of a row of blocks, 4 high and "width"
1835 * long. The x offset is calculated differently as well, since moving 4
1836 * pixels to the right actually moves an entire 4x4 block to right, ie
1837 * 16 bytes (8 in case of DXT1). */
1838 if (This->resource.format == WINED3DFMT_DXT1)
1840 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1842 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
1843 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5)
1845 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1847 else
1849 pLockedRect->pBits = This->resource.allocatedMemory +
1850 (pLockedRect->Pitch * pRect->top) +
1851 (pRect->left * This->bytesPerPixel);
1853 This->lockedRect.left = pRect->left;
1854 This->lockedRect.top = pRect->top;
1855 This->lockedRect.right = pRect->right;
1856 This->lockedRect.bottom = pRect->bottom;
1859 /* No dirtifying is needed for this surface implementation */
1860 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1862 return WINED3D_OK;
1865 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface) {
1866 ERR("Should not be called on base texture\n");
1867 return;
1870 /* TODO: think about moving this down to resource? */
1871 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1873 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1875 /* This should only be called for sysmem textures, it may be a good idea
1876 * to extend this to all pools at some point in the future */
1877 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1879 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1881 return This->resource.allocatedMemory;