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-2010 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_IWineD3DSurface)) {
97 IUnknown_AddRef((IUnknown*)iface);
102 return E_NOINTERFACE;
105 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface)
107 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
110 TRACE("Surface %p, container %p of type %#x.\n",
111 surface, surface->container.u.base, surface->container.type);
113 switch (surface->container.type)
115 case WINED3D_CONTAINER_TEXTURE:
116 return wined3d_texture_incref(surface->container.u.texture);
118 case WINED3D_CONTAINER_SWAPCHAIN:
119 return wined3d_swapchain_incref(surface->container.u.swapchain);
122 ERR("Unhandled container type %#x.\n", surface->container.type);
123 case WINED3D_CONTAINER_NONE:
127 refcount = InterlockedIncrement(&surface->resource.ref);
128 TRACE("%p increasing refcount to %u.\n", surface, refcount);
133 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
134 REFGUID riid, const void *data, DWORD data_size, DWORD flags)
136 return resource_set_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, riid, data, data_size, flags);
139 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
140 REFGUID guid, void *data, DWORD *data_size)
142 return resource_get_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, guid, data, data_size);
145 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
147 return resource_free_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, refguid);
150 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
152 return resource_set_priority(&((IWineD3DSurfaceImpl *)iface)->resource, priority);
155 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
157 return resource_get_priority(&((IWineD3DSurfaceImpl *)iface)->resource);
160 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
162 TRACE("iface %p.\n", iface);
164 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
167 struct wined3d_resource * WINAPI IWineD3DBaseSurfaceImpl_GetResource(IWineD3DSurface *iface)
169 TRACE("iface %p.\n", iface);
171 return &((IWineD3DSurfaceImpl *)iface)->resource;
174 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
176 TRACE("iface %p, flags %#x.\n", iface, flags);
180 case WINEDDGBS_CANBLT:
181 case WINEDDGBS_ISBLTDONE:
185 return WINED3DERR_INVALIDCALL;
189 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
191 /* XXX: DDERR_INVALIDSURFACETYPE */
193 TRACE("iface %p, flags %#x.\n", iface, flags);
197 case WINEDDGFS_CANFLIP:
198 case WINEDDGFS_ISFLIPDONE:
202 return WINED3DERR_INVALIDCALL;
206 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
207 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
208 TRACE("(%p)\n", This);
210 /* D3D8 and 9 loose full devices, ddraw only surfaces */
211 return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
214 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
215 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
216 TRACE("(%p)\n", This);
218 /* So far we don't lose anything :) */
219 This->flags &= ~SFLAG_LOST;
223 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
225 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
227 TRACE("iface %p, palette %p.\n", iface, palette);
229 if (This->palette == palette)
231 TRACE("Nop palette change\n");
236 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
237 This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
239 This->palette = palette;
243 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
244 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
246 This->surface_ops->surface_realize_palette(This);
252 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
254 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
256 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
258 if (flags & WINEDDCKEY_COLORSPACE)
260 FIXME(" colorkey value not supported (%08x) !\n", flags);
261 return WINED3DERR_INVALIDCALL;
264 /* Dirtify the surface, but only if a key was changed */
267 switch (flags & ~WINEDDCKEY_COLORSPACE)
269 case WINEDDCKEY_DESTBLT:
270 This->DestBltCKey = *CKey;
271 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
274 case WINEDDCKEY_DESTOVERLAY:
275 This->DestOverlayCKey = *CKey;
276 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
279 case WINEDDCKEY_SRCOVERLAY:
280 This->SrcOverlayCKey = *CKey;
281 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
284 case WINEDDCKEY_SRCBLT:
285 This->SrcBltCKey = *CKey;
286 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
292 switch (flags & ~WINEDDCKEY_COLORSPACE)
294 case WINEDDCKEY_DESTBLT:
295 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
298 case WINEDDCKEY_DESTOVERLAY:
299 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
302 case WINEDDCKEY_SRCOVERLAY:
303 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
306 case WINEDDCKEY_SRCBLT:
307 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
315 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
317 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
319 TRACE("iface %p, palette %p.\n", iface, palette);
321 *palette = This->palette;
326 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
328 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
329 const struct wined3d_format *format = This->resource.format;
331 TRACE("(%p)\n", This);
333 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
335 /* Since compressed formats are block based, pitch means the amount of
336 * bytes to the next row of block rather than the next row of pixels. */
337 UINT row_block_count = (This->resource.width + format->block_width - 1) / format->block_width;
338 ret = row_block_count * format->block_byte_count;
342 unsigned char alignment = This->resource.device->surface_alignment;
343 ret = This->resource.format->byte_count * This->resource.width; /* Bytes / row */
344 ret = (ret + alignment - 1) & ~(alignment - 1);
346 TRACE("(%p) Returning %d\n", This, ret);
350 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
351 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
354 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
356 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
358 TRACE("(%p): Not an overlay surface\n", This);
359 return WINEDDERR_NOTAOVERLAYSURFACE;
362 w = This->overlay_destrect.right - This->overlay_destrect.left;
363 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
364 This->overlay_destrect.left = X;
365 This->overlay_destrect.top = Y;
366 This->overlay_destrect.right = X + w;
367 This->overlay_destrect.bottom = Y + h;
369 This->surface_ops->surface_draw_overlay(This);
374 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
375 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
378 TRACE("(%p)->(%p,%p)\n", This, X, Y);
380 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
382 TRACE("(%p): Not an overlay surface\n", This);
383 return WINEDDERR_NOTAOVERLAYSURFACE;
386 if (!This->overlay_dest)
389 hr = WINEDDERR_OVERLAYNOTVISIBLE;
391 *X = This->overlay_destrect.left;
392 *Y = This->overlay_destrect.top;
396 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
400 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
402 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
404 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
406 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
408 TRACE("(%p): Not an overlay surface\n", This);
409 return WINEDDERR_NOTAOVERLAYSURFACE;
415 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
416 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
418 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
419 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
421 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
422 iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
424 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
426 WARN("(%p): Not an overlay surface\n", This);
427 return WINEDDERR_NOTAOVERLAYSURFACE;
428 } else if(!DstSurface) {
429 WARN("(%p): Dest surface is NULL\n", This);
430 return WINED3DERR_INVALIDCALL;
434 This->overlay_srcrect = *SrcRect;
436 This->overlay_srcrect.left = 0;
437 This->overlay_srcrect.top = 0;
438 This->overlay_srcrect.right = This->resource.width;
439 This->overlay_srcrect.bottom = This->resource.height;
443 This->overlay_destrect = *DstRect;
445 This->overlay_destrect.left = 0;
446 This->overlay_destrect.top = 0;
447 This->overlay_destrect.right = Dst ? Dst->resource.width : 0;
448 This->overlay_destrect.bottom = Dst ? Dst->resource.height : 0;
451 if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
453 list_remove(&This->overlay_entry);
456 if (flags & WINEDDOVER_SHOW)
458 if (This->overlay_dest != Dst)
460 This->overlay_dest = Dst;
461 list_add_tail(&Dst->overlays, &This->overlay_entry);
464 else if (flags & WINEDDOVER_HIDE)
466 /* tests show that the rectangles are erased on hide */
467 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
468 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
469 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
470 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
471 This->overlay_dest = NULL;
474 This->surface_ops->surface_draw_overlay(This);
479 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
481 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
483 TRACE("iface %p, clipper %p.\n", iface, clipper);
485 This->clipper = clipper;
490 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
492 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
494 TRACE("iface %p, clipper %p.\n", iface, clipper);
496 *clipper = This->clipper;
498 wined3d_clipper_incref(*clipper);
503 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
505 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
506 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
508 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
510 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
511 return WINED3DERR_INVALIDCALL;
514 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
516 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
517 This->pow2Width, This->pow2Height);
519 This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
521 This->resource.format = format;
523 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
528 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
530 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
531 const struct wined3d_format *format = This->resource.format;
539 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
541 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
542 return WINED3DERR_INVALIDCALL;
545 switch (format->byte_count)
549 /* Allocate extra space to store the RGB bit masks. */
550 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
554 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
558 /* Allocate extra space for a palette. */
559 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
560 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
565 return E_OUTOFMEMORY;
567 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
568 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
569 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
570 * add an extra line to the dib section
572 GetSystemInfo(&sysInfo);
573 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
575 TRACE("Adding an extra line to the dib section\n");
578 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
579 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
580 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
581 b_info->bmiHeader.biHeight = -This->resource.height - extraline;
582 b_info->bmiHeader.biSizeImage = (This->resource.height + extraline) * IWineD3DSurface_GetPitch(iface);
583 b_info->bmiHeader.biPlanes = 1;
584 b_info->bmiHeader.biBitCount = format->byte_count * 8;
586 b_info->bmiHeader.biXPelsPerMeter = 0;
587 b_info->bmiHeader.biYPelsPerMeter = 0;
588 b_info->bmiHeader.biClrUsed = 0;
589 b_info->bmiHeader.biClrImportant = 0;
591 /* Get the bit masks */
592 masks = (DWORD *)b_info->bmiColors;
593 switch (This->resource.format->id)
595 case WINED3DFMT_B8G8R8_UNORM:
596 usage = DIB_RGB_COLORS;
597 b_info->bmiHeader.biCompression = BI_RGB;
600 case WINED3DFMT_B5G5R5X1_UNORM:
601 case WINED3DFMT_B5G5R5A1_UNORM:
602 case WINED3DFMT_B4G4R4A4_UNORM:
603 case WINED3DFMT_B4G4R4X4_UNORM:
604 case WINED3DFMT_B2G3R3_UNORM:
605 case WINED3DFMT_B2G3R3A8_UNORM:
606 case WINED3DFMT_R10G10B10A2_UNORM:
607 case WINED3DFMT_R8G8B8A8_UNORM:
608 case WINED3DFMT_R8G8B8X8_UNORM:
609 case WINED3DFMT_B10G10R10A2_UNORM:
610 case WINED3DFMT_B5G6R5_UNORM:
611 case WINED3DFMT_R16G16B16A16_UNORM:
613 b_info->bmiHeader.biCompression = BI_BITFIELDS;
614 masks[0] = format->red_mask;
615 masks[1] = format->green_mask;
616 masks[2] = format->blue_mask;
620 /* Don't know palette */
621 b_info->bmiHeader.biCompression = BI_RGB;
626 if (!(ddc = GetDC(0)))
628 HeapFree(GetProcessHeap(), 0, b_info);
629 return HRESULT_FROM_WIN32(GetLastError());
632 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
633 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
636 if (!This->dib.DIBsection) {
637 ERR("CreateDIBSection failed!\n");
638 HeapFree(GetProcessHeap(), 0, b_info);
639 return HRESULT_FROM_WIN32(GetLastError());
642 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
643 /* copy the existing surface to the dib section */
644 if (This->resource.allocatedMemory)
646 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,
647 This->resource.height * IWineD3DSurface_GetPitch(iface));
651 /* This is to make LockRect read the gl Texture although memory is allocated */
652 This->flags &= ~SFLAG_INSYSMEM;
654 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
656 HeapFree(GetProcessHeap(), 0, b_info);
658 /* Now allocate a HDC */
659 This->hDC = CreateCompatibleDC(0);
660 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
661 TRACE("using wined3d palette %p\n", This->palette);
662 SelectPalette(This->hDC,
663 This->palette ? This->palette->hpal : 0,
666 This->flags |= SFLAG_DIBSECTION;
668 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
669 This->resource.heapMemory = NULL;
674 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
675 unsigned int w, unsigned int h)
679 unsigned short *dst_s;
681 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
682 for(y = 0; y < h; y++) {
683 src_f = (const float *)(src + y * pitch_in);
684 dst_s = (unsigned short *) (dst + y * pitch_out);
685 for(x = 0; x < w; x++) {
686 dst_s[x] = float_32_to_16(src_f + x);
691 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
692 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
694 static const unsigned char convert_5to8[] =
696 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
697 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
698 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
699 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
701 static const unsigned char convert_6to8[] =
703 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
704 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
705 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
706 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
707 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
708 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
709 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
710 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
714 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
716 for (y = 0; y < h; ++y)
718 const WORD *src_line = (const WORD *)(src + y * pitch_in);
719 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
720 for (x = 0; x < w; ++x)
722 WORD pixel = src_line[x];
723 dst_line[x] = 0xff000000
724 | convert_5to8[(pixel & 0xf800) >> 11] << 16
725 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
726 | convert_5to8[(pixel & 0x001f)];
731 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
732 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
736 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
738 for (y = 0; y < h; ++y)
740 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
741 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
743 for (x = 0; x < w; ++x)
745 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
750 static inline BYTE cliptobyte(int x)
752 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
755 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
756 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
759 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
761 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
763 for (y = 0; y < h; ++y)
765 const BYTE *src_line = src + y * pitch_in;
766 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
767 for (x = 0; x < w; ++x)
769 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
770 * C = Y - 16; D = U - 128; E = V - 128;
771 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
772 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
773 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
774 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
775 * U and V are shared between the pixels.
777 if (!(x & 1)) /* for every even pixel, read new U and V */
779 d = (int) src_line[1] - 128;
780 e = (int) src_line[3] - 128;
782 g2 = - 100 * d - 208 * e + 128;
785 c2 = 298 * ((int) src_line[0] - 16);
786 dst_line[x] = 0xff000000
787 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
788 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
789 | cliptobyte((c2 + b2) >> 8); /* blue */
790 /* Scale RGB values to 0..255 range,
791 * then clip them if still not in range (may be negative),
792 * then shift them within DWORD if necessary.
799 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
800 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
803 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
805 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
807 for (y = 0; y < h; ++y)
809 const BYTE *src_line = src + y * pitch_in;
810 WORD *dst_line = (WORD *)(dst + y * pitch_out);
811 for (x = 0; x < w; ++x)
813 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
814 * C = Y - 16; D = U - 128; E = V - 128;
815 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
816 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
817 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
818 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
819 * U and V are shared between the pixels.
821 if (!(x & 1)) /* for every even pixel, read new U and V */
823 d = (int) src_line[1] - 128;
824 e = (int) src_line[3] - 128;
826 g2 = - 100 * d - 208 * e + 128;
829 c2 = 298 * ((int) src_line[0] - 16);
830 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
831 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
832 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
833 /* Scale RGB values to 0..255 range,
834 * then clip them if still not in range (may be negative),
835 * then shift them within DWORD if necessary.
842 struct d3dfmt_convertor_desc
844 enum wined3d_format_id from, to;
845 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
848 static const struct d3dfmt_convertor_desc convertors[] =
850 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
851 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
852 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
853 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
854 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
857 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
860 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
861 if(convertors[i].from == from && convertors[i].to == to) {
862 return &convertors[i];
868 /*****************************************************************************
869 * surface_convert_format
871 * Creates a duplicate of a surface in a different format. Is used by Blt to
872 * blit between surfaces with different formats
875 * source: Source surface
876 * fmt: Requested destination format
878 *****************************************************************************/
879 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
881 IWineD3DSurface *ret = NULL;
882 const struct d3dfmt_convertor_desc *conv;
883 WINED3DLOCKED_RECT lock_src, lock_dst;
886 conv = find_convertor(source->resource.format->id, to_fmt);
889 FIXME("Cannot find a conversion function from format %s to %s.\n",
890 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
894 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
895 source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
896 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
897 0 /* MultiSampleQuality */, source->surface_type, NULL /* parent */, &wined3d_null_parent_ops, &ret);
899 ERR("Failed to create a destination surface for conversion\n");
903 memset(&lock_src, 0, sizeof(lock_src));
904 memset(&lock_dst, 0, sizeof(lock_dst));
906 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
909 ERR("Failed to lock the source surface.\n");
910 IWineD3DSurface_Release(ret);
913 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
916 ERR("Failed to lock the dest surface\n");
917 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
918 IWineD3DSurface_Release(ret);
922 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
923 source->resource.width, source->resource.height);
925 IWineD3DSurface_Unmap(ret);
926 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
928 return (IWineD3DSurfaceImpl *) ret;
931 /*****************************************************************************
934 * Helper function that fills a memory area with a specific color
937 * buf: memory address to start filling at
938 * width, height: Dimensions of the area to fill
939 * bpp: Bit depth of the surface
940 * lPitch: pitch of the surface
941 * color: Color to fill with
943 *****************************************************************************/
945 _Blt_ColorFill(BYTE *buf,
946 int width, int height,
947 int bpp, LONG lPitch,
955 #define COLORFILL_ROW(type) \
957 type *d = (type *) buf; \
958 for (x = 0; x < width; x++) \
959 d[x] = (type) color; \
964 case 1: COLORFILL_ROW(BYTE)
965 case 2: COLORFILL_ROW(WORD)
969 for (x = 0; x < width; x++,d+=3)
971 d[0] = (color ) & 0xFF;
972 d[1] = (color>> 8) & 0xFF;
973 d[2] = (color>>16) & 0xFF;
977 case 4: COLORFILL_ROW(DWORD)
979 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
980 return WINED3DERR_NOTAVAILABLE;
985 /* Now copy first row */
987 for (y = 1; y < height; y++)
990 memcpy(buf, first, width * bpp);
995 /*****************************************************************************
996 * IWineD3DSurface::Blt, SW emulation version
998 * Performs a blit to a surface, with or without a source surface.
999 * This is the main functionality of DirectDraw
1002 * DestRect: Destination rectangle to write to
1003 * src_surface: Source surface, can be NULL
1004 * SrcRect: Source rectangle
1005 *****************************************************************************/
1006 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
1007 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
1009 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1010 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1012 HRESULT ret = WINED3D_OK;
1013 WINED3DLOCKED_RECT dlock, slock;
1014 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
1015 const struct wined3d_format *sEntry, *dEntry;
1020 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1021 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
1022 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
1024 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
1026 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1027 return WINEDDERR_SURFACEBUSY;
1030 /* First check for the validity of source / destination rectangles.
1031 * This was verified using a test application + by MSDN. */
1037 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
1038 || SrcRect->left > src->resource.width || SrcRect->left < 0
1039 || SrcRect->top > src->resource.height || SrcRect->top < 0
1040 || SrcRect->right > src->resource.width || SrcRect->right < 0
1041 || SrcRect->bottom > src->resource.height || SrcRect->bottom < 0)
1043 WARN("Application gave us bad source rectangle for Blt.\n");
1044 return WINEDDERR_INVALIDRECT;
1047 if (!SrcRect->right || !SrcRect->bottom
1048 || SrcRect->left == (int)src->resource.width
1049 || SrcRect->top == (int)src->resource.height)
1051 TRACE("Nothing to be done.\n");
1062 xsrc.right = src->resource.width;
1063 xsrc.bottom = src->resource.height;
1067 memset(&xsrc, 0, sizeof(xsrc));
1072 /* For the Destination rect, it can be out of bounds on the condition
1073 * that a clipper is set for the given surface. */
1074 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1075 || DestRect->left > This->resource.width || DestRect->left < 0
1076 || DestRect->top > This->resource.height || DestRect->top < 0
1077 || DestRect->right > This->resource.width || DestRect->right < 0
1078 || DestRect->bottom > This->resource.height || DestRect->bottom < 0))
1080 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1081 return WINEDDERR_INVALIDRECT;
1084 if (DestRect->right <= 0 || DestRect->bottom <= 0
1085 || DestRect->left >= (int)This->resource.width
1086 || DestRect->top >= (int)This->resource.height)
1088 TRACE("Nothing to be done.\n");
1098 full_rect.right = This->resource.width;
1099 full_rect.bottom = This->resource.height;
1100 IntersectRect(&xdst, &full_rect, DestRect);
1104 BOOL clip_horiz, clip_vert;
1107 clip_horiz = xdst.left < 0 || xdst.right > (int)This->resource.width;
1108 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->resource.height;
1110 if (clip_vert || clip_horiz)
1112 /* Now check if this is a special case or not... */
1113 if ((flags & WINEDDBLT_DDFX)
1114 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1115 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1117 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1125 xsrc.left -= xdst.left;
1128 if (xdst.right > This->resource.width)
1130 xsrc.right -= (xdst.right - (int)This->resource.width);
1131 xdst.right = (int)This->resource.width;
1139 xsrc.top -= xdst.top;
1142 if (xdst.bottom > This->resource.height)
1144 xsrc.bottom -= (xdst.bottom - (int)This->resource.height);
1145 xdst.bottom = (int)This->resource.height;
1149 /* And check if after clipping something is still to be done... */
1150 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1151 || (xdst.left >= (int)This->resource.width)
1152 || (xdst.top >= (int)This->resource.height)
1153 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1154 || (xsrc.left >= (int)src->resource.width)
1155 || (xsrc.top >= (int)src->resource.height))
1157 TRACE("Nothing to be done after clipping.\n");
1167 xdst.right = This->resource.width;
1168 xdst.bottom = This->resource.height;
1173 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1175 sEntry = This->resource.format;
1180 dEntry = This->resource.format;
1183 if (This->resource.format->id != src->resource.format->id)
1185 src = surface_convert_format(src, dEntry->id);
1188 /* The conv function writes a FIXME */
1189 WARN("Cannot convert source surface format to dest format\n");
1193 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1194 sEntry = src->resource.format;
1201 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1203 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1206 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1208 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1210 if (!DestRect || src == This)
1212 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1217 bpp = This->resource.format->byte_count;
1218 srcheight = xsrc.bottom - xsrc.top;
1219 srcwidth = xsrc.right - xsrc.left;
1220 dstheight = xdst.bottom - xdst.top;
1221 dstwidth = xdst.right - xdst.left;
1222 width = (xdst.right - xdst.left) * bpp;
1224 if (DestRect && src != This)
1227 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1229 if (flags & WINEDDBLT_WAIT)
1231 flags &= ~WINEDDBLT_WAIT;
1233 if (flags & WINEDDBLT_ASYNC)
1235 static BOOL displayed = FALSE;
1237 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1239 flags &= ~WINEDDBLT_ASYNC;
1241 if (flags & WINEDDBLT_DONOTWAIT)
1243 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1244 static BOOL displayed = FALSE;
1246 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1248 flags &= ~WINEDDBLT_DONOTWAIT;
1251 /* First, all the 'source-less' blits */
1252 if (flags & WINEDDBLT_COLORFILL)
1254 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1255 dlock.Pitch, DDBltFx->u5.dwFillColor);
1256 flags &= ~WINEDDBLT_COLORFILL;
1259 if (flags & WINEDDBLT_DEPTHFILL)
1261 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1263 if (flags & WINEDDBLT_ROP)
1265 /* Catch some degenerate cases here */
1266 switch(DDBltFx->dwROP)
1269 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1271 case 0xAA0029: /* No-op */
1274 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1276 case SRCCOPY: /* well, we do that below ? */
1279 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1282 flags &= ~WINEDDBLT_ROP;
1284 if (flags & WINEDDBLT_DDROPS)
1286 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1288 /* Now the 'with source' blits */
1292 int sx, xinc, sy, yinc;
1294 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1297 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1298 && (srcwidth != dstwidth || srcheight != dstheight))
1300 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1301 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1304 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1305 xinc = (srcwidth << 16) / dstwidth;
1306 yinc = (srcheight << 16) / dstheight;
1310 /* No effects, we can cheat here */
1311 if (dstwidth == srcwidth)
1313 if (dstheight == srcheight)
1315 /* No stretching in either direction. This needs to be as
1316 * fast as possible */
1319 /* check for overlapping surfaces */
1320 if (src != This || xdst.top < xsrc.top ||
1321 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1323 /* no overlap, or dst above src, so copy from top downwards */
1324 for (y = 0; y < dstheight; y++)
1326 memcpy(dbuf, sbuf, width);
1327 sbuf += slock.Pitch;
1328 dbuf += dlock.Pitch;
1331 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1333 sbuf += (slock.Pitch*dstheight);
1334 dbuf += (dlock.Pitch*dstheight);
1335 for (y = 0; y < dstheight; y++)
1337 sbuf -= slock.Pitch;
1338 dbuf -= dlock.Pitch;
1339 memcpy(dbuf, sbuf, width);
1342 else /* src and dst overlapping on the same line, use memmove */
1344 for (y = 0; y < dstheight; y++)
1346 memmove(dbuf, sbuf, width);
1347 sbuf += slock.Pitch;
1348 dbuf += dlock.Pitch;
1352 /* Stretching in Y direction only */
1353 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1354 sbuf = sbase + (sy >> 16) * slock.Pitch;
1355 memcpy(dbuf, sbuf, width);
1356 dbuf += dlock.Pitch;
1362 /* Stretching in X direction */
1364 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1366 sbuf = sbase + (sy >> 16) * slock.Pitch;
1368 if ((sy >> 16) == (last_sy >> 16))
1370 /* this sourcerow is the same as last sourcerow -
1371 * copy already stretched row
1373 memcpy(dbuf, dbuf - dlock.Pitch, width);
1377 #define STRETCH_ROW(type) { \
1378 const type *s = (const type *)sbuf; \
1379 type *d = (type *)dbuf; \
1380 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1381 d[x] = s[sx >> 16]; \
1386 case 1: STRETCH_ROW(BYTE)
1387 case 2: STRETCH_ROW(WORD)
1388 case 4: STRETCH_ROW(DWORD)
1393 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1397 s = sbuf+3*(sx>>16);
1398 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1399 d[0] = (pixel )&0xff;
1400 d[1] = (pixel>> 8)&0xff;
1401 d[2] = (pixel>>16)&0xff;
1407 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1408 ret = WINED3DERR_NOTAVAILABLE;
1413 dbuf += dlock.Pitch;
1420 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1421 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1422 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1423 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1425 /* The color keying flags are checked for correctness in ddraw */
1426 if (flags & WINEDDBLT_KEYSRC)
1428 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1429 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1431 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1433 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1434 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1437 if (flags & WINEDDBLT_KEYDEST)
1439 /* Destination color keys are taken from the source surface ! */
1440 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1441 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1443 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1445 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1446 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1455 keymask = sEntry->red_mask
1456 | sEntry->green_mask
1457 | sEntry->blue_mask;
1459 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1462 if (flags & WINEDDBLT_DDFX)
1464 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1467 dTopRight = dbuf+((dstwidth-1)*bpp);
1468 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1469 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1471 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1473 /* I don't think we need to do anything about this flag */
1474 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1476 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1479 dTopRight = dTopLeft;
1482 dBottomRight = dBottomLeft;
1484 dstxinc = dstxinc *-1;
1486 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1489 dTopLeft = dBottomLeft;
1492 dTopRight = dBottomRight;
1494 dstyinc = dstyinc *-1;
1496 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1498 /* I don't think we need to do anything about this flag */
1499 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1501 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1504 dBottomRight = dTopLeft;
1507 dBottomLeft = dTopRight;
1509 dstxinc = dstxinc * -1;
1510 dstyinc = dstyinc * -1;
1512 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1515 dTopLeft = dBottomLeft;
1516 dBottomLeft = dBottomRight;
1517 dBottomRight = dTopRight;
1522 dstxinc = dstxinc * -1;
1524 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1527 dTopLeft = dTopRight;
1528 dTopRight = dBottomRight;
1529 dBottomRight = dBottomLeft;
1534 dstyinc = dstyinc * -1;
1536 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1538 /* I don't think we need to do anything about this flag */
1539 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1542 flags &= ~(WINEDDBLT_DDFX);
1545 #define COPY_COLORKEY_FX(type) { \
1547 type *d = (type *)dbuf, *dx, tmp; \
1548 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1549 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1551 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1552 tmp = s[sx >> 16]; \
1553 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1554 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1557 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1559 d = (type*)(((LPBYTE)d)+dstyinc); \
1564 case 1: COPY_COLORKEY_FX(BYTE)
1565 case 2: COPY_COLORKEY_FX(WORD)
1566 case 4: COPY_COLORKEY_FX(DWORD)
1570 BYTE *d = dbuf, *dx;
1571 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1573 sbuf = sbase + (sy >> 16) * slock.Pitch;
1575 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1577 DWORD pixel, dpixel = 0;
1578 s = sbuf+3*(sx>>16);
1579 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1580 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1581 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1582 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1584 dx[0] = (pixel )&0xff;
1585 dx[1] = (pixel>> 8)&0xff;
1586 dx[2] = (pixel>>16)&0xff;
1595 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1596 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1597 ret = WINED3DERR_NOTAVAILABLE;
1599 #undef COPY_COLORKEY_FX
1605 if (flags && FIXME_ON(d3d_surface))
1607 FIXME("\tUnsupported flags: %#x.\n", flags);
1611 IWineD3DSurface_Unmap(iface);
1612 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1613 /* Release the converted surface if any */
1614 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1618 /*****************************************************************************
1619 * IWineD3DSurface::BltFast, SW emulation version
1621 * This is the software implementation of BltFast, as used by GDI surfaces
1622 * and as a fallback for OpenGL surfaces. This code is taken from the old
1623 * DirectDraw code, and was originally written by TransGaming.
1628 * src_surface: Source surface to copy from
1629 * rsrc: Source rectangle
1633 * WINED3D_OK on success
1635 *****************************************************************************/
1636 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1637 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1639 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1640 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1642 int bpp, w, h, x, y;
1643 WINED3DLOCKED_RECT dlock,slock;
1644 HRESULT ret = WINED3D_OK;
1646 RECT lock_src, lock_dst, lock_union;
1649 const struct wined3d_format *sEntry, *dEntry;
1651 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1652 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1654 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1656 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1657 return WINEDDERR_SURFACEBUSY;
1662 WARN("rsrc is NULL!\n");
1665 rsrc2.right = src->resource.width;
1666 rsrc2.bottom = src->resource.height;
1670 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1671 if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
1672 || (rsrc->top > src->resource.height) || (rsrc->top < 0)
1673 || (rsrc->left > src->resource.width) || (rsrc->left < 0)
1674 || (rsrc->right > src->resource.width) || (rsrc->right < 0)
1675 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1677 WARN("Application gave us bad source rectangle for BltFast.\n");
1678 return WINEDDERR_INVALIDRECT;
1681 h = rsrc->bottom - rsrc->top;
1682 if (h > This->resource.height-dsty)
1683 h = This->resource.height-dsty;
1684 if (h > src->resource.height-rsrc->top)
1685 h = src->resource.height-rsrc->top;
1687 return WINEDDERR_INVALIDRECT;
1689 w = rsrc->right - rsrc->left;
1690 if (w > This->resource.width-dstx)
1691 w = This->resource.width-dstx;
1692 if (w > src->resource.width-rsrc->left)
1693 w = src->resource.width-rsrc->left;
1695 return WINEDDERR_INVALIDRECT;
1697 /* Now compute the locking rectangle... */
1698 lock_src.left = rsrc->left;
1699 lock_src.top = rsrc->top;
1700 lock_src.right = lock_src.left + w;
1701 lock_src.bottom = lock_src.top + h;
1703 lock_dst.left = dstx;
1704 lock_dst.top = dsty;
1705 lock_dst.right = dstx + w;
1706 lock_dst.bottom = dsty + h;
1708 bpp = This->resource.format->byte_count;
1710 /* We need to lock the surfaces, or we won't get refreshes when done. */
1715 UnionRect(&lock_union, &lock_src, &lock_dst);
1717 /* Lock the union of the two rectangles */
1718 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1719 if (FAILED(ret)) goto error;
1721 pitch = dlock.Pitch;
1722 slock.Pitch = dlock.Pitch;
1724 /* Since slock was originally copied from this surface's description, we can just reuse it */
1725 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1726 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1727 sEntry = src->resource.format;
1732 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1733 if (FAILED(ret)) goto error;
1734 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1735 if (FAILED(ret)) goto error;
1739 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1741 sEntry = src->resource.format;
1742 dEntry = This->resource.format;
1745 /* Handle compressed surfaces first... */
1746 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1748 UINT row_block_count;
1750 TRACE("compressed -> compressed copy\n");
1752 FIXME("trans arg not supported when a compressed surface is involved\n");
1754 FIXME("offset for destination surface is not supported\n");
1755 if (src->resource.format->id != This->resource.format->id)
1757 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1758 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1762 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1763 for (y = 0; y < h; y += dEntry->block_height)
1765 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1766 dbuf += dlock.Pitch;
1767 sbuf += slock.Pitch;
1772 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1774 /* TODO: Use the libtxc_dxtn.so shared library to do
1775 * software decompression
1777 ERR("Software decompression not supported.\n");
1781 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1783 DWORD keylow, keyhigh;
1784 DWORD mask = src->resource.format->red_mask
1785 | src->resource.format->green_mask
1786 | src->resource.format->blue_mask;
1788 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1792 TRACE("Color keyed copy\n");
1793 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1795 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1796 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1800 /* I'm not sure if this is correct */
1801 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1802 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1803 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1806 #define COPYBOX_COLORKEY(type) { \
1807 const type *s = (const type *)sbuf; \
1808 type *d = (type *)dbuf; \
1810 for (y = 0; y < h; y++) { \
1811 for (x = 0; x < w; x++) { \
1813 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1815 s = (const type *)((const BYTE *)s + slock.Pitch); \
1816 d = (type *)((BYTE *)d + dlock.Pitch); \
1822 case 1: COPYBOX_COLORKEY(BYTE)
1823 case 2: COPYBOX_COLORKEY(WORD)
1824 case 4: COPYBOX_COLORKEY(DWORD)
1832 for (y = 0; y < h; y++)
1834 for (x = 0; x < w * 3; x += 3)
1836 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1837 if (tmp < keylow || tmp > keyhigh)
1839 d[x + 0] = s[x + 0];
1840 d[x + 1] = s[x + 1];
1841 d[x + 2] = s[x + 2];
1850 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1851 ret = WINED3DERR_NOTAVAILABLE;
1854 #undef COPYBOX_COLORKEY
1855 TRACE("Copy Done\n");
1859 int width = w * bpp;
1860 INT sbufpitch, dbufpitch;
1862 TRACE("NO color key copy\n");
1863 /* Handle overlapping surfaces */
1866 sbuf += (h - 1) * slock.Pitch;
1867 dbuf += (h - 1) * dlock.Pitch;
1868 sbufpitch = -slock.Pitch;
1869 dbufpitch = -dlock.Pitch;
1873 sbufpitch = slock.Pitch;
1874 dbufpitch = dlock.Pitch;
1876 for (y = 0; y < h; y++)
1878 /* This is pretty easy, a line for line memcpy */
1879 memmove(dbuf, sbuf, width);
1883 TRACE("Copy done\n");
1889 IWineD3DSurface_Unmap(iface);
1893 IWineD3DSurface_Unmap(iface);
1894 IWineD3DSurface_Unmap(src_surface);
1900 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1901 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1903 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1905 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1906 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1908 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1912 pLockedRect->pBits = This->resource.allocatedMemory;
1913 This->lockedRect.left = 0;
1914 This->lockedRect.top = 0;
1915 This->lockedRect.right = This->resource.width;
1916 This->lockedRect.bottom = This->resource.height;
1918 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1919 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1920 This->lockedRect.right, This->lockedRect.bottom);
1924 const struct wined3d_format *format = This->resource.format;
1926 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1927 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1929 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1931 /* Compressed textures are block based, so calculate the offset of
1932 * the block that contains the top-left pixel of the locked rectangle. */
1933 pLockedRect->pBits = This->resource.allocatedMemory
1934 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1935 + ((pRect->left / format->block_width) * format->block_byte_count);
1939 pLockedRect->pBits = This->resource.allocatedMemory +
1940 (pLockedRect->Pitch * pRect->top) +
1941 (pRect->left * format->byte_count);
1943 This->lockedRect.left = pRect->left;
1944 This->lockedRect.top = pRect->top;
1945 This->lockedRect.right = pRect->right;
1946 This->lockedRect.bottom = pRect->bottom;
1949 /* No dirtifying is needed for this surface implementation */
1950 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);