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
13 * Copyright 2009 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in)
40 float tmp = fabs(*in);
41 unsigned int mantissa;
44 /* Deal with special numbers */
45 if (*in == 0.0f) return 0x0000;
46 if(isnan(*in)) return 0x7C01;
47 if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
49 if(tmp < powf(2, 10)) {
54 }while(tmp < powf(2, 10));
55 } else if(tmp >= powf(2, 11)) {
60 }while(tmp >= powf(2, 11));
63 mantissa = (unsigned int) tmp;
64 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
66 exp += 10; /* Normalize the mantissa */
67 exp += 15; /* Exponent is encoded with excess 15 */
69 if(exp > 30) { /* too big */
70 ret = 0x7c00; /* INF */
72 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
74 mantissa = mantissa >> 1;
77 ret = mantissa & 0x3ff;
79 ret = (exp << 10) | (mantissa & 0x3ff);
82 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
86 /* *******************************************
87 IWineD3DSurface IUnknown parts follow
88 ******************************************* */
89 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
91 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
92 /* Warn ,but be nice about things */
93 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
95 if (IsEqualGUID(riid, &IID_IUnknown)
96 || IsEqualGUID(riid, &IID_IWineD3DBase)
97 || IsEqualGUID(riid, &IID_IWineD3DResource)
98 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
99 IUnknown_AddRef((IUnknown*)iface);
104 return E_NOINTERFACE;
107 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
109 ULONG ref = InterlockedIncrement(&This->resource.ref);
110 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
114 /* ****************************************************
115 IWineD3DSurface IWineD3DResource parts follow
116 **************************************************** */
117 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
118 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
122 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
126 return resource_free_private_data((IWineD3DResource *)iface, refguid);
129 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
130 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
133 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
134 return resource_get_priority((IWineD3DResource *)iface);
137 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
138 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
139 return resource_get_type((IWineD3DResource *)iface);
142 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
143 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
144 return resource_get_parent((IWineD3DResource *)iface, pParent);
147 /* ******************************************************
148 IWineD3DSurface IWineD3DSurface parts follow
149 ****************************************************** */
151 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
152 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
153 IWineD3DBase *container = 0;
155 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
158 ERR("Called without a valid ppContainer.\n");
161 /* Standalone surfaces return the device as container. */
162 if (This->container.u.base) container = This->container.u.base;
163 else container = (IWineD3DBase *)This->resource.device;
165 TRACE("Relaying to QueryInterface\n");
166 return IUnknown_QueryInterface(container, riid, ppContainer);
169 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
170 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
172 TRACE("(%p) : copying into %p\n", This, pDesc);
174 pDesc->format = This->resource.format_desc->format;
175 pDesc->resource_type = This->resource.resourceType;
176 pDesc->usage = This->resource.usage;
177 pDesc->pool = This->resource.pool;
178 pDesc->size = This->resource.size; /* dx8 only */
179 pDesc->multisample_type = This->currentDesc.MultiSampleType;
180 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
181 pDesc->width = This->currentDesc.Width;
182 pDesc->height = This->currentDesc.Height;
187 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
189 TRACE("iface %p, flags %#x.\n", iface, Flags);
193 case WINEDDGBS_CANBLT:
194 case WINEDDGBS_ISBLTDONE:
198 return WINED3DERR_INVALIDCALL;
202 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
203 /* XXX: DDERR_INVALIDSURFACETYPE */
205 TRACE("(%p)->(%08x)\n",iface,Flags);
207 case WINEDDGFS_CANFLIP:
208 case WINEDDGFS_ISFLIPDONE:
212 return WINED3DERR_INVALIDCALL;
216 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
217 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
218 TRACE("(%p)\n", This);
220 /* D3D8 and 9 loose full devices, ddraw only surfaces */
221 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
224 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
225 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
226 TRACE("(%p)\n", This);
228 /* So far we don't lose anything :) */
229 This->Flags &= ~SFLAG_LOST;
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
234 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
236 TRACE("(%p)->(%p)\n", This, Pal);
238 if(This->palette == PalImpl) {
239 TRACE("Nop palette change\n");
243 if(This->palette != NULL)
244 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
245 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
247 This->palette = PalImpl;
249 if(PalImpl != NULL) {
250 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
251 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
254 return IWineD3DSurface_RealizePalette(iface);
256 else return WINED3D_OK;
259 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
261 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
262 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
264 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
265 FIXME(" colorkey value not supported (%08x) !\n", Flags);
266 return WINED3DERR_INVALIDCALL;
269 /* Dirtify the surface, but only if a key was changed */
271 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
272 case WINEDDCKEY_DESTBLT:
273 This->DestBltCKey = *CKey;
274 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
277 case WINEDDCKEY_DESTOVERLAY:
278 This->DestOverlayCKey = *CKey;
279 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
282 case WINEDDCKEY_SRCOVERLAY:
283 This->SrcOverlayCKey = *CKey;
284 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
287 case WINEDDCKEY_SRCBLT:
288 This->SrcBltCKey = *CKey;
289 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
294 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
295 case WINEDDCKEY_DESTBLT:
296 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
299 case WINEDDCKEY_DESTOVERLAY:
300 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
303 case WINEDDCKEY_SRCOVERLAY:
304 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
307 case WINEDDCKEY_SRCBLT:
308 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
316 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
317 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
318 TRACE("(%p)->(%p)\n", This, Pal);
320 *Pal = (IWineD3DPalette *) This->palette;
324 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
325 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
326 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
328 TRACE("(%p)\n", This);
330 if ((format_desc->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH))
331 == WINED3DFMT_FLAG_COMPRESSED)
333 /* Since compressed formats are block based, pitch means the amount of
334 * bytes to the next row of block rather than the next row of pixels. */
335 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
336 ret = row_block_count * format_desc->block_byte_count;
340 unsigned char alignment = This->resource.device->surface_alignment;
341 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
342 ret = (ret + alignment - 1) & ~(alignment - 1);
344 TRACE("(%p) Returning %d\n", This, ret);
348 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
349 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
352 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
354 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
356 TRACE("(%p): Not an overlay surface\n", This);
357 return WINEDDERR_NOTAOVERLAYSURFACE;
360 w = This->overlay_destrect.right - This->overlay_destrect.left;
361 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
362 This->overlay_destrect.left = X;
363 This->overlay_destrect.top = Y;
364 This->overlay_destrect.right = X + w;
365 This->overlay_destrect.bottom = Y + h;
367 IWineD3DSurface_DrawOverlay(iface);
372 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
373 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
376 TRACE("(%p)->(%p,%p)\n", This, X, Y);
378 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
380 TRACE("(%p): Not an overlay surface\n", This);
381 return WINEDDERR_NOTAOVERLAYSURFACE;
383 if(This->overlay_dest == NULL) {
385 hr = WINEDDERR_OVERLAYNOTVISIBLE;
387 *X = This->overlay_destrect.left;
388 *Y = This->overlay_destrect.top;
392 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
396 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
397 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
399 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
401 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
403 TRACE("(%p): Not an overlay surface\n", This);
404 return WINEDDERR_NOTAOVERLAYSURFACE;
410 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
411 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
413 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
414 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
415 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
417 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
419 WARN("(%p): Not an overlay surface\n", This);
420 return WINEDDERR_NOTAOVERLAYSURFACE;
421 } else if(!DstSurface) {
422 WARN("(%p): Dest surface is NULL\n", This);
423 return WINED3DERR_INVALIDCALL;
427 This->overlay_srcrect = *SrcRect;
429 This->overlay_srcrect.left = 0;
430 This->overlay_srcrect.top = 0;
431 This->overlay_srcrect.right = This->currentDesc.Width;
432 This->overlay_srcrect.bottom = This->currentDesc.Height;
436 This->overlay_destrect = *DstRect;
438 This->overlay_destrect.left = 0;
439 This->overlay_destrect.top = 0;
440 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
441 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
444 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
445 list_remove(&This->overlay_entry);
448 if(Flags & WINEDDOVER_SHOW) {
449 if(This->overlay_dest != Dst) {
450 This->overlay_dest = Dst;
451 list_add_tail(&Dst->overlays, &This->overlay_entry);
453 } else if(Flags & WINEDDOVER_HIDE) {
454 /* tests show that the rectangles are erased on hide */
455 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
456 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
457 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
458 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
459 This->overlay_dest = NULL;
462 IWineD3DSurface_DrawOverlay(iface);
467 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
469 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
470 TRACE("(%p)->(%p)\n", This, clipper);
472 This->clipper = clipper;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 *clipper = This->clipper;
483 IWineD3DClipper_AddRef(*clipper);
488 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
490 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
491 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format_id,
492 &This->resource.device->adapter->gl_info);
494 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
496 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
497 return WINED3DERR_INVALIDCALL;
500 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format_id, debug_d3dformat(format_id));
502 This->resource.size = wined3d_format_calculate_size(format_desc, This->resource.device->surface_alignment,
503 This->pow2Width, This->pow2Height);
505 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
507 This->resource.format_desc = format_desc;
509 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
514 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
515 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
516 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
524 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
526 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
527 return WINED3DERR_INVALIDCALL;
530 switch (format_desc->byte_count)
534 /* Allocate extra space to store the RGB bit masks. */
535 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
539 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
543 /* Allocate extra space for a palette. */
544 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
545 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
550 return E_OUTOFMEMORY;
552 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
553 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
554 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
555 * add an extra line to the dib section
557 GetSystemInfo(&sysInfo);
558 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
560 TRACE("Adding an extra line to the dib section\n");
563 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
564 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
565 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
566 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
567 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
568 b_info->bmiHeader.biPlanes = 1;
569 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
571 b_info->bmiHeader.biXPelsPerMeter = 0;
572 b_info->bmiHeader.biYPelsPerMeter = 0;
573 b_info->bmiHeader.biClrUsed = 0;
574 b_info->bmiHeader.biClrImportant = 0;
576 /* Get the bit masks */
577 masks = (DWORD *)b_info->bmiColors;
578 switch (This->resource.format_desc->format)
580 case WINED3DFMT_B8G8R8_UNORM:
581 usage = DIB_RGB_COLORS;
582 b_info->bmiHeader.biCompression = BI_RGB;
585 case WINED3DFMT_B5G5R5X1_UNORM:
586 case WINED3DFMT_B5G5R5A1_UNORM:
587 case WINED3DFMT_B4G4R4A4_UNORM:
588 case WINED3DFMT_B4G4R4X4_UNORM:
589 case WINED3DFMT_B2G3R3_UNORM:
590 case WINED3DFMT_B2G3R3A8_UNORM:
591 case WINED3DFMT_R10G10B10A2_UNORM:
592 case WINED3DFMT_R8G8B8A8_UNORM:
593 case WINED3DFMT_R8G8B8X8_UNORM:
594 case WINED3DFMT_B10G10R10A2_UNORM:
595 case WINED3DFMT_B5G6R5_UNORM:
596 case WINED3DFMT_R16G16B16A16_UNORM:
598 b_info->bmiHeader.biCompression = BI_BITFIELDS;
599 masks[0] = format_desc->red_mask;
600 masks[1] = format_desc->green_mask;
601 masks[2] = format_desc->blue_mask;
605 /* Don't know palette */
606 b_info->bmiHeader.biCompression = BI_RGB;
613 HeapFree(GetProcessHeap(), 0, b_info);
614 return HRESULT_FROM_WIN32(GetLastError());
617 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);
618 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
621 if (!This->dib.DIBsection) {
622 ERR("CreateDIBSection failed!\n");
623 HeapFree(GetProcessHeap(), 0, b_info);
624 return HRESULT_FROM_WIN32(GetLastError());
627 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
628 /* copy the existing surface to the dib section */
629 if(This->resource.allocatedMemory) {
630 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
632 /* This is to make LockRect read the gl Texture although memory is allocated */
633 This->Flags &= ~SFLAG_INSYSMEM;
635 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
637 HeapFree(GetProcessHeap(), 0, b_info);
639 /* Now allocate a HDC */
640 This->hDC = CreateCompatibleDC(0);
641 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
642 TRACE("using wined3d palette %p\n", This->palette);
643 SelectPalette(This->hDC,
644 This->palette ? This->palette->hpal : 0,
647 This->Flags |= SFLAG_DIBSECTION;
649 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
650 This->resource.heapMemory = NULL;
655 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
656 unsigned int w, unsigned int h)
660 unsigned short *dst_s;
662 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
663 for(y = 0; y < h; y++) {
664 src_f = (const float *)(src + y * pitch_in);
665 dst_s = (unsigned short *) (dst + y * pitch_out);
666 for(x = 0; x < w; x++) {
667 dst_s[x] = float_32_to_16(src_f + x);
672 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
673 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
675 static const unsigned char convert_5to8[] =
677 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
678 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
679 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
680 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
682 static const unsigned char convert_6to8[] =
684 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
685 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
686 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
687 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
688 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
689 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
690 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
691 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
695 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
697 for (y = 0; y < h; ++y)
699 const WORD *src_line = (const WORD *)(src + y * pitch_in);
700 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
701 for (x = 0; x < w; ++x)
703 WORD pixel = src_line[x];
704 dst_line[x] = 0xff000000
705 | convert_5to8[(pixel & 0xf800) >> 11] << 16
706 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
707 | convert_5to8[(pixel & 0x001f)];
712 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
713 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
717 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
719 for (y = 0; y < h; ++y)
721 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
722 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
724 for (x = 0; x < w; ++x)
726 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
731 static inline BYTE cliptobyte(int x)
733 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
736 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
737 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
740 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
742 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
744 for (y = 0; y < h; ++y)
746 const BYTE *src_line = src + y * pitch_in;
747 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
748 for (x = 0; x < w; ++x)
750 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
751 * C = Y - 16; D = U - 128; E = V - 128;
752 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
753 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
754 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
755 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
756 * U and V are shared between the pixels.
758 if (!(x & 1)) /* for every even pixel, read new U and V */
760 d = (int) src_line[1] - 128;
761 e = (int) src_line[3] - 128;
763 g2 = - 100 * d - 208 * e + 128;
766 c2 = 298 * ((int) src_line[0] - 16);
767 dst_line[x] = 0xff000000
768 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
769 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
770 | cliptobyte((c2 + b2) >> 8); /* blue */
771 /* Scale RGB values to 0..255 range,
772 * then clip them if still not in range (may be negative),
773 * then shift them within DWORD if necessary.
780 struct d3dfmt_convertor_desc
782 enum wined3d_format_id from, to;
783 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
786 static const struct d3dfmt_convertor_desc convertors[] =
788 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
789 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
790 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
791 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
794 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
797 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
798 if(convertors[i].from == from && convertors[i].to == to) {
799 return &convertors[i];
805 /*****************************************************************************
806 * surface_convert_format
808 * Creates a duplicate of a surface in a different format. Is used by Blt to
809 * blit between surfaces with different formats
812 * source: Source surface
813 * fmt: Requested destination format
815 *****************************************************************************/
816 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
818 IWineD3DSurface *ret = NULL;
819 const struct d3dfmt_convertor_desc *conv;
820 WINED3DLOCKED_RECT lock_src, lock_dst;
823 conv = find_convertor(source->resource.format_desc->format, to_fmt);
825 FIXME("Cannot find a conversion function from format %s to %s\n",
826 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
830 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
831 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
832 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
833 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
834 NULL /* parent */, &wined3d_null_parent_ops);
836 ERR("Failed to create a destination surface for conversion\n");
840 memset(&lock_src, 0, sizeof(lock_src));
841 memset(&lock_dst, 0, sizeof(lock_dst));
843 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
845 ERR("Failed to lock the source surface\n");
846 IWineD3DSurface_Release(ret);
849 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
851 ERR("Failed to lock the dest surface\n");
852 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
853 IWineD3DSurface_Release(ret);
857 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
858 source->currentDesc.Width, source->currentDesc.Height);
860 IWineD3DSurface_UnlockRect(ret);
861 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
863 return (IWineD3DSurfaceImpl *) ret;
866 /*****************************************************************************
869 * Helper function that fills a memory area with a specific color
872 * buf: memory address to start filling at
873 * width, height: Dimensions of the area to fill
874 * bpp: Bit depth of the surface
875 * lPitch: pitch of the surface
876 * color: Color to fill with
878 *****************************************************************************/
880 _Blt_ColorFill(BYTE *buf,
881 int width, int height,
882 int bpp, LONG lPitch,
890 #define COLORFILL_ROW(type) \
892 type *d = (type *) buf; \
893 for (x = 0; x < width; x++) \
894 d[x] = (type) color; \
899 case 1: COLORFILL_ROW(BYTE)
900 case 2: COLORFILL_ROW(WORD)
904 for (x = 0; x < width; x++,d+=3)
906 d[0] = (color ) & 0xFF;
907 d[1] = (color>> 8) & 0xFF;
908 d[2] = (color>>16) & 0xFF;
912 case 4: COLORFILL_ROW(DWORD)
914 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
915 return WINED3DERR_NOTAVAILABLE;
920 /* Now copy first row */
922 for (y = 1; y < height; y++)
925 memcpy(buf, first, width * bpp);
930 /*****************************************************************************
931 * IWineD3DSurface::Blt, SW emulation version
933 * Performs a blit to a surface, with or without a source surface.
934 * This is the main functionality of DirectDraw
937 * DestRect: Destination rectangle to write to
938 * src_surface: Source surface, can be NULL
939 * SrcRect: Source rectangle
940 *****************************************************************************/
941 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
942 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
944 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
945 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
947 HRESULT ret = WINED3D_OK;
948 WINED3DLOCKED_RECT dlock, slock;
949 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
950 const struct wined3d_format_desc *sEntry, *dEntry;
955 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
956 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
957 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
959 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
961 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
962 return WINEDDERR_SURFACEBUSY;
965 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
966 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
967 FIXME("Filters not supported in software blit\n");
970 /* First check for the validity of source / destination rectangles.
971 * This was verified using a test application + by MSDN. */
977 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
978 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
979 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
980 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
981 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
983 WARN("Application gave us bad source rectangle for Blt.\n");
984 return WINEDDERR_INVALIDRECT;
987 if (!SrcRect->right || !SrcRect->bottom
988 || SrcRect->left == (int)src->currentDesc.Width
989 || SrcRect->top == (int)src->currentDesc.Height)
991 TRACE("Nothing to be done.\n");
1002 xsrc.right = src->currentDesc.Width;
1003 xsrc.bottom = src->currentDesc.Height;
1007 memset(&xsrc, 0, sizeof(xsrc));
1012 /* For the Destination rect, it can be out of bounds on the condition
1013 * that a clipper is set for the given surface. */
1014 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1015 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1016 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1017 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1018 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1020 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1021 return WINEDDERR_INVALIDRECT;
1024 if (DestRect->right <= 0 || DestRect->bottom <= 0
1025 || DestRect->left >= (int)This->currentDesc.Width
1026 || DestRect->top >= (int)This->currentDesc.Height)
1028 TRACE("Nothing to be done.\n");
1038 full_rect.right = This->currentDesc.Width;
1039 full_rect.bottom = This->currentDesc.Height;
1040 IntersectRect(&xdst, &full_rect, DestRect);
1044 BOOL clip_horiz, clip_vert;
1047 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1048 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1050 if (clip_vert || clip_horiz)
1052 /* Now check if this is a special case or not... */
1053 if ((Flags & WINEDDBLT_DDFX)
1054 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1055 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1057 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1065 xsrc.left -= xdst.left;
1068 if (xdst.right > This->currentDesc.Width)
1070 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1071 xdst.right = (int)This->currentDesc.Width;
1079 xsrc.top -= xdst.top;
1082 if (xdst.bottom > This->currentDesc.Height)
1084 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1085 xdst.bottom = (int)This->currentDesc.Height;
1089 /* And check if after clipping something is still to be done... */
1090 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1091 || (xdst.left >= (int)This->currentDesc.Width)
1092 || (xdst.top >= (int)This->currentDesc.Height)
1093 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1094 || (xsrc.left >= (int)src->currentDesc.Width)
1095 || (xsrc.top >= (int)src->currentDesc.Height))
1097 TRACE("Nothing to be done after clipping.\n");
1107 xdst.right = This->currentDesc.Width;
1108 xdst.bottom = This->currentDesc.Height;
1113 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1115 sEntry = This->resource.format_desc;
1120 dEntry = This->resource.format_desc;
1123 if (This->resource.format_desc->format != src->resource.format_desc->format)
1125 src = surface_convert_format(src, dEntry->format);
1128 /* The conv function writes a FIXME */
1129 WARN("Cannot convert source surface format to dest format\n");
1133 IWineD3DSurface_LockRect((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1134 sEntry = src->resource.format_desc;
1141 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1143 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1146 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1148 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1150 if (!DestRect || src == This)
1152 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1157 bpp = This->resource.format_desc->byte_count;
1158 srcheight = xsrc.bottom - xsrc.top;
1159 srcwidth = xsrc.right - xsrc.left;
1160 dstheight = xdst.bottom - xdst.top;
1161 dstwidth = xdst.right - xdst.left;
1162 width = (xdst.right - xdst.left) * bpp;
1164 if (DestRect && src != This)
1167 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1169 if (Flags & WINEDDBLT_WAIT)
1171 Flags &= ~WINEDDBLT_WAIT;
1173 if (Flags & WINEDDBLT_ASYNC)
1175 static BOOL displayed = FALSE;
1177 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1179 Flags &= ~WINEDDBLT_ASYNC;
1181 if (Flags & WINEDDBLT_DONOTWAIT)
1183 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1184 static BOOL displayed = FALSE;
1186 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1188 Flags &= ~WINEDDBLT_DONOTWAIT;
1191 /* First, all the 'source-less' blits */
1192 if (Flags & WINEDDBLT_COLORFILL)
1194 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1195 dlock.Pitch, DDBltFx->u5.dwFillColor);
1196 Flags &= ~WINEDDBLT_COLORFILL;
1199 if (Flags & WINEDDBLT_DEPTHFILL)
1201 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1203 if (Flags & WINEDDBLT_ROP)
1205 /* Catch some degenerate cases here */
1206 switch(DDBltFx->dwROP)
1209 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1211 case 0xAA0029: /* No-op */
1214 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1216 case SRCCOPY: /* well, we do that below ? */
1219 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1222 Flags &= ~WINEDDBLT_ROP;
1224 if (Flags & WINEDDBLT_DDROPS)
1226 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1228 /* Now the 'with source' blits */
1232 int sx, xinc, sy, yinc;
1234 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1236 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1237 xinc = (srcwidth << 16) / dstwidth;
1238 yinc = (srcheight << 16) / dstheight;
1242 /* No effects, we can cheat here */
1243 if (dstwidth == srcwidth)
1245 if (dstheight == srcheight)
1247 /* No stretching in either direction. This needs to be as
1248 * fast as possible */
1251 /* check for overlapping surfaces */
1252 if (src != This || xdst.top < xsrc.top ||
1253 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1255 /* no overlap, or dst above src, so copy from top downwards */
1256 for (y = 0; y < dstheight; y++)
1258 memcpy(dbuf, sbuf, width);
1259 sbuf += slock.Pitch;
1260 dbuf += dlock.Pitch;
1263 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1265 sbuf += (slock.Pitch*dstheight);
1266 dbuf += (dlock.Pitch*dstheight);
1267 for (y = 0; y < dstheight; y++)
1269 sbuf -= slock.Pitch;
1270 dbuf -= dlock.Pitch;
1271 memcpy(dbuf, sbuf, width);
1274 else /* src and dst overlapping on the same line, use memmove */
1276 for (y = 0; y < dstheight; y++)
1278 memmove(dbuf, sbuf, width);
1279 sbuf += slock.Pitch;
1280 dbuf += dlock.Pitch;
1284 /* Stretching in Y direction only */
1285 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1286 sbuf = sbase + (sy >> 16) * slock.Pitch;
1287 memcpy(dbuf, sbuf, width);
1288 dbuf += dlock.Pitch;
1294 /* Stretching in X direction */
1296 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1298 sbuf = sbase + (sy >> 16) * slock.Pitch;
1300 if ((sy >> 16) == (last_sy >> 16))
1302 /* this sourcerow is the same as last sourcerow -
1303 * copy already stretched row
1305 memcpy(dbuf, dbuf - dlock.Pitch, width);
1309 #define STRETCH_ROW(type) { \
1310 const type *s = (const type *)sbuf; \
1311 type *d = (type *)dbuf; \
1312 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1313 d[x] = s[sx >> 16]; \
1318 case 1: STRETCH_ROW(BYTE)
1319 case 2: STRETCH_ROW(WORD)
1320 case 4: STRETCH_ROW(DWORD)
1325 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1329 s = sbuf+3*(sx>>16);
1330 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1331 d[0] = (pixel )&0xff;
1332 d[1] = (pixel>> 8)&0xff;
1333 d[2] = (pixel>>16)&0xff;
1339 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1340 ret = WINED3DERR_NOTAVAILABLE;
1345 dbuf += dlock.Pitch;
1352 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1353 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1354 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1355 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1357 /* The color keying flags are checked for correctness in ddraw */
1358 if (Flags & WINEDDBLT_KEYSRC)
1360 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1361 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1363 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1365 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1366 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1369 if (Flags & WINEDDBLT_KEYDEST)
1371 /* Destination color keys are taken from the source surface ! */
1372 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1373 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1375 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1377 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1378 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1387 keymask = sEntry->red_mask
1388 | sEntry->green_mask
1389 | sEntry->blue_mask;
1391 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1394 if (Flags & WINEDDBLT_DDFX)
1396 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1399 dTopRight = dbuf+((dstwidth-1)*bpp);
1400 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1401 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1403 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1405 /* I don't think we need to do anything about this flag */
1406 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1408 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1411 dTopRight = dTopLeft;
1414 dBottomRight = dBottomLeft;
1416 dstxinc = dstxinc *-1;
1418 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1421 dTopLeft = dBottomLeft;
1424 dTopRight = dBottomRight;
1426 dstyinc = dstyinc *-1;
1428 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1430 /* I don't think we need to do anything about this flag */
1431 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1433 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1436 dBottomRight = dTopLeft;
1439 dBottomLeft = dTopRight;
1441 dstxinc = dstxinc * -1;
1442 dstyinc = dstyinc * -1;
1444 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1447 dTopLeft = dBottomLeft;
1448 dBottomLeft = dBottomRight;
1449 dBottomRight = dTopRight;
1454 dstxinc = dstxinc * -1;
1456 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1459 dTopLeft = dTopRight;
1460 dTopRight = dBottomRight;
1461 dBottomRight = dBottomLeft;
1466 dstyinc = dstyinc * -1;
1468 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1470 /* I don't think we need to do anything about this flag */
1471 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1474 Flags &= ~(WINEDDBLT_DDFX);
1477 #define COPY_COLORKEY_FX(type) { \
1479 type *d = (type *)dbuf, *dx, tmp; \
1480 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1481 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1483 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1484 tmp = s[sx >> 16]; \
1485 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1486 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1489 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1491 d = (type*)(((LPBYTE)d)+dstyinc); \
1496 case 1: COPY_COLORKEY_FX(BYTE)
1497 case 2: COPY_COLORKEY_FX(WORD)
1498 case 4: COPY_COLORKEY_FX(DWORD)
1502 BYTE *d = dbuf, *dx;
1503 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1505 sbuf = sbase + (sy >> 16) * slock.Pitch;
1507 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1509 DWORD pixel, dpixel = 0;
1510 s = sbuf+3*(sx>>16);
1511 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1512 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1513 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1514 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1516 dx[0] = (pixel )&0xff;
1517 dx[1] = (pixel>> 8)&0xff;
1518 dx[2] = (pixel>>16)&0xff;
1527 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1528 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1529 ret = WINED3DERR_NOTAVAILABLE;
1531 #undef COPY_COLORKEY_FX
1537 if (Flags && FIXME_ON(d3d_surface))
1539 FIXME("\tUnsupported flags: %08x\n", Flags);
1543 IWineD3DSurface_UnlockRect(iface);
1544 if (src && src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *)src);
1545 /* Release the converted surface if any */
1546 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1550 /*****************************************************************************
1551 * IWineD3DSurface::BltFast, SW emulation version
1553 * This is the software implementation of BltFast, as used by GDI surfaces
1554 * and as a fallback for OpenGL surfaces. This code is taken from the old
1555 * DirectDraw code, and was originally written by TransGaming.
1560 * src_surface: Source surface to copy from
1561 * rsrc: Source rectangle
1565 * WINED3D_OK on success
1567 *****************************************************************************/
1568 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1569 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1571 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1572 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1574 int bpp, w, h, x, y;
1575 WINED3DLOCKED_RECT dlock,slock;
1576 HRESULT ret = WINED3D_OK;
1578 RECT lock_src, lock_dst, lock_union;
1581 const struct wined3d_format_desc *sEntry, *dEntry;
1583 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1584 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1586 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1588 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1589 return WINEDDERR_SURFACEBUSY;
1594 WARN("rsrc is NULL!\n");
1597 rsrc2.right = src->currentDesc.Width;
1598 rsrc2.bottom = src->currentDesc.Height;
1602 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1603 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1604 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1605 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1606 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1607 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1609 WARN("Application gave us bad source rectangle for BltFast.\n");
1610 return WINEDDERR_INVALIDRECT;
1613 h = rsrc->bottom - rsrc->top;
1614 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1615 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1616 if (h <= 0) return WINEDDERR_INVALIDRECT;
1618 w = rsrc->right - rsrc->left;
1619 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1620 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1621 if (w <= 0) return WINEDDERR_INVALIDRECT;
1623 /* Now compute the locking rectangle... */
1624 lock_src.left = rsrc->left;
1625 lock_src.top = rsrc->top;
1626 lock_src.right = lock_src.left + w;
1627 lock_src.bottom = lock_src.top + h;
1629 lock_dst.left = dstx;
1630 lock_dst.top = dsty;
1631 lock_dst.right = dstx + w;
1632 lock_dst.bottom = dsty + h;
1634 bpp = This->resource.format_desc->byte_count;
1636 /* We need to lock the surfaces, or we won't get refreshes when done. */
1641 UnionRect(&lock_union, &lock_src, &lock_dst);
1643 /* Lock the union of the two rectangles */
1644 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1645 if(ret != WINED3D_OK) goto error;
1647 pitch = dlock.Pitch;
1648 slock.Pitch = dlock.Pitch;
1650 /* Since slock was originally copied from this surface's description, we can just reuse it */
1651 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1652 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1653 sEntry = src->resource.format_desc;
1658 ret = IWineD3DSurface_LockRect(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1659 if(ret != WINED3D_OK) goto error;
1660 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1661 if(ret != WINED3D_OK) goto error;
1665 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1667 sEntry = src->resource.format_desc;
1668 dEntry = This->resource.format_desc;
1671 /* Handle compressed surfaces first... */
1672 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1674 UINT row_block_count;
1676 TRACE("compressed -> compressed copy\n");
1678 FIXME("trans arg not supported when a compressed surface is involved\n");
1680 FIXME("offset for destination surface is not supported\n");
1681 if (src->resource.format_desc->format != This->resource.format_desc->format)
1683 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1684 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1688 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1689 for (y = 0; y < h; y += dEntry->block_height)
1691 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1692 dbuf += dlock.Pitch;
1693 sbuf += slock.Pitch;
1698 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1700 /* TODO: Use the libtxc_dxtn.so shared library to do
1701 * software decompression
1703 ERR("Software decompression not supported.\n");
1707 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1709 DWORD keylow, keyhigh;
1710 DWORD mask = src->resource.format_desc->red_mask
1711 | src->resource.format_desc->green_mask
1712 | src->resource.format_desc->blue_mask;
1714 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1718 TRACE("Color keyed copy\n");
1719 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1721 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1722 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1726 /* I'm not sure if this is correct */
1727 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1728 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1729 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1732 #define COPYBOX_COLORKEY(type) { \
1733 const type *s = (const type *)sbuf; \
1734 type *d = (type *)dbuf; \
1736 for (y = 0; y < h; y++) { \
1737 for (x = 0; x < w; x++) { \
1739 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1741 s = (const type *)((const BYTE *)s + slock.Pitch); \
1742 d = (type *)((BYTE *)d + dlock.Pitch); \
1748 case 1: COPYBOX_COLORKEY(BYTE)
1749 case 2: COPYBOX_COLORKEY(WORD)
1750 case 4: COPYBOX_COLORKEY(DWORD)
1758 for (y = 0; y < h; y++)
1760 for (x = 0; x < w * 3; x += 3)
1762 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1763 if (tmp < keylow || tmp > keyhigh)
1765 d[x + 0] = s[x + 0];
1766 d[x + 1] = s[x + 1];
1767 d[x + 2] = s[x + 2];
1776 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1777 ret = WINED3DERR_NOTAVAILABLE;
1780 #undef COPYBOX_COLORKEY
1781 TRACE("Copy Done\n");
1785 int width = w * bpp;
1786 INT sbufpitch, dbufpitch;
1788 TRACE("NO color key copy\n");
1789 /* Handle overlapping surfaces */
1792 sbuf += (h - 1) * slock.Pitch;
1793 dbuf += (h - 1) * dlock.Pitch;
1794 sbufpitch = -slock.Pitch;
1795 dbufpitch = -dlock.Pitch;
1799 sbufpitch = slock.Pitch;
1800 dbufpitch = dlock.Pitch;
1802 for (y = 0; y < h; y++)
1804 /* This is pretty easy, a line for line memcpy */
1805 memmove(dbuf, sbuf, width);
1809 TRACE("Copy done\n");
1815 IWineD3DSurface_UnlockRect(iface);
1819 IWineD3DSurface_UnlockRect(iface);
1820 IWineD3DSurface_UnlockRect(src_surface);
1826 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1828 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1830 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1831 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1833 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1837 pLockedRect->pBits = This->resource.allocatedMemory;
1838 This->lockedRect.left = 0;
1839 This->lockedRect.top = 0;
1840 This->lockedRect.right = This->currentDesc.Width;
1841 This->lockedRect.bottom = This->currentDesc.Height;
1843 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1844 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1845 This->lockedRect.right, This->lockedRect.bottom);
1849 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1851 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1852 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1854 if ((format_desc->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH))
1855 == WINED3DFMT_FLAG_COMPRESSED)
1857 /* Compressed textures are block based, so calculate the offset of
1858 * the block that contains the top-left pixel of the locked rectangle. */
1859 pLockedRect->pBits = This->resource.allocatedMemory
1860 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1861 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1865 pLockedRect->pBits = This->resource.allocatedMemory +
1866 (pLockedRect->Pitch * pRect->top) +
1867 (pRect->left * format_desc->byte_count);
1869 This->lockedRect.left = pRect->left;
1870 This->lockedRect.top = pRect->top;
1871 This->lockedRect.right = pRect->right;
1872 This->lockedRect.bottom = pRect->bottom;
1875 /* No dirtifying is needed for this surface implementation */
1876 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1881 /* TODO: think about moving this down to resource? */
1882 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1884 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1886 /* This should only be called for sysmem textures, it may be a good idea
1887 * to extend this to all pools at some point in the future */
1888 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1890 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1892 return This->resource.allocatedMemory;