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"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
35 /* See also float_16_to_32() in wined3d_private.h */
36 static inline unsigned short float_32_to_16(const float *in)
39 float tmp = fabs(*in);
40 unsigned int mantissa;
43 /* Deal with special numbers */
44 if (*in == 0.0f) return 0x0000;
45 if(isnan(*in)) return 0x7C01;
46 if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
48 if(tmp < pow(2, 10)) {
53 }while(tmp < pow(2, 10));
54 } else if(tmp >= pow(2, 11)) {
59 }while(tmp >= pow(2, 11));
62 mantissa = (unsigned int) tmp;
63 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
65 exp += 10; /* Normalize the mantissa */
66 exp += 15; /* Exponent is encoded with excess 15 */
68 if(exp > 30) { /* too big */
69 ret = 0x7c00; /* INF */
71 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
73 mantissa = mantissa >> 1;
76 ret = mantissa & 0x3ff;
78 ret = (exp << 10) | (mantissa & 0x3ff);
81 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
86 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
88 /* *******************************************
89 IWineD3DSurface IUnknown parts follow
90 ******************************************* */
91 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
93 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
94 /* Warn ,but be nice about things */
95 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
97 if (IsEqualGUID(riid, &IID_IUnknown)
98 || IsEqualGUID(riid, &IID_IWineD3DBase)
99 || IsEqualGUID(riid, &IID_IWineD3DResource)
100 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
101 IUnknown_AddRef((IUnknown*)iface);
106 return E_NOINTERFACE;
109 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
110 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
111 ULONG ref = InterlockedIncrement(&This->resource.ref);
112 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
116 /* ****************************************************
117 IWineD3DSurface IWineD3DResource parts follow
118 **************************************************** */
119 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
120 return resource_get_device((IWineD3DResource *)iface, ppDevice);
123 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
124 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
127 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
128 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
131 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
132 return resource_free_private_data((IWineD3DResource *)iface, refguid);
135 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
136 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
139 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
140 return resource_get_priority((IWineD3DResource *)iface);
143 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
144 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
145 return resource_get_type((IWineD3DResource *)iface);
148 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
149 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
150 return resource_get_parent((IWineD3DResource *)iface, pParent);
153 /* ******************************************************
154 IWineD3DSurface IWineD3DSurface parts follow
155 ****************************************************** */
157 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
158 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
159 IWineD3DBase *container = 0;
161 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
164 ERR("Called without a valid ppContainer.\n");
167 /* Standalone surfaces return the device as container. */
168 if (This->container) {
169 container = This->container;
171 container = (IWineD3DBase *)This->resource.wineD3DDevice;
174 TRACE("Relaying to QueryInterface\n");
175 return IUnknown_QueryInterface(container, riid, ppContainer);
178 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
179 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
181 TRACE("(%p) : copying into %p\n", This, pDesc);
183 pDesc->format = This->resource.format_desc->format;
184 pDesc->resource_type = This->resource.resourceType;
185 pDesc->usage = This->resource.usage;
186 pDesc->pool = This->resource.pool;
187 pDesc->size = This->resource.size; /* dx8 only */
188 pDesc->multisample_type = This->currentDesc.MultiSampleType;
189 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
190 pDesc->width = This->currentDesc.Width;
191 pDesc->height = This->currentDesc.Height;
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 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
547 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
548 return WINED3DERR_INVALIDCALL;
551 switch (format_desc->byte_count)
555 /* Allocate extra space to store the RGB bit masks. */
556 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
560 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
564 /* Allocate extra space for a palette. */
565 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
566 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
571 return E_OUTOFMEMORY;
573 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
574 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
575 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
576 * add an extra line to the dib section
578 GetSystemInfo(&sysInfo);
579 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
581 TRACE("Adding an extra line to the dib section\n");
584 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
585 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
586 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
587 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
588 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
589 b_info->bmiHeader.biPlanes = 1;
590 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
592 b_info->bmiHeader.biXPelsPerMeter = 0;
593 b_info->bmiHeader.biYPelsPerMeter = 0;
594 b_info->bmiHeader.biClrUsed = 0;
595 b_info->bmiHeader.biClrImportant = 0;
597 /* Get the bit masks */
598 masks = (DWORD *)b_info->bmiColors;
599 switch (This->resource.format_desc->format)
601 case WINED3DFMT_R8G8B8:
602 usage = DIB_RGB_COLORS;
603 b_info->bmiHeader.biCompression = BI_RGB;
606 case WINED3DFMT_X1R5G5B5:
607 case WINED3DFMT_A1R5G5B5:
608 case WINED3DFMT_A4R4G4B4:
609 case WINED3DFMT_X4R4G4B4:
610 case WINED3DFMT_R3G3B2:
611 case WINED3DFMT_A8R3G3B2:
612 case WINED3DFMT_R10G10B10A2_UNORM:
613 case WINED3DFMT_R8G8B8A8_UNORM:
614 case WINED3DFMT_X8B8G8R8:
615 case WINED3DFMT_A2R10G10B10:
616 case WINED3DFMT_R5G6B5:
617 case WINED3DFMT_R16G16B16A16_UNORM:
619 b_info->bmiHeader.biCompression = BI_BITFIELDS;
620 masks[0] = format_desc->red_mask;
621 masks[1] = format_desc->green_mask;
622 masks[2] = format_desc->blue_mask;
626 /* Don't know palette */
627 b_info->bmiHeader.biCompression = BI_RGB;
634 HeapFree(GetProcessHeap(), 0, b_info);
635 return HRESULT_FROM_WIN32(GetLastError());
638 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);
639 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
642 if (!This->dib.DIBsection) {
643 ERR("CreateDIBSection failed!\n");
644 HeapFree(GetProcessHeap(), 0, b_info);
645 return HRESULT_FROM_WIN32(GetLastError());
648 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
649 /* copy the existing surface to the dib section */
650 if(This->resource.allocatedMemory) {
651 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
653 /* This is to make LockRect read the gl Texture although memory is allocated */
654 This->Flags &= ~SFLAG_INSYSMEM;
656 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
658 HeapFree(GetProcessHeap(), 0, b_info);
660 /* Now allocate a HDC */
661 This->hDC = CreateCompatibleDC(0);
662 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
663 TRACE("using wined3d palette %p\n", This->palette);
664 SelectPalette(This->hDC,
665 This->palette ? This->palette->hpal : 0,
668 This->Flags |= SFLAG_DIBSECTION;
670 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
671 This->resource.heapMemory = NULL;
676 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
677 unsigned int w, unsigned int h)
681 unsigned short *dst_s;
683 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
684 for(y = 0; y < h; y++) {
685 src_f = (const float *)(src + y * pitch_in);
686 dst_s = (unsigned short *) (dst + y * pitch_out);
687 for(x = 0; x < w; x++) {
688 dst_s[x] = float_32_to_16(src_f + x);
693 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
694 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
696 static const unsigned char convert_5to8[] =
698 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
699 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
700 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
701 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
703 static const unsigned char convert_6to8[] =
705 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
706 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
707 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
708 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
709 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
710 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
711 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
712 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
716 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
718 for (y = 0; y < h; ++y)
720 const WORD *src_line = (const WORD *)(src + y * pitch_in);
721 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
722 for (x = 0; x < w; ++x)
724 WORD pixel = src_line[x];
725 dst_line[x] = 0xff000000
726 | convert_5to8[(pixel & 0xf800) >> 11] << 16
727 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
728 | convert_5to8[(pixel & 0x001f)];
733 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
734 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
738 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
740 for (y = 0; y < h; ++y)
742 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
743 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
745 for (x = 0; x < w; ++x)
747 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
752 struct d3dfmt_convertor_desc {
753 WINED3DFORMAT from, to;
754 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
757 static const struct d3dfmt_convertor_desc convertors[] =
759 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
760 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
761 {WINED3DFMT_A8R8G8B8, WINED3DFMT_X8R8G8B8, convert_a8r8g8b8_x8r8g8b8},
764 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
767 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
768 if(convertors[i].from == from && convertors[i].to == to) {
769 return &convertors[i];
775 /*****************************************************************************
776 * surface_convert_format
778 * Creates a duplicate of a surface in a different format. Is used by Blt to
779 * blit between surfaces with different formats
782 * source: Source surface
783 * fmt: Requested destination format
785 *****************************************************************************/
786 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
787 IWineD3DSurface *ret = NULL;
788 const struct d3dfmt_convertor_desc *conv;
789 WINED3DLOCKED_RECT lock_src, lock_dst;
792 conv = find_convertor(source->resource.format_desc->format, to_fmt);
794 FIXME("Cannot find a conversion function from format %s to %s\n",
795 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
799 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice, source->currentDesc.Width,
800 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
801 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
802 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
804 ERR("Failed to create a destination surface for conversion\n");
808 memset(&lock_src, 0, sizeof(lock_src));
809 memset(&lock_dst, 0, sizeof(lock_dst));
811 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
813 ERR("Failed to lock the source surface\n");
814 IWineD3DSurface_Release(ret);
817 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
819 ERR("Failed to lock the dest surface\n");
820 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
821 IWineD3DSurface_Release(ret);
825 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
826 source->currentDesc.Width, source->currentDesc.Height);
828 IWineD3DSurface_UnlockRect(ret);
829 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
831 return (IWineD3DSurfaceImpl *) ret;
834 /*****************************************************************************
837 * Helper function that fills a memory area with a specific color
840 * buf: memory address to start filling at
841 * width, height: Dimensions of the area to fill
842 * bpp: Bit depth of the surface
843 * lPitch: pitch of the surface
844 * color: Color to fill with
846 *****************************************************************************/
848 _Blt_ColorFill(BYTE *buf,
849 int width, int height,
850 int bpp, LONG lPitch,
858 #define COLORFILL_ROW(type) \
860 type *d = (type *) buf; \
861 for (x = 0; x < width; x++) \
862 d[x] = (type) color; \
867 case 1: COLORFILL_ROW(BYTE)
868 case 2: COLORFILL_ROW(WORD)
872 for (x = 0; x < width; x++,d+=3)
874 d[0] = (color ) & 0xFF;
875 d[1] = (color>> 8) & 0xFF;
876 d[2] = (color>>16) & 0xFF;
880 case 4: COLORFILL_ROW(DWORD)
882 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
883 return WINED3DERR_NOTAVAILABLE;
888 /* Now copy first row */
890 for (y = 1; y < height; y++)
893 memcpy(buf, first, width * bpp);
898 /*****************************************************************************
899 * IWineD3DSurface::Blt, SW emulation version
901 * Performs blits to a surface, eigher from a source of source-less blts
902 * This is the main functionality of DirectDraw
905 * DestRect: Destination rectangle to write to
906 * SrcSurface: Source surface, can be NULL
907 * SrcRect: Source rectangle
908 *****************************************************************************/
909 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
910 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
912 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
913 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
915 HRESULT ret = WINED3D_OK;
916 WINED3DLOCKED_RECT dlock, slock;
917 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
918 const struct GlPixelFormatDesc *sEntry, *dEntry;
922 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
924 if (TRACE_ON(d3d_surface))
926 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
927 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
928 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
929 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
932 DDRAW_dump_DDBLT(Flags);
933 if (Flags & WINEDDBLT_DDFX)
936 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
941 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
943 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
944 return WINEDDERR_SURFACEBUSY;
947 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
948 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
949 FIXME("Filters not supported in software blit\n");
952 /* First check for the validity of source / destination rectangles. This was
953 * verified using a test application + by MSDN.
955 if ((Src != NULL) && (SrcRect != NULL) &&
956 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
957 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
958 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
959 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
960 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
962 WARN("Application gave us bad source rectangle for Blt.\n");
963 return WINEDDERR_INVALIDRECT;
965 /* For the Destination rect, it can be out of bounds on the condition that a clipper
966 * is set for the given surface.
968 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
969 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
970 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
971 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
972 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
973 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
975 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
976 return WINEDDERR_INVALIDRECT;
979 /* Now handle negative values in the rectangles. Warning: only supported for now
980 in the 'simple' cases (ie not in any stretching / rotation cases).
982 First, the case where nothing is to be done.
984 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
985 (DestRect->top >= (int) This->currentDesc.Height) ||
986 (DestRect->left >= (int) This->currentDesc.Width))) ||
987 ((Src != NULL) && (SrcRect != NULL) &&
988 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
989 (SrcRect->top >= (int) Src->currentDesc.Height) ||
990 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
992 TRACE("Nothing to be done !\n");
1003 xdst.bottom = This->currentDesc.Height;
1005 xdst.right = This->currentDesc.Width;
1017 xsrc.bottom = Src->currentDesc.Height;
1019 xsrc.right = Src->currentDesc.Width;
1023 memset(&xsrc,0,sizeof(xsrc));
1027 /* The easy case : the source-less blits.... */
1028 if (Src == NULL && DestRect)
1031 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1035 full_rect.right = This->currentDesc.Width;
1036 full_rect.bottom = This->currentDesc.Height;
1037 IntersectRect(&temp_rect, &full_rect, DestRect);
1042 /* Only handle clipping on the destination rectangle */
1043 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1044 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1045 if (clip_vert || clip_horiz)
1047 /* Now check if this is a special case or not... */
1048 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1049 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1050 (Flags & WINEDDBLT_DDFX))
1052 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1058 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1059 if (DestRect->right > This->currentDesc.Width)
1061 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1062 xdst.right = (int) This->currentDesc.Width;
1067 if (DestRect->top < 0)
1069 xsrc.top -= DestRect->top;
1072 if (DestRect->bottom > This->currentDesc.Height)
1074 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1075 xdst.bottom = (int) This->currentDesc.Height;
1078 /* And check if after clipping something is still to be done... */
1079 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1080 (xdst.top >= (int) This->currentDesc.Height) ||
1081 (xdst.left >= (int) This->currentDesc.Width) ||
1082 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1083 (xsrc.top >= (int) Src->currentDesc.Height) ||
1084 (xsrc.left >= (int) Src->currentDesc.Width))
1086 TRACE("Nothing to be done after clipping !\n");
1094 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1096 sEntry = This->resource.format_desc;
1101 dEntry = This->resource.format_desc;
1104 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1106 Src = surface_convert_format(Src, dEntry->format);
1108 /* The conv function writes a FIXME */
1109 WARN("Cannot convert source surface format to dest format\n");
1113 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1114 sEntry = Src->resource.format_desc;
1121 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1123 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1126 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1128 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1130 if (!DestRect || Src == This)
1132 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1137 bpp = This->resource.format_desc->byte_count;
1138 srcheight = xsrc.bottom - xsrc.top;
1139 srcwidth = xsrc.right - xsrc.left;
1140 dstheight = xdst.bottom - xdst.top;
1141 dstwidth = xdst.right - xdst.left;
1142 width = (xdst.right - xdst.left) * bpp;
1144 if (DestRect && Src != This)
1147 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1149 if (Flags & WINEDDBLT_WAIT)
1151 Flags &= ~WINEDDBLT_WAIT;
1153 if (Flags & WINEDDBLT_ASYNC)
1155 static BOOL displayed = FALSE;
1157 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1159 Flags &= ~WINEDDBLT_ASYNC;
1161 if (Flags & WINEDDBLT_DONOTWAIT)
1163 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1164 static BOOL displayed = FALSE;
1166 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1168 Flags &= ~WINEDDBLT_DONOTWAIT;
1171 /* First, all the 'source-less' blits */
1172 if (Flags & WINEDDBLT_COLORFILL)
1174 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1175 dlock.Pitch, DDBltFx->u5.dwFillColor);
1176 Flags &= ~WINEDDBLT_COLORFILL;
1179 if (Flags & WINEDDBLT_DEPTHFILL)
1181 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1183 if (Flags & WINEDDBLT_ROP)
1185 /* Catch some degenerate cases here */
1186 switch(DDBltFx->dwROP)
1189 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1191 case 0xAA0029: /* No-op */
1194 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1196 case SRCCOPY: /* well, we do that below ? */
1199 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1202 Flags &= ~WINEDDBLT_ROP;
1204 if (Flags & WINEDDBLT_DDROPS)
1206 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1208 /* Now the 'with source' blits */
1212 int sx, xinc, sy, yinc;
1214 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1216 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1217 xinc = (srcwidth << 16) / dstwidth;
1218 yinc = (srcheight << 16) / dstheight;
1222 /* No effects, we can cheat here */
1223 if (dstwidth == srcwidth)
1225 if (dstheight == srcheight)
1227 /* No stretching in either direction. This needs to be as
1228 * fast as possible */
1231 /* check for overlapping surfaces */
1232 if (Src != This || xdst.top < xsrc.top ||
1233 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1235 /* no overlap, or dst above src, so copy from top downwards */
1236 for (y = 0; y < dstheight; y++)
1238 memcpy(dbuf, sbuf, width);
1239 sbuf += slock.Pitch;
1240 dbuf += dlock.Pitch;
1243 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1245 sbuf += (slock.Pitch*dstheight);
1246 dbuf += (dlock.Pitch*dstheight);
1247 for (y = 0; y < dstheight; y++)
1249 sbuf -= slock.Pitch;
1250 dbuf -= dlock.Pitch;
1251 memcpy(dbuf, sbuf, width);
1254 else /* src and dst overlapping on the same line, use memmove */
1256 for (y = 0; y < dstheight; y++)
1258 memmove(dbuf, sbuf, width);
1259 sbuf += slock.Pitch;
1260 dbuf += dlock.Pitch;
1264 /* Stretching in Y direction only */
1265 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1266 sbuf = sbase + (sy >> 16) * slock.Pitch;
1267 memcpy(dbuf, sbuf, width);
1268 dbuf += dlock.Pitch;
1274 /* Stretching in X direction */
1276 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1278 sbuf = sbase + (sy >> 16) * slock.Pitch;
1280 if ((sy >> 16) == (last_sy >> 16))
1282 /* this sourcerow is the same as last sourcerow -
1283 * copy already stretched row
1285 memcpy(dbuf, dbuf - dlock.Pitch, width);
1289 #define STRETCH_ROW(type) { \
1290 const type *s = (const type *)sbuf; \
1291 type *d = (type *)dbuf; \
1292 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1293 d[x] = s[sx >> 16]; \
1298 case 1: STRETCH_ROW(BYTE)
1299 case 2: STRETCH_ROW(WORD)
1300 case 4: STRETCH_ROW(DWORD)
1305 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1309 s = sbuf+3*(sx>>16);
1310 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1311 d[0] = (pixel )&0xff;
1312 d[1] = (pixel>> 8)&0xff;
1313 d[2] = (pixel>>16)&0xff;
1319 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1320 ret = WINED3DERR_NOTAVAILABLE;
1325 dbuf += dlock.Pitch;
1332 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1333 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1334 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1335 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1337 /* The color keying flags are checked for correctness in ddraw */
1338 if (Flags & WINEDDBLT_KEYSRC)
1340 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1341 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1343 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1345 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1346 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1349 if (Flags & WINEDDBLT_KEYDEST)
1351 /* Destination color keys are taken from the source surface ! */
1352 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1353 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1355 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1357 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1358 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1367 keymask = sEntry->red_mask
1368 | sEntry->green_mask
1369 | sEntry->blue_mask;
1371 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1374 if (Flags & WINEDDBLT_DDFX)
1376 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1379 dTopRight = dbuf+((dstwidth-1)*bpp);
1380 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1381 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1383 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1385 /* I don't think we need to do anything about this flag */
1386 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1388 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1391 dTopRight = dTopLeft;
1394 dBottomRight = dBottomLeft;
1396 dstxinc = dstxinc *-1;
1398 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1401 dTopLeft = dBottomLeft;
1404 dTopRight = dBottomRight;
1406 dstyinc = dstyinc *-1;
1408 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1410 /* I don't think we need to do anything about this flag */
1411 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1413 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1416 dBottomRight = dTopLeft;
1419 dBottomLeft = dTopRight;
1421 dstxinc = dstxinc * -1;
1422 dstyinc = dstyinc * -1;
1424 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1427 dTopLeft = dBottomLeft;
1428 dBottomLeft = dBottomRight;
1429 dBottomRight = dTopRight;
1434 dstxinc = dstxinc * -1;
1436 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1439 dTopLeft = dTopRight;
1440 dTopRight = dBottomRight;
1441 dBottomRight = dBottomLeft;
1446 dstyinc = dstyinc * -1;
1448 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1450 /* I don't think we need to do anything about this flag */
1451 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1454 Flags &= ~(WINEDDBLT_DDFX);
1457 #define COPY_COLORKEY_FX(type) { \
1459 type *d = (type *)dbuf, *dx, tmp; \
1460 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1461 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1463 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1464 tmp = s[sx >> 16]; \
1465 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1466 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1469 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1471 d = (type*)(((LPBYTE)d)+dstyinc); \
1476 case 1: COPY_COLORKEY_FX(BYTE)
1477 case 2: COPY_COLORKEY_FX(WORD)
1478 case 4: COPY_COLORKEY_FX(DWORD)
1482 BYTE *d = dbuf, *dx;
1483 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1485 sbuf = sbase + (sy >> 16) * slock.Pitch;
1487 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1489 DWORD pixel, dpixel = 0;
1490 s = sbuf+3*(sx>>16);
1491 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1492 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1493 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1494 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1496 dx[0] = (pixel )&0xff;
1497 dx[1] = (pixel>> 8)&0xff;
1498 dx[2] = (pixel>>16)&0xff;
1507 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1508 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1509 ret = WINED3DERR_NOTAVAILABLE;
1511 #undef COPY_COLORKEY_FX
1517 if (Flags && FIXME_ON(d3d_surface))
1519 FIXME("\tUnsupported flags: %08x\n", Flags);
1523 IWineD3DSurface_UnlockRect(iface);
1524 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1525 /* Release the converted surface if any */
1526 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1530 /*****************************************************************************
1531 * IWineD3DSurface::BltFast, SW emulation version
1533 * This is the software implementation of BltFast, as used by GDI surfaces
1534 * and as a fallback for OpenGL surfaces. This code is taken from the old
1535 * DirectDraw code, and was originally written by TransGaming.
1540 * Source: Source surface to copy from
1541 * rsrc: Source rectangle
1545 * WINED3D_OK on success
1547 *****************************************************************************/
1548 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1549 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1551 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1552 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1554 int bpp, w, h, x, y;
1555 WINED3DLOCKED_RECT dlock,slock;
1556 HRESULT ret = WINED3D_OK;
1558 RECT lock_src, lock_dst, lock_union;
1561 const struct GlPixelFormatDesc *sEntry, *dEntry;
1563 if (TRACE_ON(d3d_surface))
1565 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1569 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1570 rsrc->right,rsrc->bottom);
1574 TRACE(" srcrect: NULL\n");
1578 if ((This->Flags & SFLAG_LOCKED) ||
1579 (Src->Flags & SFLAG_LOCKED))
1581 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1582 return WINEDDERR_SURFACEBUSY;
1587 WARN("rsrc is NULL!\n");
1590 rsrc2.right = Src->currentDesc.Width;
1591 rsrc2.bottom = Src->currentDesc.Height;
1595 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1596 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1597 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1598 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1599 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1600 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1602 WARN("Application gave us bad source rectangle for BltFast.\n");
1603 return WINEDDERR_INVALIDRECT;
1606 h = rsrc->bottom - rsrc->top;
1607 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1608 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1609 if (h <= 0) return WINEDDERR_INVALIDRECT;
1611 w = rsrc->right - rsrc->left;
1612 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1613 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1614 if (w <= 0) return WINEDDERR_INVALIDRECT;
1616 /* Now compute the locking rectangle... */
1617 lock_src.left = rsrc->left;
1618 lock_src.top = rsrc->top;
1619 lock_src.right = lock_src.left + w;
1620 lock_src.bottom = lock_src.top + h;
1622 lock_dst.left = dstx;
1623 lock_dst.top = dsty;
1624 lock_dst.right = dstx + w;
1625 lock_dst.bottom = dsty + h;
1627 bpp = This->resource.format_desc->byte_count;
1629 /* We need to lock the surfaces, or we won't get refreshes when done. */
1634 UnionRect(&lock_union, &lock_src, &lock_dst);
1636 /* Lock the union of the two rectangles */
1637 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1638 if(ret != WINED3D_OK) goto error;
1640 pitch = dlock.Pitch;
1641 slock.Pitch = dlock.Pitch;
1643 /* Since slock was originally copied from this surface's description, we can just reuse it */
1644 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1645 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1646 sEntry = Src->resource.format_desc;
1651 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1652 if(ret != WINED3D_OK) goto error;
1653 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1654 if(ret != WINED3D_OK) goto error;
1658 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1660 sEntry = Src->resource.format_desc;
1661 dEntry = This->resource.format_desc;
1664 /* Handle compressed surfaces first... */
1665 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1667 UINT row_block_count;
1669 TRACE("compressed -> compressed copy\n");
1671 FIXME("trans arg not supported when a compressed surface is involved\n");
1673 FIXME("offset for destination surface is not supported\n");
1674 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1676 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1677 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1681 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1682 for (y = 0; y < h; y += dEntry->block_height)
1684 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1685 dbuf += dlock.Pitch;
1686 sbuf += slock.Pitch;
1691 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1693 /* TODO: Use the libtxc_dxtn.so shared library to do
1694 * software decompression
1696 ERR("Software decompression not supported.\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 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1836 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1837 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1839 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1841 /* Compressed textures are block based, so calculate the offset of
1842 * the block that contains the top-left pixel of the locked rectangle. */
1843 pLockedRect->pBits = This->resource.allocatedMemory
1844 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1845 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1849 pLockedRect->pBits = This->resource.allocatedMemory +
1850 (pLockedRect->Pitch * pRect->top) +
1851 (pRect->left * format_desc->byte_count);
1853 This->lockedRect.left = pRect->left;
1854 This->lockedRect.top = pRect->top;
1855 This->lockedRect.right = pRect->right;
1856 This->lockedRect.bottom = pRect->bottom;
1859 /* No dirtifying is needed for this surface implementation */
1860 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1865 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1866 ERR("Should not be called on base texture\n");
1870 /* TODO: think about moving this down to resource? */
1871 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1873 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1875 /* This should only be called for sysmem textures, it may be a good idea
1876 * to extend this to all pools at some point in the future */
1877 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1879 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1881 return This->resource.allocatedMemory;