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
30 #include "wine/port.h"
31 #include "wined3d_private.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)
41 float tmp = fabs(*in);
42 unsigned int mantissa;
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)) {
55 }while(tmp < pow(2, 10));
56 } else if(tmp >= pow(2, 11)) {
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 */
73 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
75 mantissa = mantissa >> 1;
78 ret = mantissa & 0x3ff;
80 ret = (exp << 10) | (mantissa & 0x3ff);
83 ret |= ((*in < 0.0 ? 1 : 0) << 15); /* Add the sign */
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);
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);
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);
166 ERR("Called without a valid ppContainer.\n");
169 /* Standalone surfaces return the device as container. */
170 if (This->container) {
171 container = This->container;
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;
196 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
197 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
198 TRACE("(%p)->(%x)\n", This, Flags);
202 case WINEDDGBS_CANBLT:
203 case WINEDDGBS_ISBLTDONE:
207 return WINED3DERR_INVALIDCALL;
211 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
212 /* XXX: DDERR_INVALIDSURFACETYPE */
214 TRACE("(%p)->(%08x)\n",iface,Flags);
216 case WINEDDGFS_CANFLIP:
217 case WINEDDGFS_ISFLIPDONE:
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;
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");
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 */
280 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
281 case WINEDDCKEY_DESTBLT:
282 This->DestBltCKey = *CKey;
283 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
286 case WINEDDCKEY_DESTOVERLAY:
287 This->DestOverlayCKey = *CKey;
288 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
291 case WINEDDCKEY_SRCOVERLAY:
292 This->SrcOverlayCKey = *CKey;
293 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
296 case WINEDDCKEY_SRCBLT:
297 This->SrcBltCKey = *CKey;
298 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
303 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
304 case WINEDDCKEY_DESTBLT:
305 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
308 case WINEDDCKEY_DESTOVERLAY:
309 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
312 case WINEDDCKEY_SRCOVERLAY:
313 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
316 case WINEDDCKEY_SRCBLT:
317 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
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;
333 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
334 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
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;
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);
355 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
356 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
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);
379 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
380 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
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) {
392 hr = WINEDDERR_OVERLAYNOTVISIBLE;
394 *X = This->overlay_destrect.left;
395 *Y = This->overlay_destrect.top;
399 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
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;
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;
435 This->overlay_srcrect = *SrcRect;
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;
444 This->overlay_destrect = *DstRect;
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);
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;
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;
491 IWineD3DClipper_AddRef(*clipper);
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;
509 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
510 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
511 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
512 &This->resource.wineD3DDevice->adapter->gl_info);
514 if (This->resource.format != WINED3DFMT_UNKNOWN) {
515 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
516 return WINED3DERR_INVALIDCALL;
519 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
520 if (format == WINED3DFMT_UNKNOWN) {
521 This->resource.size = 0;
522 } else if (format == WINED3DFMT_DXT1) {
523 /* DXT1 is half byte per pixel */
524 This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4)) >> 1;
526 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
527 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
528 This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4));
530 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
531 This->resource.size = ((This->pow2Width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1);
532 This->resource.size *= This->pow2Height;
535 if (format != WINED3DFMT_UNKNOWN) {
536 This->bytesPerPixel = format_desc->byte_count;
538 This->bytesPerPixel = 0;
541 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
543 This->resource.format = format;
544 This->resource.format_desc = format_desc;
546 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, This->bytesPerPixel);
551 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
552 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
553 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
561 switch (This->bytesPerPixel) {
564 /* Allocate extra space to store the RGB bit masks. */
565 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
569 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
573 /* Allocate extra space for a palette. */
574 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
575 sizeof(BITMAPINFOHEADER)
577 * (1 << (This->bytesPerPixel * 8)));
582 return E_OUTOFMEMORY;
584 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
585 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
586 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
587 * add an extra line to the dib section
589 GetSystemInfo(&sysInfo);
590 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
592 TRACE("Adding an extra line to the dib section\n");
595 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
596 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
597 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel;
598 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
599 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
600 b_info->bmiHeader.biPlanes = 1;
601 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
603 b_info->bmiHeader.biXPelsPerMeter = 0;
604 b_info->bmiHeader.biYPelsPerMeter = 0;
605 b_info->bmiHeader.biClrUsed = 0;
606 b_info->bmiHeader.biClrImportant = 0;
608 /* Get the bit masks */
609 masks = (DWORD *)b_info->bmiColors;
610 switch (This->resource.format) {
611 case WINED3DFMT_R8G8B8:
612 usage = DIB_RGB_COLORS;
613 b_info->bmiHeader.biCompression = BI_RGB;
616 case WINED3DFMT_X1R5G5B5:
617 case WINED3DFMT_A1R5G5B5:
618 case WINED3DFMT_A4R4G4B4:
619 case WINED3DFMT_X4R4G4B4:
620 case WINED3DFMT_R3G3B2:
621 case WINED3DFMT_A8R3G3B2:
622 case WINED3DFMT_R10G10B10A2_UNORM:
623 case WINED3DFMT_R8G8B8A8_UNORM:
624 case WINED3DFMT_X8B8G8R8:
625 case WINED3DFMT_A2R10G10B10:
626 case WINED3DFMT_R5G6B5:
627 case WINED3DFMT_R16G16B16A16_UNORM:
629 b_info->bmiHeader.biCompression = BI_BITFIELDS;
630 masks[0] = format_desc->red_mask;
631 masks[1] = format_desc->green_mask;
632 masks[2] = format_desc->blue_mask;
636 /* Don't know palette */
637 b_info->bmiHeader.biCompression = BI_RGB;
644 HeapFree(GetProcessHeap(), 0, b_info);
645 return HRESULT_FROM_WIN32(GetLastError());
648 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);
649 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
652 if (!This->dib.DIBsection) {
653 ERR("CreateDIBSection failed!\n");
654 HeapFree(GetProcessHeap(), 0, b_info);
655 return HRESULT_FROM_WIN32(GetLastError());
658 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
659 /* copy the existing surface to the dib section */
660 if(This->resource.allocatedMemory) {
661 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
663 /* This is to make LockRect read the gl Texture although memory is allocated */
664 This->Flags &= ~SFLAG_INSYSMEM;
666 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
668 HeapFree(GetProcessHeap(), 0, b_info);
670 /* Now allocate a HDC */
671 This->hDC = CreateCompatibleDC(0);
672 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
673 TRACE("using wined3d palette %p\n", This->palette);
674 SelectPalette(This->hDC,
675 This->palette ? This->palette->hpal : 0,
678 This->Flags |= SFLAG_DIBSECTION;
680 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
681 This->resource.heapMemory = NULL;
686 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
687 unsigned int w, unsigned int h)
691 unsigned short *dst_s;
693 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
694 for(y = 0; y < h; y++) {
695 src_f = (const float *)(src + y * pitch_in);
696 dst_s = (unsigned short *) (dst + y * pitch_out);
697 for(x = 0; x < w; x++) {
698 dst_s[x] = float_32_to_16(src_f + x);
703 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
704 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
706 static const unsigned char convert_5to8[] =
708 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
709 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
710 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
711 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
713 static const unsigned char convert_6to8[] =
715 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
716 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
717 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
718 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
719 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
720 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
721 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
722 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
726 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
728 for (y = 0; y < h; ++y)
730 const WORD *src_line = (const WORD *)(src + y * pitch_in);
731 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
732 for (x = 0; x < w; ++x)
734 WORD pixel = src_line[x];
735 dst_line[x] = 0xff000000
736 | convert_5to8[(pixel & 0xf800) >> 11] << 16
737 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
738 | convert_5to8[(pixel & 0x001f)];
743 struct d3dfmt_convertor_desc {
744 WINED3DFORMAT from, to;
745 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
748 static const struct d3dfmt_convertor_desc convertors[] =
750 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
751 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
754 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
757 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
758 if(convertors[i].from == from && convertors[i].to == to) {
759 return &convertors[i];
765 /*****************************************************************************
766 * surface_convert_format
768 * Creates a duplicate of a surface in a different format. Is used by Blt to
769 * blit between surfaces with different formats
772 * source: Source surface
773 * fmt: Requested destination format
775 *****************************************************************************/
776 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
777 IWineD3DSurface *ret = NULL;
778 const struct d3dfmt_convertor_desc *conv;
779 WINED3DLOCKED_RECT lock_src, lock_dst;
782 conv = find_convertor(source->resource.format, to_fmt);
784 FIXME("Cannot find a conversion function from format %s to %s\n",
785 debug_d3dformat(source->resource.format), debug_d3dformat(to_fmt));
789 IWineD3DDevice_CreateSurface((IWineD3DDevice *) source->resource.wineD3DDevice,
790 source->currentDesc.Width,
791 source->currentDesc.Height,
797 WINED3DRTYPE_SURFACE,
800 WINED3DMULTISAMPLE_NONE, /* TODO: Multisampled conversion */
801 0, /* MultiSampleQuality */
802 NULL, /* SharedHandle */
803 IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
806 ERR("Failed to create a destination surface for conversion\n");
810 memset(&lock_src, 0, sizeof(lock_src));
811 memset(&lock_dst, 0, sizeof(lock_dst));
813 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
815 ERR("Failed to lock the source surface\n");
816 IWineD3DSurface_Release(ret);
819 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
821 ERR("Failed to lock the dest surface\n");
822 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
823 IWineD3DSurface_Release(ret);
827 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
828 source->currentDesc.Width, source->currentDesc.Height);
830 IWineD3DSurface_UnlockRect(ret);
831 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
833 return (IWineD3DSurfaceImpl *) ret;
836 /*****************************************************************************
839 * Helper function that fills a memory area with a specific color
842 * buf: memory address to start filling at
843 * width, height: Dimensions of the area to fill
844 * bpp: Bit depth of the surface
845 * lPitch: pitch of the surface
846 * color: Color to fill with
848 *****************************************************************************/
850 _Blt_ColorFill(BYTE *buf,
851 int width, int height,
852 int bpp, LONG lPitch,
860 #define COLORFILL_ROW(type) \
862 type *d = (type *) buf; \
863 for (x = 0; x < width; x++) \
864 d[x] = (type) color; \
869 case 1: COLORFILL_ROW(BYTE)
870 case 2: COLORFILL_ROW(WORD)
874 for (x = 0; x < width; x++,d+=3)
876 d[0] = (color ) & 0xFF;
877 d[1] = (color>> 8) & 0xFF;
878 d[2] = (color>>16) & 0xFF;
882 case 4: COLORFILL_ROW(DWORD)
884 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
885 return WINED3DERR_NOTAVAILABLE;
890 /* Now copy first row */
892 for (y = 1; y < height; y++)
895 memcpy(buf, first, width * bpp);
900 /*****************************************************************************
901 * IWineD3DSurface::Blt, SW emulation version
903 * Performs blits to a surface, eigher from a source of source-less blts
904 * This is the main functionality of DirectDraw
907 * DestRect: Destination rectangle to write to
908 * SrcSurface: Source surface, can be NULL
909 * SrcRect: Source rectangle
910 *****************************************************************************/
911 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
912 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
914 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
915 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
917 HRESULT ret = WINED3D_OK;
918 WINED3DLOCKED_RECT dlock, slock;
919 WINED3DFORMAT dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN;
920 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
921 const struct GlPixelFormatDesc *sEntry, *dEntry;
925 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
927 if (TRACE_ON(d3d_surface))
929 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
930 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
931 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
932 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
935 DDRAW_dump_DDBLT(Flags);
936 if (Flags & WINEDDBLT_DDFX)
939 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
944 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
946 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
947 return WINEDDERR_SURFACEBUSY;
950 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
951 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
952 FIXME("Filters not supported in software blit\n");
955 /* First check for the validity of source / destination rectangles. This was
956 * verified using a test application + by MSDN.
958 if ((Src != NULL) && (SrcRect != NULL) &&
959 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
960 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
961 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
962 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
963 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
965 WARN("Application gave us bad source rectangle for Blt.\n");
966 return WINEDDERR_INVALIDRECT;
968 /* For the Destination rect, it can be out of bounds on the condition that a clipper
969 * is set for the given surface.
971 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
972 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
973 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
974 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
975 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
976 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
978 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
979 return WINEDDERR_INVALIDRECT;
982 /* Now handle negative values in the rectangles. Warning: only supported for now
983 in the 'simple' cases (ie not in any stretching / rotation cases).
985 First, the case where nothing is to be done.
987 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
988 (DestRect->top >= (int) This->currentDesc.Height) ||
989 (DestRect->left >= (int) This->currentDesc.Width))) ||
990 ((Src != NULL) && (SrcRect != NULL) &&
991 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
992 (SrcRect->top >= (int) Src->currentDesc.Height) ||
993 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
995 TRACE("Nothing to be done !\n");
1006 xdst.bottom = This->currentDesc.Height;
1008 xdst.right = This->currentDesc.Width;
1020 xsrc.bottom = Src->currentDesc.Height;
1022 xsrc.right = Src->currentDesc.Width;
1026 memset(&xsrc,0,sizeof(xsrc));
1030 /* The easy case : the source-less blits.... */
1031 if (Src == NULL && DestRect)
1034 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1038 full_rect.right = This->currentDesc.Width;
1039 full_rect.bottom = This->currentDesc.Height;
1040 IntersectRect(&temp_rect, &full_rect, DestRect);
1045 /* Only handle clipping on the destination rectangle */
1046 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1047 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1048 if (clip_vert || clip_horiz)
1050 /* Now check if this is a special case or not... */
1051 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1052 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1053 (Flags & WINEDDBLT_DDFX))
1055 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1061 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1062 if (DestRect->right > This->currentDesc.Width)
1064 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1065 xdst.right = (int) This->currentDesc.Width;
1070 if (DestRect->top < 0)
1072 xsrc.top -= DestRect->top;
1075 if (DestRect->bottom > This->currentDesc.Height)
1077 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1078 xdst.bottom = (int) This->currentDesc.Height;
1081 /* And check if after clipping something is still to be done... */
1082 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1083 (xdst.top >= (int) This->currentDesc.Height) ||
1084 (xdst.left >= (int) This->currentDesc.Width) ||
1085 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1086 (xsrc.top >= (int) Src->currentDesc.Height) ||
1087 (xsrc.left >= (int) Src->currentDesc.Width))
1089 TRACE("Nothing to be done after clipping !\n");
1097 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1098 dfmt = This->resource.format;
1101 sEntry = This->resource.format_desc;
1106 dfmt = This->resource.format;
1107 dEntry = This->resource.format_desc;
1110 if(This->resource.format != Src->resource.format) {
1111 Src = surface_convert_format(Src, dfmt);
1113 /* The conv function writes a FIXME */
1114 WARN("Cannot convert source surface format to dest format\n");
1118 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1119 sfmt = Src->resource.format;
1120 sEntry = Src->resource.format_desc;
1127 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1129 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1132 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1134 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1136 if (!DestRect || Src == This)
1138 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1143 bpp = This->bytesPerPixel;
1144 srcheight = xsrc.bottom - xsrc.top;
1145 srcwidth = xsrc.right - xsrc.left;
1146 dstheight = xdst.bottom - xdst.top;
1147 dstwidth = xdst.right - xdst.left;
1148 width = (xdst.right - xdst.left) * bpp;
1150 assert(width <= dlock.Pitch);
1152 if (DestRect && Src != This)
1155 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1157 if (Flags & WINEDDBLT_WAIT)
1159 Flags &= ~WINEDDBLT_WAIT;
1161 if (Flags & WINEDDBLT_ASYNC)
1163 static BOOL displayed = FALSE;
1165 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1167 Flags &= ~WINEDDBLT_ASYNC;
1169 if (Flags & WINEDDBLT_DONOTWAIT)
1171 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1172 static BOOL displayed = FALSE;
1174 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1176 Flags &= ~WINEDDBLT_DONOTWAIT;
1179 /* First, all the 'source-less' blits */
1180 if (Flags & WINEDDBLT_COLORFILL)
1182 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1183 dlock.Pitch, DDBltFx->u5.dwFillColor);
1184 Flags &= ~WINEDDBLT_COLORFILL;
1187 if (Flags & WINEDDBLT_DEPTHFILL)
1189 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1191 if (Flags & WINEDDBLT_ROP)
1193 /* Catch some degenerate cases here */
1194 switch(DDBltFx->dwROP)
1197 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1199 case 0xAA0029: /* No-op */
1202 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1204 case SRCCOPY: /* well, we do that below ? */
1207 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1210 Flags &= ~WINEDDBLT_ROP;
1212 if (Flags & WINEDDBLT_DDROPS)
1214 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1216 /* Now the 'with source' blits */
1220 int sx, xinc, sy, yinc;
1222 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1224 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1225 xinc = (srcwidth << 16) / dstwidth;
1226 yinc = (srcheight << 16) / dstheight;
1230 /* No effects, we can cheat here */
1231 if (dstwidth == srcwidth)
1233 if (dstheight == srcheight)
1235 /* No stretching in either direction. This needs to be as
1236 * fast as possible */
1239 /* check for overlapping surfaces */
1240 if (Src != This || xdst.top < xsrc.top ||
1241 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1243 /* no overlap, or dst above src, so copy from top downwards */
1244 for (y = 0; y < dstheight; y++)
1246 memcpy(dbuf, sbuf, width);
1247 sbuf += slock.Pitch;
1248 dbuf += dlock.Pitch;
1251 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1253 sbuf += (slock.Pitch*dstheight);
1254 dbuf += (dlock.Pitch*dstheight);
1255 for (y = 0; y < dstheight; y++)
1257 sbuf -= slock.Pitch;
1258 dbuf -= dlock.Pitch;
1259 memcpy(dbuf, sbuf, width);
1262 else /* src and dst overlapping on the same line, use memmove */
1264 for (y = 0; y < dstheight; y++)
1266 memmove(dbuf, sbuf, width);
1267 sbuf += slock.Pitch;
1268 dbuf += dlock.Pitch;
1272 /* Stretching in Y direction only */
1273 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1274 sbuf = sbase + (sy >> 16) * slock.Pitch;
1275 memcpy(dbuf, sbuf, width);
1276 dbuf += dlock.Pitch;
1282 /* Stretching in X direction */
1284 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1286 sbuf = sbase + (sy >> 16) * slock.Pitch;
1288 if ((sy >> 16) == (last_sy >> 16))
1290 /* this sourcerow is the same as last sourcerow -
1291 * copy already stretched row
1293 memcpy(dbuf, dbuf - dlock.Pitch, width);
1297 #define STRETCH_ROW(type) { \
1298 const type *s = (const type *)sbuf; \
1299 type *d = (type *)dbuf; \
1300 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1301 d[x] = s[sx >> 16]; \
1306 case 1: STRETCH_ROW(BYTE)
1307 case 2: STRETCH_ROW(WORD)
1308 case 4: STRETCH_ROW(DWORD)
1313 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1317 s = sbuf+3*(sx>>16);
1318 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1319 d[0] = (pixel )&0xff;
1320 d[1] = (pixel>> 8)&0xff;
1321 d[2] = (pixel>>16)&0xff;
1327 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1328 ret = WINED3DERR_NOTAVAILABLE;
1333 dbuf += dlock.Pitch;
1340 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1341 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1342 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1343 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1345 /* The color keying flags are checked for correctness in ddraw */
1346 if (Flags & WINEDDBLT_KEYSRC)
1348 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1349 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1351 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1353 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1354 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1357 if (Flags & WINEDDBLT_KEYDEST)
1359 /* Destination color keys are taken from the source surface ! */
1360 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1361 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1363 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1365 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1366 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1375 keymask = sEntry->red_mask
1376 | sEntry->green_mask
1377 | sEntry->blue_mask;
1379 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1382 if (Flags & WINEDDBLT_DDFX)
1384 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1387 dTopRight = dbuf+((dstwidth-1)*bpp);
1388 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1389 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1391 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1393 /* I don't think we need to do anything about this flag */
1394 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1396 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1399 dTopRight = dTopLeft;
1402 dBottomRight = dBottomLeft;
1404 dstxinc = dstxinc *-1;
1406 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1409 dTopLeft = dBottomLeft;
1412 dTopRight = dBottomRight;
1414 dstyinc = dstyinc *-1;
1416 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1418 /* I don't think we need to do anything about this flag */
1419 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1421 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1424 dBottomRight = dTopLeft;
1427 dBottomLeft = dTopRight;
1429 dstxinc = dstxinc * -1;
1430 dstyinc = dstyinc * -1;
1432 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1435 dTopLeft = dBottomLeft;
1436 dBottomLeft = dBottomRight;
1437 dBottomRight = dTopRight;
1442 dstxinc = dstxinc * -1;
1444 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1447 dTopLeft = dTopRight;
1448 dTopRight = dBottomRight;
1449 dBottomRight = dBottomLeft;
1454 dstyinc = dstyinc * -1;
1456 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1458 /* I don't think we need to do anything about this flag */
1459 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1462 Flags &= ~(WINEDDBLT_DDFX);
1465 #define COPY_COLORKEY_FX(type) { \
1467 type *d = (type *)dbuf, *dx, tmp; \
1468 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1469 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1471 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1472 tmp = s[sx >> 16]; \
1473 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1474 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1477 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1479 d = (type*)(((LPBYTE)d)+dstyinc); \
1484 case 1: COPY_COLORKEY_FX(BYTE)
1485 case 2: COPY_COLORKEY_FX(WORD)
1486 case 4: COPY_COLORKEY_FX(DWORD)
1490 BYTE *d = dbuf, *dx;
1491 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1493 sbuf = sbase + (sy >> 16) * slock.Pitch;
1495 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1497 DWORD pixel, dpixel = 0;
1498 s = sbuf+3*(sx>>16);
1499 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1500 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1501 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1502 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1504 dx[0] = (pixel )&0xff;
1505 dx[1] = (pixel>> 8)&0xff;
1506 dx[2] = (pixel>>16)&0xff;
1515 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1516 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1517 ret = WINED3DERR_NOTAVAILABLE;
1519 #undef COPY_COLORKEY_FX
1525 if (Flags && FIXME_ON(d3d_surface))
1527 FIXME("\tUnsupported flags: %08x\n", Flags);
1531 IWineD3DSurface_UnlockRect(iface);
1532 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1533 /* Release the converted surface if any */
1534 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1538 /*****************************************************************************
1539 * IWineD3DSurface::BltFast, SW emulation version
1541 * This is the software implementation of BltFast, as used by GDI surfaces
1542 * and as a fallback for OpenGL surfaces. This code is taken from the old
1543 * DirectDraw code, and was originally written by TransGaming.
1548 * Source: Source surface to copy from
1549 * rsrc: Source rectangle
1553 * WINED3D_OK on success
1555 *****************************************************************************/
1556 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1557 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1559 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1560 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1562 int bpp, w, h, x, y;
1563 WINED3DLOCKED_RECT dlock,slock;
1564 HRESULT ret = WINED3D_OK;
1566 RECT lock_src, lock_dst, lock_union;
1569 const struct GlPixelFormatDesc *sEntry, *dEntry;
1571 if (TRACE_ON(d3d_surface))
1573 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1577 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1578 rsrc->right,rsrc->bottom);
1582 TRACE(" srcrect: NULL\n");
1586 if ((This->Flags & SFLAG_LOCKED) ||
1587 (Src->Flags & SFLAG_LOCKED))
1589 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1590 return WINEDDERR_SURFACEBUSY;
1595 WARN("rsrc is NULL!\n");
1598 rsrc2.right = Src->currentDesc.Width;
1599 rsrc2.bottom = Src->currentDesc.Height;
1603 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1604 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1605 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1606 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1607 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1608 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1610 WARN("Application gave us bad source rectangle for BltFast.\n");
1611 return WINEDDERR_INVALIDRECT;
1614 h = rsrc->bottom - rsrc->top;
1615 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1616 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1617 if (h <= 0) return WINEDDERR_INVALIDRECT;
1619 w = rsrc->right - rsrc->left;
1620 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1621 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1622 if (w <= 0) return WINEDDERR_INVALIDRECT;
1624 /* Now compute the locking rectangle... */
1625 lock_src.left = rsrc->left;
1626 lock_src.top = rsrc->top;
1627 lock_src.right = lock_src.left + w;
1628 lock_src.bottom = lock_src.top + h;
1630 lock_dst.left = dstx;
1631 lock_dst.top = dsty;
1632 lock_dst.right = dstx + w;
1633 lock_dst.bottom = dsty + h;
1635 bpp = This->bytesPerPixel;
1637 /* We need to lock the surfaces, or we won't get refreshes when done. */
1642 UnionRect(&lock_union, &lock_src, &lock_dst);
1644 /* Lock the union of the two rectangles */
1645 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1646 if(ret != WINED3D_OK) goto error;
1648 pitch = dlock.Pitch;
1649 slock.Pitch = dlock.Pitch;
1651 /* Since slock was originally copied from this surface's description, we can just reuse it */
1652 assert(This->resource.allocatedMemory != NULL);
1653 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1654 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1655 sEntry = Src->resource.format_desc;
1660 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1661 if(ret != WINED3D_OK) goto error;
1662 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1663 if(ret != WINED3D_OK) goto error;
1667 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1669 sEntry = Src->resource.format_desc;
1670 dEntry = This->resource.format_desc;
1673 /* Handle first the FOURCC surfaces... */
1674 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1676 TRACE("Fourcc -> Fourcc copy\n");
1678 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1680 FIXME("offset for destination surface is not supported\n");
1681 if (Src->resource.format != This->resource.format)
1683 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1684 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1687 /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1688 memcpy(dbuf, sbuf, This->resource.size);
1691 if ((sEntry->Flags & WINED3DFMT_FLAG_FOURCC) && !(dEntry->Flags & WINED3DFMT_FLAG_FOURCC))
1693 /* TODO: Use the libtxc_dxtn.so shared library to do
1694 * software decompression
1696 ERR("DXTC decompression not supported by now\n");
1700 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1702 DWORD keylow, keyhigh;
1703 TRACE("Color keyed copy\n");
1704 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1706 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1707 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1711 /* I'm not sure if this is correct */
1712 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1713 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1714 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1717 #define COPYBOX_COLORKEY(type) { \
1718 const type *s = (const type *)sbuf; \
1719 type *d = (type *)dbuf; \
1721 for (y = 0; y < h; y++) { \
1722 for (x = 0; x < w; x++) { \
1724 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1726 s = (const type *)((const BYTE *)s + slock.Pitch); \
1727 d = (type *)((BYTE *)d + dlock.Pitch); \
1733 case 1: COPYBOX_COLORKEY(BYTE)
1734 case 2: COPYBOX_COLORKEY(WORD)
1735 case 4: COPYBOX_COLORKEY(DWORD)
1743 for (y = 0; y < h; y++)
1745 for (x = 0; x < w * 3; x += 3)
1747 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1748 if (tmp < keylow || tmp > keyhigh)
1750 d[x + 0] = s[x + 0];
1751 d[x + 1] = s[x + 1];
1752 d[x + 2] = s[x + 2];
1761 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1762 ret = WINED3DERR_NOTAVAILABLE;
1765 #undef COPYBOX_COLORKEY
1766 TRACE("Copy Done\n");
1770 int width = w * bpp;
1771 INT sbufpitch, dbufpitch;
1773 TRACE("NO color key copy\n");
1774 /* Handle overlapping surfaces */
1777 sbuf += (h - 1) * slock.Pitch;
1778 dbuf += (h - 1) * dlock.Pitch;
1779 sbufpitch = -slock.Pitch;
1780 dbufpitch = -dlock.Pitch;
1784 sbufpitch = slock.Pitch;
1785 dbufpitch = dlock.Pitch;
1787 for (y = 0; y < h; y++)
1789 /* This is pretty easy, a line for line memcpy */
1790 memmove(dbuf, sbuf, width);
1794 TRACE("Copy done\n");
1800 IWineD3DSurface_UnlockRect(iface);
1804 IWineD3DSurface_UnlockRect(iface);
1805 IWineD3DSurface_UnlockRect(Source);
1811 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1813 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1815 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1816 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1818 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1822 pLockedRect->pBits = This->resource.allocatedMemory;
1823 This->lockedRect.left = 0;
1824 This->lockedRect.top = 0;
1825 This->lockedRect.right = This->currentDesc.Width;
1826 This->lockedRect.bottom = This->currentDesc.Height;
1828 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1829 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1830 This->lockedRect.right, This->lockedRect.bottom);
1834 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1835 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1837 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1838 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1839 * slightly different meaning compared to regular textures. For DXTn
1840 * textures Pitch is the size of a row of blocks, 4 high and "width"
1841 * long. The x offset is calculated differently as well, since moving 4
1842 * pixels to the right actually moves an entire 4x4 block to right, ie
1843 * 16 bytes (8 in case of DXT1). */
1844 if (This->resource.format == WINED3DFMT_DXT1)
1846 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1848 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
1849 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5)
1851 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1855 pLockedRect->pBits = This->resource.allocatedMemory +
1856 (pLockedRect->Pitch * pRect->top) +
1857 (pRect->left * This->bytesPerPixel);
1859 This->lockedRect.left = pRect->left;
1860 This->lockedRect.top = pRect->top;
1861 This->lockedRect.right = pRect->right;
1862 This->lockedRect.bottom = pRect->bottom;
1865 /* No dirtifying is needed for this surface implementation */
1866 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1871 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1872 ERR("Should not be called on base texture\n");
1876 /* TODO: think about moving this down to resource? */
1877 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1879 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1881 /* This should only be called for sysmem textures, it may be a good idea
1882 * to extend this to all pools at some point in the future */
1883 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1885 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1887 return This->resource.allocatedMemory;