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_desc->format;
185 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
186 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
187 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
188 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
189 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
190 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
191 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
192 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
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;
335 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
337 TRACE("(%p)\n", This);
339 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
341 /* Since compressed formats are block based, pitch means the amount of
342 * bytes to the next row of block rather than the next row of pixels. */
343 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
344 ret = row_block_count * format_desc->block_byte_count;
348 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
349 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
350 ret = (ret + alignment - 1) & ~(alignment - 1);
352 TRACE("(%p) Returning %d\n", This, ret);
356 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
357 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
360 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
362 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
364 TRACE("(%p): Not an overlay surface\n", This);
365 return WINEDDERR_NOTAOVERLAYSURFACE;
368 w = This->overlay_destrect.right - This->overlay_destrect.left;
369 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
370 This->overlay_destrect.left = X;
371 This->overlay_destrect.top = Y;
372 This->overlay_destrect.right = X + w;
373 This->overlay_destrect.bottom = Y + h;
375 IWineD3DSurface_DrawOverlay(iface);
380 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
381 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
384 TRACE("(%p)->(%p,%p)\n", This, X, Y);
386 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
388 TRACE("(%p): Not an overlay surface\n", This);
389 return WINEDDERR_NOTAOVERLAYSURFACE;
391 if(This->overlay_dest == NULL) {
393 hr = WINEDDERR_OVERLAYNOTVISIBLE;
395 *X = This->overlay_destrect.left;
396 *Y = This->overlay_destrect.top;
400 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
404 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
406 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
408 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
410 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
412 TRACE("(%p): Not an overlay surface\n", This);
413 return WINEDDERR_NOTAOVERLAYSURFACE;
419 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
420 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
422 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
423 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
424 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
426 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
428 WARN("(%p): Not an overlay surface\n", This);
429 return WINEDDERR_NOTAOVERLAYSURFACE;
430 } else if(!DstSurface) {
431 WARN("(%p): Dest surface is NULL\n", This);
432 return WINED3DERR_INVALIDCALL;
436 This->overlay_srcrect = *SrcRect;
438 This->overlay_srcrect.left = 0;
439 This->overlay_srcrect.top = 0;
440 This->overlay_srcrect.right = This->currentDesc.Width;
441 This->overlay_srcrect.bottom = This->currentDesc.Height;
445 This->overlay_destrect = *DstRect;
447 This->overlay_destrect.left = 0;
448 This->overlay_destrect.top = 0;
449 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
450 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
453 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
454 list_remove(&This->overlay_entry);
457 if(Flags & WINEDDOVER_SHOW) {
458 if(This->overlay_dest != Dst) {
459 This->overlay_dest = Dst;
460 list_add_tail(&Dst->overlays, &This->overlay_entry);
462 } else if(Flags & WINEDDOVER_HIDE) {
463 /* tests show that the rectangles are erased on hide */
464 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
465 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
466 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
467 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
468 This->overlay_dest = NULL;
471 IWineD3DSurface_DrawOverlay(iface);
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 This->clipper = clipper;
485 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
487 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
488 TRACE("(%p)->(%p)\n", This, clipper);
490 *clipper = This->clipper;
492 IWineD3DClipper_AddRef(*clipper);
497 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
498 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
500 TRACE("This %p, container %p\n", This, container);
502 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
504 TRACE("Setting container to %p from %p\n", container, This->container);
505 This->container = container;
510 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
511 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
512 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
513 &This->resource.wineD3DDevice->adapter->gl_info);
515 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
517 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
518 return WINED3DERR_INVALIDCALL;
521 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
523 This->resource.size = surface_calculate_size(format_desc, This->resource.wineD3DDevice->surface_alignment,
524 This->pow2Width, This->pow2Height);
526 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
528 This->resource.format_desc = format_desc;
530 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
535 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
536 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
537 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
545 switch (format_desc->byte_count)
549 /* Allocate extra space to store the RGB bit masks. */
550 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
554 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
558 /* Allocate extra space for a palette. */
559 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
560 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
565 return E_OUTOFMEMORY;
567 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
568 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
569 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
570 * add an extra line to the dib section
572 GetSystemInfo(&sysInfo);
573 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
575 TRACE("Adding an extra line to the dib section\n");
578 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
579 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
580 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
581 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
582 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
583 b_info->bmiHeader.biPlanes = 1;
584 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
586 b_info->bmiHeader.biXPelsPerMeter = 0;
587 b_info->bmiHeader.biYPelsPerMeter = 0;
588 b_info->bmiHeader.biClrUsed = 0;
589 b_info->bmiHeader.biClrImportant = 0;
591 /* Get the bit masks */
592 masks = (DWORD *)b_info->bmiColors;
593 switch (This->resource.format_desc->format)
595 case WINED3DFMT_R8G8B8:
596 usage = DIB_RGB_COLORS;
597 b_info->bmiHeader.biCompression = BI_RGB;
600 case WINED3DFMT_X1R5G5B5:
601 case WINED3DFMT_A1R5G5B5:
602 case WINED3DFMT_A4R4G4B4:
603 case WINED3DFMT_X4R4G4B4:
604 case WINED3DFMT_R3G3B2:
605 case WINED3DFMT_A8R3G3B2:
606 case WINED3DFMT_R10G10B10A2_UNORM:
607 case WINED3DFMT_R8G8B8A8_UNORM:
608 case WINED3DFMT_X8B8G8R8:
609 case WINED3DFMT_A2R10G10B10:
610 case WINED3DFMT_R5G6B5:
611 case WINED3DFMT_R16G16B16A16_UNORM:
613 b_info->bmiHeader.biCompression = BI_BITFIELDS;
614 masks[0] = format_desc->red_mask;
615 masks[1] = format_desc->green_mask;
616 masks[2] = format_desc->blue_mask;
620 /* Don't know palette */
621 b_info->bmiHeader.biCompression = BI_RGB;
628 HeapFree(GetProcessHeap(), 0, b_info);
629 return HRESULT_FROM_WIN32(GetLastError());
632 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
633 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
636 if (!This->dib.DIBsection) {
637 ERR("CreateDIBSection failed!\n");
638 HeapFree(GetProcessHeap(), 0, b_info);
639 return HRESULT_FROM_WIN32(GetLastError());
642 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
643 /* copy the existing surface to the dib section */
644 if(This->resource.allocatedMemory) {
645 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
647 /* This is to make LockRect read the gl Texture although memory is allocated */
648 This->Flags &= ~SFLAG_INSYSMEM;
650 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
652 HeapFree(GetProcessHeap(), 0, b_info);
654 /* Now allocate a HDC */
655 This->hDC = CreateCompatibleDC(0);
656 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
657 TRACE("using wined3d palette %p\n", This->palette);
658 SelectPalette(This->hDC,
659 This->palette ? This->palette->hpal : 0,
662 This->Flags |= SFLAG_DIBSECTION;
664 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
665 This->resource.heapMemory = NULL;
670 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
671 unsigned int w, unsigned int h)
675 unsigned short *dst_s;
677 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
678 for(y = 0; y < h; y++) {
679 src_f = (const float *)(src + y * pitch_in);
680 dst_s = (unsigned short *) (dst + y * pitch_out);
681 for(x = 0; x < w; x++) {
682 dst_s[x] = float_32_to_16(src_f + x);
687 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
688 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
690 static const unsigned char convert_5to8[] =
692 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
693 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
694 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
695 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
697 static const unsigned char convert_6to8[] =
699 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
700 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
701 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
702 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
703 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
704 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
705 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
706 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
710 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
712 for (y = 0; y < h; ++y)
714 const WORD *src_line = (const WORD *)(src + y * pitch_in);
715 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
716 for (x = 0; x < w; ++x)
718 WORD pixel = src_line[x];
719 dst_line[x] = 0xff000000
720 | convert_5to8[(pixel & 0xf800) >> 11] << 16
721 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
722 | convert_5to8[(pixel & 0x001f)];
727 struct d3dfmt_convertor_desc {
728 WINED3DFORMAT from, to;
729 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
732 static const struct d3dfmt_convertor_desc convertors[] =
734 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
735 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
738 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
741 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
742 if(convertors[i].from == from && convertors[i].to == to) {
743 return &convertors[i];
749 /*****************************************************************************
750 * surface_convert_format
752 * Creates a duplicate of a surface in a different format. Is used by Blt to
753 * blit between surfaces with different formats
756 * source: Source surface
757 * fmt: Requested destination format
759 *****************************************************************************/
760 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
761 IWineD3DSurface *ret = NULL;
762 const struct d3dfmt_convertor_desc *conv;
763 WINED3DLOCKED_RECT lock_src, lock_dst;
766 conv = find_convertor(source->resource.format_desc->format, to_fmt);
768 FIXME("Cannot find a conversion function from format %s to %s\n",
769 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
773 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice, source->currentDesc.Width,
774 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
775 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
776 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
778 ERR("Failed to create a destination surface for conversion\n");
782 memset(&lock_src, 0, sizeof(lock_src));
783 memset(&lock_dst, 0, sizeof(lock_dst));
785 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
787 ERR("Failed to lock the source surface\n");
788 IWineD3DSurface_Release(ret);
791 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
793 ERR("Failed to lock the dest surface\n");
794 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
795 IWineD3DSurface_Release(ret);
799 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
800 source->currentDesc.Width, source->currentDesc.Height);
802 IWineD3DSurface_UnlockRect(ret);
803 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
805 return (IWineD3DSurfaceImpl *) ret;
808 /*****************************************************************************
811 * Helper function that fills a memory area with a specific color
814 * buf: memory address to start filling at
815 * width, height: Dimensions of the area to fill
816 * bpp: Bit depth of the surface
817 * lPitch: pitch of the surface
818 * color: Color to fill with
820 *****************************************************************************/
822 _Blt_ColorFill(BYTE *buf,
823 int width, int height,
824 int bpp, LONG lPitch,
832 #define COLORFILL_ROW(type) \
834 type *d = (type *) buf; \
835 for (x = 0; x < width; x++) \
836 d[x] = (type) color; \
841 case 1: COLORFILL_ROW(BYTE)
842 case 2: COLORFILL_ROW(WORD)
846 for (x = 0; x < width; x++,d+=3)
848 d[0] = (color ) & 0xFF;
849 d[1] = (color>> 8) & 0xFF;
850 d[2] = (color>>16) & 0xFF;
854 case 4: COLORFILL_ROW(DWORD)
856 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
857 return WINED3DERR_NOTAVAILABLE;
862 /* Now copy first row */
864 for (y = 1; y < height; y++)
867 memcpy(buf, first, width * bpp);
872 /*****************************************************************************
873 * IWineD3DSurface::Blt, SW emulation version
875 * Performs blits to a surface, eigher from a source of source-less blts
876 * This is the main functionality of DirectDraw
879 * DestRect: Destination rectangle to write to
880 * SrcSurface: Source surface, can be NULL
881 * SrcRect: Source rectangle
882 *****************************************************************************/
883 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
884 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
886 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
887 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
889 HRESULT ret = WINED3D_OK;
890 WINED3DLOCKED_RECT dlock, slock;
891 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
892 const struct GlPixelFormatDesc *sEntry, *dEntry;
896 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
898 if (TRACE_ON(d3d_surface))
900 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
901 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
902 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
903 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
906 DDRAW_dump_DDBLT(Flags);
907 if (Flags & WINEDDBLT_DDFX)
910 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
915 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
917 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
918 return WINEDDERR_SURFACEBUSY;
921 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
922 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
923 FIXME("Filters not supported in software blit\n");
926 /* First check for the validity of source / destination rectangles. This was
927 * verified using a test application + by MSDN.
929 if ((Src != NULL) && (SrcRect != NULL) &&
930 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
931 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
932 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
933 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
934 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
936 WARN("Application gave us bad source rectangle for Blt.\n");
937 return WINEDDERR_INVALIDRECT;
939 /* For the Destination rect, it can be out of bounds on the condition that a clipper
940 * is set for the given surface.
942 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
943 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
944 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
945 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
946 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
947 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
949 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
950 return WINEDDERR_INVALIDRECT;
953 /* Now handle negative values in the rectangles. Warning: only supported for now
954 in the 'simple' cases (ie not in any stretching / rotation cases).
956 First, the case where nothing is to be done.
958 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
959 (DestRect->top >= (int) This->currentDesc.Height) ||
960 (DestRect->left >= (int) This->currentDesc.Width))) ||
961 ((Src != NULL) && (SrcRect != NULL) &&
962 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
963 (SrcRect->top >= (int) Src->currentDesc.Height) ||
964 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
966 TRACE("Nothing to be done !\n");
977 xdst.bottom = This->currentDesc.Height;
979 xdst.right = This->currentDesc.Width;
991 xsrc.bottom = Src->currentDesc.Height;
993 xsrc.right = Src->currentDesc.Width;
997 memset(&xsrc,0,sizeof(xsrc));
1001 /* The easy case : the source-less blits.... */
1002 if (Src == NULL && DestRect)
1005 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1009 full_rect.right = This->currentDesc.Width;
1010 full_rect.bottom = This->currentDesc.Height;
1011 IntersectRect(&temp_rect, &full_rect, DestRect);
1016 /* Only handle clipping on the destination rectangle */
1017 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1018 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1019 if (clip_vert || clip_horiz)
1021 /* Now check if this is a special case or not... */
1022 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1023 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1024 (Flags & WINEDDBLT_DDFX))
1026 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1032 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1033 if (DestRect->right > This->currentDesc.Width)
1035 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1036 xdst.right = (int) This->currentDesc.Width;
1041 if (DestRect->top < 0)
1043 xsrc.top -= DestRect->top;
1046 if (DestRect->bottom > This->currentDesc.Height)
1048 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1049 xdst.bottom = (int) This->currentDesc.Height;
1052 /* And check if after clipping something is still to be done... */
1053 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1054 (xdst.top >= (int) This->currentDesc.Height) ||
1055 (xdst.left >= (int) This->currentDesc.Width) ||
1056 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1057 (xsrc.top >= (int) Src->currentDesc.Height) ||
1058 (xsrc.left >= (int) Src->currentDesc.Width))
1060 TRACE("Nothing to be done after clipping !\n");
1068 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1070 sEntry = This->resource.format_desc;
1075 dEntry = This->resource.format_desc;
1078 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1080 Src = surface_convert_format(Src, dEntry->format);
1082 /* The conv function writes a FIXME */
1083 WARN("Cannot convert source surface format to dest format\n");
1087 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1088 sEntry = Src->resource.format_desc;
1095 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1097 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1100 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1102 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1104 if (!DestRect || Src == This)
1106 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1111 bpp = This->resource.format_desc->byte_count;
1112 srcheight = xsrc.bottom - xsrc.top;
1113 srcwidth = xsrc.right - xsrc.left;
1114 dstheight = xdst.bottom - xdst.top;
1115 dstwidth = xdst.right - xdst.left;
1116 width = (xdst.right - xdst.left) * bpp;
1118 assert(width <= dlock.Pitch);
1120 if (DestRect && Src != This)
1123 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1125 if (Flags & WINEDDBLT_WAIT)
1127 Flags &= ~WINEDDBLT_WAIT;
1129 if (Flags & WINEDDBLT_ASYNC)
1131 static BOOL displayed = FALSE;
1133 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1135 Flags &= ~WINEDDBLT_ASYNC;
1137 if (Flags & WINEDDBLT_DONOTWAIT)
1139 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1140 static BOOL displayed = FALSE;
1142 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1144 Flags &= ~WINEDDBLT_DONOTWAIT;
1147 /* First, all the 'source-less' blits */
1148 if (Flags & WINEDDBLT_COLORFILL)
1150 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1151 dlock.Pitch, DDBltFx->u5.dwFillColor);
1152 Flags &= ~WINEDDBLT_COLORFILL;
1155 if (Flags & WINEDDBLT_DEPTHFILL)
1157 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1159 if (Flags & WINEDDBLT_ROP)
1161 /* Catch some degenerate cases here */
1162 switch(DDBltFx->dwROP)
1165 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1167 case 0xAA0029: /* No-op */
1170 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1172 case SRCCOPY: /* well, we do that below ? */
1175 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1178 Flags &= ~WINEDDBLT_ROP;
1180 if (Flags & WINEDDBLT_DDROPS)
1182 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1184 /* Now the 'with source' blits */
1188 int sx, xinc, sy, yinc;
1190 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1192 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1193 xinc = (srcwidth << 16) / dstwidth;
1194 yinc = (srcheight << 16) / dstheight;
1198 /* No effects, we can cheat here */
1199 if (dstwidth == srcwidth)
1201 if (dstheight == srcheight)
1203 /* No stretching in either direction. This needs to be as
1204 * fast as possible */
1207 /* check for overlapping surfaces */
1208 if (Src != This || xdst.top < xsrc.top ||
1209 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1211 /* no overlap, or dst above src, so copy from top downwards */
1212 for (y = 0; y < dstheight; y++)
1214 memcpy(dbuf, sbuf, width);
1215 sbuf += slock.Pitch;
1216 dbuf += dlock.Pitch;
1219 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1221 sbuf += (slock.Pitch*dstheight);
1222 dbuf += (dlock.Pitch*dstheight);
1223 for (y = 0; y < dstheight; y++)
1225 sbuf -= slock.Pitch;
1226 dbuf -= dlock.Pitch;
1227 memcpy(dbuf, sbuf, width);
1230 else /* src and dst overlapping on the same line, use memmove */
1232 for (y = 0; y < dstheight; y++)
1234 memmove(dbuf, sbuf, width);
1235 sbuf += slock.Pitch;
1236 dbuf += dlock.Pitch;
1240 /* Stretching in Y direction only */
1241 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1242 sbuf = sbase + (sy >> 16) * slock.Pitch;
1243 memcpy(dbuf, sbuf, width);
1244 dbuf += dlock.Pitch;
1250 /* Stretching in X direction */
1252 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1254 sbuf = sbase + (sy >> 16) * slock.Pitch;
1256 if ((sy >> 16) == (last_sy >> 16))
1258 /* this sourcerow is the same as last sourcerow -
1259 * copy already stretched row
1261 memcpy(dbuf, dbuf - dlock.Pitch, width);
1265 #define STRETCH_ROW(type) { \
1266 const type *s = (const type *)sbuf; \
1267 type *d = (type *)dbuf; \
1268 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1269 d[x] = s[sx >> 16]; \
1274 case 1: STRETCH_ROW(BYTE)
1275 case 2: STRETCH_ROW(WORD)
1276 case 4: STRETCH_ROW(DWORD)
1281 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1285 s = sbuf+3*(sx>>16);
1286 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1287 d[0] = (pixel )&0xff;
1288 d[1] = (pixel>> 8)&0xff;
1289 d[2] = (pixel>>16)&0xff;
1295 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1296 ret = WINED3DERR_NOTAVAILABLE;
1301 dbuf += dlock.Pitch;
1308 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1309 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1310 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1311 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1313 /* The color keying flags are checked for correctness in ddraw */
1314 if (Flags & WINEDDBLT_KEYSRC)
1316 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1317 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1319 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1321 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1322 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1325 if (Flags & WINEDDBLT_KEYDEST)
1327 /* Destination color keys are taken from the source surface ! */
1328 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1329 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1331 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1333 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1334 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1343 keymask = sEntry->red_mask
1344 | sEntry->green_mask
1345 | sEntry->blue_mask;
1347 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1350 if (Flags & WINEDDBLT_DDFX)
1352 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1355 dTopRight = dbuf+((dstwidth-1)*bpp);
1356 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1357 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1359 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1361 /* I don't think we need to do anything about this flag */
1362 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1364 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1367 dTopRight = dTopLeft;
1370 dBottomRight = dBottomLeft;
1372 dstxinc = dstxinc *-1;
1374 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1377 dTopLeft = dBottomLeft;
1380 dTopRight = dBottomRight;
1382 dstyinc = dstyinc *-1;
1384 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1386 /* I don't think we need to do anything about this flag */
1387 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1389 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1392 dBottomRight = dTopLeft;
1395 dBottomLeft = dTopRight;
1397 dstxinc = dstxinc * -1;
1398 dstyinc = dstyinc * -1;
1400 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1403 dTopLeft = dBottomLeft;
1404 dBottomLeft = dBottomRight;
1405 dBottomRight = dTopRight;
1410 dstxinc = dstxinc * -1;
1412 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1415 dTopLeft = dTopRight;
1416 dTopRight = dBottomRight;
1417 dBottomRight = dBottomLeft;
1422 dstyinc = dstyinc * -1;
1424 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1426 /* I don't think we need to do anything about this flag */
1427 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1430 Flags &= ~(WINEDDBLT_DDFX);
1433 #define COPY_COLORKEY_FX(type) { \
1435 type *d = (type *)dbuf, *dx, tmp; \
1436 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1437 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1439 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1440 tmp = s[sx >> 16]; \
1441 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1442 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1445 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1447 d = (type*)(((LPBYTE)d)+dstyinc); \
1452 case 1: COPY_COLORKEY_FX(BYTE)
1453 case 2: COPY_COLORKEY_FX(WORD)
1454 case 4: COPY_COLORKEY_FX(DWORD)
1458 BYTE *d = dbuf, *dx;
1459 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1461 sbuf = sbase + (sy >> 16) * slock.Pitch;
1463 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1465 DWORD pixel, dpixel = 0;
1466 s = sbuf+3*(sx>>16);
1467 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1468 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1469 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1470 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1472 dx[0] = (pixel )&0xff;
1473 dx[1] = (pixel>> 8)&0xff;
1474 dx[2] = (pixel>>16)&0xff;
1483 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1484 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1485 ret = WINED3DERR_NOTAVAILABLE;
1487 #undef COPY_COLORKEY_FX
1493 if (Flags && FIXME_ON(d3d_surface))
1495 FIXME("\tUnsupported flags: %08x\n", Flags);
1499 IWineD3DSurface_UnlockRect(iface);
1500 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1501 /* Release the converted surface if any */
1502 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1506 /*****************************************************************************
1507 * IWineD3DSurface::BltFast, SW emulation version
1509 * This is the software implementation of BltFast, as used by GDI surfaces
1510 * and as a fallback for OpenGL surfaces. This code is taken from the old
1511 * DirectDraw code, and was originally written by TransGaming.
1516 * Source: Source surface to copy from
1517 * rsrc: Source rectangle
1521 * WINED3D_OK on success
1523 *****************************************************************************/
1524 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1525 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1527 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1528 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1530 int bpp, w, h, x, y;
1531 WINED3DLOCKED_RECT dlock,slock;
1532 HRESULT ret = WINED3D_OK;
1534 RECT lock_src, lock_dst, lock_union;
1537 const struct GlPixelFormatDesc *sEntry, *dEntry;
1539 if (TRACE_ON(d3d_surface))
1541 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1545 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1546 rsrc->right,rsrc->bottom);
1550 TRACE(" srcrect: NULL\n");
1554 if ((This->Flags & SFLAG_LOCKED) ||
1555 (Src->Flags & SFLAG_LOCKED))
1557 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1558 return WINEDDERR_SURFACEBUSY;
1563 WARN("rsrc is NULL!\n");
1566 rsrc2.right = Src->currentDesc.Width;
1567 rsrc2.bottom = Src->currentDesc.Height;
1571 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1572 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1573 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1574 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1575 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1576 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1578 WARN("Application gave us bad source rectangle for BltFast.\n");
1579 return WINEDDERR_INVALIDRECT;
1582 h = rsrc->bottom - rsrc->top;
1583 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1584 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1585 if (h <= 0) return WINEDDERR_INVALIDRECT;
1587 w = rsrc->right - rsrc->left;
1588 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1589 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1590 if (w <= 0) return WINEDDERR_INVALIDRECT;
1592 /* Now compute the locking rectangle... */
1593 lock_src.left = rsrc->left;
1594 lock_src.top = rsrc->top;
1595 lock_src.right = lock_src.left + w;
1596 lock_src.bottom = lock_src.top + h;
1598 lock_dst.left = dstx;
1599 lock_dst.top = dsty;
1600 lock_dst.right = dstx + w;
1601 lock_dst.bottom = dsty + h;
1603 bpp = This->resource.format_desc->byte_count;
1605 /* We need to lock the surfaces, or we won't get refreshes when done. */
1610 UnionRect(&lock_union, &lock_src, &lock_dst);
1612 /* Lock the union of the two rectangles */
1613 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1614 if(ret != WINED3D_OK) goto error;
1616 pitch = dlock.Pitch;
1617 slock.Pitch = dlock.Pitch;
1619 /* Since slock was originally copied from this surface's description, we can just reuse it */
1620 assert(This->resource.allocatedMemory != NULL);
1621 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1622 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1623 sEntry = Src->resource.format_desc;
1628 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1629 if(ret != WINED3D_OK) goto error;
1630 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1631 if(ret != WINED3D_OK) goto error;
1635 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1637 sEntry = Src->resource.format_desc;
1638 dEntry = This->resource.format_desc;
1641 /* Handle compressed surfaces first... */
1642 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1644 UINT row_block_count;
1646 TRACE("compressed -> compressed copy\n");
1648 FIXME("trans arg not supported when a compressed surface is involved\n");
1650 FIXME("offset for destination surface is not supported\n");
1651 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1653 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1654 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1658 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1659 for (y = 0; y < h; y += dEntry->block_height)
1661 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1662 dbuf += dlock.Pitch;
1663 sbuf += slock.Pitch;
1668 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1670 /* TODO: Use the libtxc_dxtn.so shared library to do
1671 * software decompression
1673 ERR("Software decompression not supported.\n");
1677 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1679 DWORD keylow, keyhigh;
1680 TRACE("Color keyed copy\n");
1681 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1683 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1684 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1688 /* I'm not sure if this is correct */
1689 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1690 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1691 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1694 #define COPYBOX_COLORKEY(type) { \
1695 const type *s = (const type *)sbuf; \
1696 type *d = (type *)dbuf; \
1698 for (y = 0; y < h; y++) { \
1699 for (x = 0; x < w; x++) { \
1701 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1703 s = (const type *)((const BYTE *)s + slock.Pitch); \
1704 d = (type *)((BYTE *)d + dlock.Pitch); \
1710 case 1: COPYBOX_COLORKEY(BYTE)
1711 case 2: COPYBOX_COLORKEY(WORD)
1712 case 4: COPYBOX_COLORKEY(DWORD)
1720 for (y = 0; y < h; y++)
1722 for (x = 0; x < w * 3; x += 3)
1724 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1725 if (tmp < keylow || tmp > keyhigh)
1727 d[x + 0] = s[x + 0];
1728 d[x + 1] = s[x + 1];
1729 d[x + 2] = s[x + 2];
1738 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1739 ret = WINED3DERR_NOTAVAILABLE;
1742 #undef COPYBOX_COLORKEY
1743 TRACE("Copy Done\n");
1747 int width = w * bpp;
1748 INT sbufpitch, dbufpitch;
1750 TRACE("NO color key copy\n");
1751 /* Handle overlapping surfaces */
1754 sbuf += (h - 1) * slock.Pitch;
1755 dbuf += (h - 1) * dlock.Pitch;
1756 sbufpitch = -slock.Pitch;
1757 dbufpitch = -dlock.Pitch;
1761 sbufpitch = slock.Pitch;
1762 dbufpitch = dlock.Pitch;
1764 for (y = 0; y < h; y++)
1766 /* This is pretty easy, a line for line memcpy */
1767 memmove(dbuf, sbuf, width);
1771 TRACE("Copy done\n");
1777 IWineD3DSurface_UnlockRect(iface);
1781 IWineD3DSurface_UnlockRect(iface);
1782 IWineD3DSurface_UnlockRect(Source);
1788 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1790 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1792 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1793 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1795 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1799 pLockedRect->pBits = This->resource.allocatedMemory;
1800 This->lockedRect.left = 0;
1801 This->lockedRect.top = 0;
1802 This->lockedRect.right = This->currentDesc.Width;
1803 This->lockedRect.bottom = This->currentDesc.Height;
1805 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1806 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1807 This->lockedRect.right, This->lockedRect.bottom);
1811 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1813 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1814 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1816 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1818 /* Compressed textures are block based, so calculate the offset of
1819 * the block that contains the top-left pixel of the locked rectangle. */
1820 pLockedRect->pBits = This->resource.allocatedMemory
1821 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1822 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1826 pLockedRect->pBits = This->resource.allocatedMemory +
1827 (pLockedRect->Pitch * pRect->top) +
1828 (pRect->left * format_desc->byte_count);
1830 This->lockedRect.left = pRect->left;
1831 This->lockedRect.top = pRect->top;
1832 This->lockedRect.right = pRect->right;
1833 This->lockedRect.bottom = pRect->bottom;
1836 /* No dirtifying is needed for this surface implementation */
1837 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1842 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1843 ERR("Should not be called on base texture\n");
1847 /* TODO: think about moving this down to resource? */
1848 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1850 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1852 /* This should only be called for sysmem textures, it may be a good idea
1853 * to extend this to all pools at some point in the future */
1854 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1856 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1858 return This->resource.allocatedMemory;