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_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 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
115 REFGUID riid, const void *data, DWORD data_size, DWORD flags)
117 return resource_set_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, riid, data, data_size, flags);
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
121 REFGUID guid, void *data, DWORD *data_size)
123 return resource_get_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, guid, data, data_size);
126 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
128 return resource_free_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, refguid);
131 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
133 return resource_set_priority(&((IWineD3DSurfaceImpl *)iface)->resource, priority);
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
138 return resource_get_priority(&((IWineD3DSurfaceImpl *)iface)->resource);
141 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface)
143 return resource_get_type(&((IWineD3DSurfaceImpl *)iface)->resource);
146 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
148 TRACE("iface %p.\n", iface);
150 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
153 struct wined3d_resource * WINAPI IWineD3DBaseSurfaceImpl_GetResource(IWineD3DSurface *iface)
155 TRACE("iface %p.\n", iface);
157 return &((IWineD3DSurfaceImpl *)iface)->resource;
160 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
162 TRACE("iface %p, flags %#x.\n", iface, flags);
166 case WINEDDGBS_CANBLT:
167 case WINEDDGBS_ISBLTDONE:
171 return WINED3DERR_INVALIDCALL;
175 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
177 /* XXX: DDERR_INVALIDSURFACETYPE */
179 TRACE("iface %p, flags %#x.\n", iface, flags);
183 case WINEDDGFS_CANFLIP:
184 case WINEDDGFS_ISFLIPDONE:
188 return WINED3DERR_INVALIDCALL;
192 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
193 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
194 TRACE("(%p)\n", This);
196 /* D3D8 and 9 loose full devices, ddraw only surfaces */
197 return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
200 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
201 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
202 TRACE("(%p)\n", This);
204 /* So far we don't lose anything :) */
205 This->flags &= ~SFLAG_LOST;
209 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
211 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
213 TRACE("iface %p, palette %p.\n", iface, palette);
215 if (This->palette == palette)
217 TRACE("Nop palette change\n");
222 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
223 This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
225 This->palette = palette;
229 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
230 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
232 This->surface_ops->surface_realize_palette(This);
238 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
240 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
242 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
244 if (flags & WINEDDCKEY_COLORSPACE)
246 FIXME(" colorkey value not supported (%08x) !\n", flags);
247 return WINED3DERR_INVALIDCALL;
250 /* Dirtify the surface, but only if a key was changed */
253 switch (flags & ~WINEDDCKEY_COLORSPACE)
255 case WINEDDCKEY_DESTBLT:
256 This->DestBltCKey = *CKey;
257 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
260 case WINEDDCKEY_DESTOVERLAY:
261 This->DestOverlayCKey = *CKey;
262 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
265 case WINEDDCKEY_SRCOVERLAY:
266 This->SrcOverlayCKey = *CKey;
267 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
270 case WINEDDCKEY_SRCBLT:
271 This->SrcBltCKey = *CKey;
272 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
278 switch (flags & ~WINEDDCKEY_COLORSPACE)
280 case WINEDDCKEY_DESTBLT:
281 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
284 case WINEDDCKEY_DESTOVERLAY:
285 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
288 case WINEDDCKEY_SRCOVERLAY:
289 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
292 case WINEDDCKEY_SRCBLT:
293 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
301 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
303 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
305 TRACE("iface %p, palette %p.\n", iface, palette);
307 *palette = This->palette;
312 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
314 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
315 const struct wined3d_format *format = This->resource.format;
317 TRACE("(%p)\n", This);
319 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
321 /* Since compressed formats are block based, pitch means the amount of
322 * bytes to the next row of block rather than the next row of pixels. */
323 UINT row_block_count = (This->resource.width + format->block_width - 1) / format->block_width;
324 ret = row_block_count * format->block_byte_count;
328 unsigned char alignment = This->resource.device->surface_alignment;
329 ret = This->resource.format->byte_count * This->resource.width; /* Bytes / row */
330 ret = (ret + alignment - 1) & ~(alignment - 1);
332 TRACE("(%p) Returning %d\n", This, ret);
336 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
337 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
340 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
342 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
344 TRACE("(%p): Not an overlay surface\n", This);
345 return WINEDDERR_NOTAOVERLAYSURFACE;
348 w = This->overlay_destrect.right - This->overlay_destrect.left;
349 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
350 This->overlay_destrect.left = X;
351 This->overlay_destrect.top = Y;
352 This->overlay_destrect.right = X + w;
353 This->overlay_destrect.bottom = Y + h;
355 This->surface_ops->surface_draw_overlay(This);
360 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
361 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
364 TRACE("(%p)->(%p,%p)\n", This, X, Y);
366 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
368 TRACE("(%p): Not an overlay surface\n", This);
369 return WINEDDERR_NOTAOVERLAYSURFACE;
372 if (!This->overlay_dest)
375 hr = WINEDDERR_OVERLAYNOTVISIBLE;
377 *X = This->overlay_destrect.left;
378 *Y = This->overlay_destrect.top;
382 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
386 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
388 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
390 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
392 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
394 TRACE("(%p): Not an overlay surface\n", This);
395 return WINEDDERR_NOTAOVERLAYSURFACE;
401 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
402 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
404 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
405 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
407 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
408 iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
410 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
412 WARN("(%p): Not an overlay surface\n", This);
413 return WINEDDERR_NOTAOVERLAYSURFACE;
414 } else if(!DstSurface) {
415 WARN("(%p): Dest surface is NULL\n", This);
416 return WINED3DERR_INVALIDCALL;
420 This->overlay_srcrect = *SrcRect;
422 This->overlay_srcrect.left = 0;
423 This->overlay_srcrect.top = 0;
424 This->overlay_srcrect.right = This->resource.width;
425 This->overlay_srcrect.bottom = This->resource.height;
429 This->overlay_destrect = *DstRect;
431 This->overlay_destrect.left = 0;
432 This->overlay_destrect.top = 0;
433 This->overlay_destrect.right = Dst ? Dst->resource.width : 0;
434 This->overlay_destrect.bottom = Dst ? Dst->resource.height : 0;
437 if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
439 list_remove(&This->overlay_entry);
442 if (flags & WINEDDOVER_SHOW)
444 if (This->overlay_dest != Dst)
446 This->overlay_dest = Dst;
447 list_add_tail(&Dst->overlays, &This->overlay_entry);
450 else if (flags & WINEDDOVER_HIDE)
452 /* tests show that the rectangles are erased on hide */
453 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
454 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
455 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
456 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
457 This->overlay_dest = NULL;
460 This->surface_ops->surface_draw_overlay(This);
465 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
467 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
469 TRACE("iface %p, clipper %p.\n", iface, clipper);
471 This->clipper = clipper;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
480 TRACE("iface %p, clipper %p.\n", iface, clipper);
482 *clipper = This->clipper;
484 wined3d_clipper_incref(*clipper);
489 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
491 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
492 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
494 if (This->resource.format->id != 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 %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
502 This->resource.size = wined3d_format_calculate_size(format, 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 = format;
509 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
514 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
516 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
517 const struct wined3d_format *format = This->resource.format;
525 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
527 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
528 return WINED3DERR_INVALIDCALL;
531 switch (format->byte_count)
535 /* Allocate extra space to store the RGB bit masks. */
536 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
540 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
544 /* Allocate extra space for a palette. */
545 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
546 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
551 return E_OUTOFMEMORY;
553 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
554 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
555 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
556 * add an extra line to the dib section
558 GetSystemInfo(&sysInfo);
559 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
561 TRACE("Adding an extra line to the dib section\n");
564 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
565 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
566 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
567 b_info->bmiHeader.biHeight = -This->resource.height - extraline;
568 b_info->bmiHeader.biSizeImage = (This->resource.height + extraline) * IWineD3DSurface_GetPitch(iface);
569 b_info->bmiHeader.biPlanes = 1;
570 b_info->bmiHeader.biBitCount = format->byte_count * 8;
572 b_info->bmiHeader.biXPelsPerMeter = 0;
573 b_info->bmiHeader.biYPelsPerMeter = 0;
574 b_info->bmiHeader.biClrUsed = 0;
575 b_info->bmiHeader.biClrImportant = 0;
577 /* Get the bit masks */
578 masks = (DWORD *)b_info->bmiColors;
579 switch (This->resource.format->id)
581 case WINED3DFMT_B8G8R8_UNORM:
582 usage = DIB_RGB_COLORS;
583 b_info->bmiHeader.biCompression = BI_RGB;
586 case WINED3DFMT_B5G5R5X1_UNORM:
587 case WINED3DFMT_B5G5R5A1_UNORM:
588 case WINED3DFMT_B4G4R4A4_UNORM:
589 case WINED3DFMT_B4G4R4X4_UNORM:
590 case WINED3DFMT_B2G3R3_UNORM:
591 case WINED3DFMT_B2G3R3A8_UNORM:
592 case WINED3DFMT_R10G10B10A2_UNORM:
593 case WINED3DFMT_R8G8B8A8_UNORM:
594 case WINED3DFMT_R8G8B8X8_UNORM:
595 case WINED3DFMT_B10G10R10A2_UNORM:
596 case WINED3DFMT_B5G6R5_UNORM:
597 case WINED3DFMT_R16G16B16A16_UNORM:
599 b_info->bmiHeader.biCompression = BI_BITFIELDS;
600 masks[0] = format->red_mask;
601 masks[1] = format->green_mask;
602 masks[2] = format->blue_mask;
606 /* Don't know palette */
607 b_info->bmiHeader.biCompression = BI_RGB;
612 if (!(ddc = GetDC(0)))
614 HeapFree(GetProcessHeap(), 0, b_info);
615 return HRESULT_FROM_WIN32(GetLastError());
618 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);
619 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
622 if (!This->dib.DIBsection) {
623 ERR("CreateDIBSection failed!\n");
624 HeapFree(GetProcessHeap(), 0, b_info);
625 return HRESULT_FROM_WIN32(GetLastError());
628 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
629 /* copy the existing surface to the dib section */
630 if (This->resource.allocatedMemory)
632 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory,
633 This->resource.height * IWineD3DSurface_GetPitch(iface));
637 /* This is to make LockRect read the gl Texture although memory is allocated */
638 This->flags &= ~SFLAG_INSYSMEM;
640 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
642 HeapFree(GetProcessHeap(), 0, b_info);
644 /* Now allocate a HDC */
645 This->hDC = CreateCompatibleDC(0);
646 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
647 TRACE("using wined3d palette %p\n", This->palette);
648 SelectPalette(This->hDC,
649 This->palette ? This->palette->hpal : 0,
652 This->flags |= SFLAG_DIBSECTION;
654 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
655 This->resource.heapMemory = NULL;
660 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
661 unsigned int w, unsigned int h)
665 unsigned short *dst_s;
667 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
668 for(y = 0; y < h; y++) {
669 src_f = (const float *)(src + y * pitch_in);
670 dst_s = (unsigned short *) (dst + y * pitch_out);
671 for(x = 0; x < w; x++) {
672 dst_s[x] = float_32_to_16(src_f + x);
677 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
678 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
680 static const unsigned char convert_5to8[] =
682 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
683 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
684 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
685 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
687 static const unsigned char convert_6to8[] =
689 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
690 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
691 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
692 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
693 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
694 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
695 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
696 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
700 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
702 for (y = 0; y < h; ++y)
704 const WORD *src_line = (const WORD *)(src + y * pitch_in);
705 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
706 for (x = 0; x < w; ++x)
708 WORD pixel = src_line[x];
709 dst_line[x] = 0xff000000
710 | convert_5to8[(pixel & 0xf800) >> 11] << 16
711 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
712 | convert_5to8[(pixel & 0x001f)];
717 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
718 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
722 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
724 for (y = 0; y < h; ++y)
726 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
727 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
729 for (x = 0; x < w; ++x)
731 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
736 static inline BYTE cliptobyte(int x)
738 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
741 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
742 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
745 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
747 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
749 for (y = 0; y < h; ++y)
751 const BYTE *src_line = src + y * pitch_in;
752 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
753 for (x = 0; x < w; ++x)
755 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
756 * C = Y - 16; D = U - 128; E = V - 128;
757 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
758 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
759 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
760 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
761 * U and V are shared between the pixels.
763 if (!(x & 1)) /* for every even pixel, read new U and V */
765 d = (int) src_line[1] - 128;
766 e = (int) src_line[3] - 128;
768 g2 = - 100 * d - 208 * e + 128;
771 c2 = 298 * ((int) src_line[0] - 16);
772 dst_line[x] = 0xff000000
773 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
774 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
775 | cliptobyte((c2 + b2) >> 8); /* blue */
776 /* Scale RGB values to 0..255 range,
777 * then clip them if still not in range (may be negative),
778 * then shift them within DWORD if necessary.
785 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
786 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
789 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
791 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
793 for (y = 0; y < h; ++y)
795 const BYTE *src_line = src + y * pitch_in;
796 WORD *dst_line = (WORD *)(dst + y * pitch_out);
797 for (x = 0; x < w; ++x)
799 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
800 * C = Y - 16; D = U - 128; E = V - 128;
801 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
802 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
803 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
804 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
805 * U and V are shared between the pixels.
807 if (!(x & 1)) /* for every even pixel, read new U and V */
809 d = (int) src_line[1] - 128;
810 e = (int) src_line[3] - 128;
812 g2 = - 100 * d - 208 * e + 128;
815 c2 = 298 * ((int) src_line[0] - 16);
816 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
817 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
818 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
819 /* Scale RGB values to 0..255 range,
820 * then clip them if still not in range (may be negative),
821 * then shift them within DWORD if necessary.
828 struct d3dfmt_convertor_desc
830 enum wined3d_format_id from, to;
831 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
834 static const struct d3dfmt_convertor_desc convertors[] =
836 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
837 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
838 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
839 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
840 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
843 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
846 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
847 if(convertors[i].from == from && convertors[i].to == to) {
848 return &convertors[i];
854 /*****************************************************************************
855 * surface_convert_format
857 * Creates a duplicate of a surface in a different format. Is used by Blt to
858 * blit between surfaces with different formats
861 * source: Source surface
862 * fmt: Requested destination format
864 *****************************************************************************/
865 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
867 IWineD3DSurface *ret = NULL;
868 const struct d3dfmt_convertor_desc *conv;
869 WINED3DLOCKED_RECT lock_src, lock_dst;
872 conv = find_convertor(source->resource.format->id, to_fmt);
875 FIXME("Cannot find a conversion function from format %s to %s.\n",
876 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
880 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
881 source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
882 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
883 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
884 NULL /* parent */, &wined3d_null_parent_ops, &ret);
886 ERR("Failed to create a destination surface for conversion\n");
890 memset(&lock_src, 0, sizeof(lock_src));
891 memset(&lock_dst, 0, sizeof(lock_dst));
893 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
896 ERR("Failed to lock the source surface.\n");
897 IWineD3DSurface_Release(ret);
900 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
903 ERR("Failed to lock the dest surface\n");
904 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
905 IWineD3DSurface_Release(ret);
909 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
910 source->resource.width, source->resource.height);
912 IWineD3DSurface_Unmap(ret);
913 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
915 return (IWineD3DSurfaceImpl *) ret;
918 /*****************************************************************************
921 * Helper function that fills a memory area with a specific color
924 * buf: memory address to start filling at
925 * width, height: Dimensions of the area to fill
926 * bpp: Bit depth of the surface
927 * lPitch: pitch of the surface
928 * color: Color to fill with
930 *****************************************************************************/
932 _Blt_ColorFill(BYTE *buf,
933 int width, int height,
934 int bpp, LONG lPitch,
942 #define COLORFILL_ROW(type) \
944 type *d = (type *) buf; \
945 for (x = 0; x < width; x++) \
946 d[x] = (type) color; \
951 case 1: COLORFILL_ROW(BYTE)
952 case 2: COLORFILL_ROW(WORD)
956 for (x = 0; x < width; x++,d+=3)
958 d[0] = (color ) & 0xFF;
959 d[1] = (color>> 8) & 0xFF;
960 d[2] = (color>>16) & 0xFF;
964 case 4: COLORFILL_ROW(DWORD)
966 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
967 return WINED3DERR_NOTAVAILABLE;
972 /* Now copy first row */
974 for (y = 1; y < height; y++)
977 memcpy(buf, first, width * bpp);
982 /*****************************************************************************
983 * IWineD3DSurface::Blt, SW emulation version
985 * Performs a blit to a surface, with or without a source surface.
986 * This is the main functionality of DirectDraw
989 * DestRect: Destination rectangle to write to
990 * src_surface: Source surface, can be NULL
991 * SrcRect: Source rectangle
992 *****************************************************************************/
993 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
994 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
996 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
997 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
999 HRESULT ret = WINED3D_OK;
1000 WINED3DLOCKED_RECT dlock, slock;
1001 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
1002 const struct wined3d_format *sEntry, *dEntry;
1007 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1008 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
1009 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
1011 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
1013 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1014 return WINEDDERR_SURFACEBUSY;
1017 /* First check for the validity of source / destination rectangles.
1018 * This was verified using a test application + by MSDN. */
1024 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
1025 || SrcRect->left > src->resource.width || SrcRect->left < 0
1026 || SrcRect->top > src->resource.height || SrcRect->top < 0
1027 || SrcRect->right > src->resource.width || SrcRect->right < 0
1028 || SrcRect->bottom > src->resource.height || SrcRect->bottom < 0)
1030 WARN("Application gave us bad source rectangle for Blt.\n");
1031 return WINEDDERR_INVALIDRECT;
1034 if (!SrcRect->right || !SrcRect->bottom
1035 || SrcRect->left == (int)src->resource.width
1036 || SrcRect->top == (int)src->resource.height)
1038 TRACE("Nothing to be done.\n");
1049 xsrc.right = src->resource.width;
1050 xsrc.bottom = src->resource.height;
1054 memset(&xsrc, 0, sizeof(xsrc));
1059 /* For the Destination rect, it can be out of bounds on the condition
1060 * that a clipper is set for the given surface. */
1061 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1062 || DestRect->left > This->resource.width || DestRect->left < 0
1063 || DestRect->top > This->resource.height || DestRect->top < 0
1064 || DestRect->right > This->resource.width || DestRect->right < 0
1065 || DestRect->bottom > This->resource.height || DestRect->bottom < 0))
1067 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1068 return WINEDDERR_INVALIDRECT;
1071 if (DestRect->right <= 0 || DestRect->bottom <= 0
1072 || DestRect->left >= (int)This->resource.width
1073 || DestRect->top >= (int)This->resource.height)
1075 TRACE("Nothing to be done.\n");
1085 full_rect.right = This->resource.width;
1086 full_rect.bottom = This->resource.height;
1087 IntersectRect(&xdst, &full_rect, DestRect);
1091 BOOL clip_horiz, clip_vert;
1094 clip_horiz = xdst.left < 0 || xdst.right > (int)This->resource.width;
1095 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->resource.height;
1097 if (clip_vert || clip_horiz)
1099 /* Now check if this is a special case or not... */
1100 if ((flags & WINEDDBLT_DDFX)
1101 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1102 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1104 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1112 xsrc.left -= xdst.left;
1115 if (xdst.right > This->resource.width)
1117 xsrc.right -= (xdst.right - (int)This->resource.width);
1118 xdst.right = (int)This->resource.width;
1126 xsrc.top -= xdst.top;
1129 if (xdst.bottom > This->resource.height)
1131 xsrc.bottom -= (xdst.bottom - (int)This->resource.height);
1132 xdst.bottom = (int)This->resource.height;
1136 /* And check if after clipping something is still to be done... */
1137 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1138 || (xdst.left >= (int)This->resource.width)
1139 || (xdst.top >= (int)This->resource.height)
1140 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1141 || (xsrc.left >= (int)src->resource.width)
1142 || (xsrc.top >= (int)src->resource.height))
1144 TRACE("Nothing to be done after clipping.\n");
1154 xdst.right = This->resource.width;
1155 xdst.bottom = This->resource.height;
1160 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1162 sEntry = This->resource.format;
1167 dEntry = This->resource.format;
1170 if (This->resource.format->id != src->resource.format->id)
1172 src = surface_convert_format(src, dEntry->id);
1175 /* The conv function writes a FIXME */
1176 WARN("Cannot convert source surface format to dest format\n");
1180 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1181 sEntry = src->resource.format;
1188 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1190 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1193 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1195 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1197 if (!DestRect || src == This)
1199 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1204 bpp = This->resource.format->byte_count;
1205 srcheight = xsrc.bottom - xsrc.top;
1206 srcwidth = xsrc.right - xsrc.left;
1207 dstheight = xdst.bottom - xdst.top;
1208 dstwidth = xdst.right - xdst.left;
1209 width = (xdst.right - xdst.left) * bpp;
1211 if (DestRect && src != This)
1214 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1216 if (flags & WINEDDBLT_WAIT)
1218 flags &= ~WINEDDBLT_WAIT;
1220 if (flags & WINEDDBLT_ASYNC)
1222 static BOOL displayed = FALSE;
1224 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1226 flags &= ~WINEDDBLT_ASYNC;
1228 if (flags & WINEDDBLT_DONOTWAIT)
1230 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1231 static BOOL displayed = FALSE;
1233 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1235 flags &= ~WINEDDBLT_DONOTWAIT;
1238 /* First, all the 'source-less' blits */
1239 if (flags & WINEDDBLT_COLORFILL)
1241 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1242 dlock.Pitch, DDBltFx->u5.dwFillColor);
1243 flags &= ~WINEDDBLT_COLORFILL;
1246 if (flags & WINEDDBLT_DEPTHFILL)
1248 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1250 if (flags & WINEDDBLT_ROP)
1252 /* Catch some degenerate cases here */
1253 switch(DDBltFx->dwROP)
1256 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1258 case 0xAA0029: /* No-op */
1261 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1263 case SRCCOPY: /* well, we do that below ? */
1266 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1269 flags &= ~WINEDDBLT_ROP;
1271 if (flags & WINEDDBLT_DDROPS)
1273 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1275 /* Now the 'with source' blits */
1279 int sx, xinc, sy, yinc;
1281 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1284 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1285 && (srcwidth != dstwidth || srcheight != dstheight))
1287 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1288 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1291 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1292 xinc = (srcwidth << 16) / dstwidth;
1293 yinc = (srcheight << 16) / dstheight;
1297 /* No effects, we can cheat here */
1298 if (dstwidth == srcwidth)
1300 if (dstheight == srcheight)
1302 /* No stretching in either direction. This needs to be as
1303 * fast as possible */
1306 /* check for overlapping surfaces */
1307 if (src != This || xdst.top < xsrc.top ||
1308 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1310 /* no overlap, or dst above src, so copy from top downwards */
1311 for (y = 0; y < dstheight; y++)
1313 memcpy(dbuf, sbuf, width);
1314 sbuf += slock.Pitch;
1315 dbuf += dlock.Pitch;
1318 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1320 sbuf += (slock.Pitch*dstheight);
1321 dbuf += (dlock.Pitch*dstheight);
1322 for (y = 0; y < dstheight; y++)
1324 sbuf -= slock.Pitch;
1325 dbuf -= dlock.Pitch;
1326 memcpy(dbuf, sbuf, width);
1329 else /* src and dst overlapping on the same line, use memmove */
1331 for (y = 0; y < dstheight; y++)
1333 memmove(dbuf, sbuf, width);
1334 sbuf += slock.Pitch;
1335 dbuf += dlock.Pitch;
1339 /* Stretching in Y direction only */
1340 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1341 sbuf = sbase + (sy >> 16) * slock.Pitch;
1342 memcpy(dbuf, sbuf, width);
1343 dbuf += dlock.Pitch;
1349 /* Stretching in X direction */
1351 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1353 sbuf = sbase + (sy >> 16) * slock.Pitch;
1355 if ((sy >> 16) == (last_sy >> 16))
1357 /* this sourcerow is the same as last sourcerow -
1358 * copy already stretched row
1360 memcpy(dbuf, dbuf - dlock.Pitch, width);
1364 #define STRETCH_ROW(type) { \
1365 const type *s = (const type *)sbuf; \
1366 type *d = (type *)dbuf; \
1367 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1368 d[x] = s[sx >> 16]; \
1373 case 1: STRETCH_ROW(BYTE)
1374 case 2: STRETCH_ROW(WORD)
1375 case 4: STRETCH_ROW(DWORD)
1380 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1384 s = sbuf+3*(sx>>16);
1385 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1386 d[0] = (pixel )&0xff;
1387 d[1] = (pixel>> 8)&0xff;
1388 d[2] = (pixel>>16)&0xff;
1394 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1395 ret = WINED3DERR_NOTAVAILABLE;
1400 dbuf += dlock.Pitch;
1407 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1408 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1409 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1410 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1412 /* The color keying flags are checked for correctness in ddraw */
1413 if (flags & WINEDDBLT_KEYSRC)
1415 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1416 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1418 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1420 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1421 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1424 if (flags & WINEDDBLT_KEYDEST)
1426 /* Destination color keys are taken from the source surface ! */
1427 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1428 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1430 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1432 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1433 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1442 keymask = sEntry->red_mask
1443 | sEntry->green_mask
1444 | sEntry->blue_mask;
1446 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1449 if (flags & WINEDDBLT_DDFX)
1451 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1454 dTopRight = dbuf+((dstwidth-1)*bpp);
1455 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1456 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1458 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1460 /* I don't think we need to do anything about this flag */
1461 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1463 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1466 dTopRight = dTopLeft;
1469 dBottomRight = dBottomLeft;
1471 dstxinc = dstxinc *-1;
1473 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1476 dTopLeft = dBottomLeft;
1479 dTopRight = dBottomRight;
1481 dstyinc = dstyinc *-1;
1483 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1485 /* I don't think we need to do anything about this flag */
1486 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1488 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1491 dBottomRight = dTopLeft;
1494 dBottomLeft = dTopRight;
1496 dstxinc = dstxinc * -1;
1497 dstyinc = dstyinc * -1;
1499 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1502 dTopLeft = dBottomLeft;
1503 dBottomLeft = dBottomRight;
1504 dBottomRight = dTopRight;
1509 dstxinc = dstxinc * -1;
1511 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1514 dTopLeft = dTopRight;
1515 dTopRight = dBottomRight;
1516 dBottomRight = dBottomLeft;
1521 dstyinc = dstyinc * -1;
1523 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1525 /* I don't think we need to do anything about this flag */
1526 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1529 flags &= ~(WINEDDBLT_DDFX);
1532 #define COPY_COLORKEY_FX(type) { \
1534 type *d = (type *)dbuf, *dx, tmp; \
1535 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1536 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1538 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1539 tmp = s[sx >> 16]; \
1540 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1541 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1544 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1546 d = (type*)(((LPBYTE)d)+dstyinc); \
1551 case 1: COPY_COLORKEY_FX(BYTE)
1552 case 2: COPY_COLORKEY_FX(WORD)
1553 case 4: COPY_COLORKEY_FX(DWORD)
1557 BYTE *d = dbuf, *dx;
1558 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1560 sbuf = sbase + (sy >> 16) * slock.Pitch;
1562 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1564 DWORD pixel, dpixel = 0;
1565 s = sbuf+3*(sx>>16);
1566 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1567 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1568 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1569 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1571 dx[0] = (pixel )&0xff;
1572 dx[1] = (pixel>> 8)&0xff;
1573 dx[2] = (pixel>>16)&0xff;
1582 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1583 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1584 ret = WINED3DERR_NOTAVAILABLE;
1586 #undef COPY_COLORKEY_FX
1592 if (flags && FIXME_ON(d3d_surface))
1594 FIXME("\tUnsupported flags: %#x.\n", flags);
1598 IWineD3DSurface_Unmap(iface);
1599 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1600 /* Release the converted surface if any */
1601 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1605 /*****************************************************************************
1606 * IWineD3DSurface::BltFast, SW emulation version
1608 * This is the software implementation of BltFast, as used by GDI surfaces
1609 * and as a fallback for OpenGL surfaces. This code is taken from the old
1610 * DirectDraw code, and was originally written by TransGaming.
1615 * src_surface: Source surface to copy from
1616 * rsrc: Source rectangle
1620 * WINED3D_OK on success
1622 *****************************************************************************/
1623 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1624 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1626 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1627 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1629 int bpp, w, h, x, y;
1630 WINED3DLOCKED_RECT dlock,slock;
1631 HRESULT ret = WINED3D_OK;
1633 RECT lock_src, lock_dst, lock_union;
1636 const struct wined3d_format *sEntry, *dEntry;
1638 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1639 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1641 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1643 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1644 return WINEDDERR_SURFACEBUSY;
1649 WARN("rsrc is NULL!\n");
1652 rsrc2.right = src->resource.width;
1653 rsrc2.bottom = src->resource.height;
1657 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1658 if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
1659 || (rsrc->top > src->resource.height) || (rsrc->top < 0)
1660 || (rsrc->left > src->resource.width) || (rsrc->left < 0)
1661 || (rsrc->right > src->resource.width) || (rsrc->right < 0)
1662 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1664 WARN("Application gave us bad source rectangle for BltFast.\n");
1665 return WINEDDERR_INVALIDRECT;
1668 h = rsrc->bottom - rsrc->top;
1669 if (h > This->resource.height-dsty)
1670 h = This->resource.height-dsty;
1671 if (h > src->resource.height-rsrc->top)
1672 h = src->resource.height-rsrc->top;
1674 return WINEDDERR_INVALIDRECT;
1676 w = rsrc->right - rsrc->left;
1677 if (w > This->resource.width-dstx)
1678 w = This->resource.width-dstx;
1679 if (w > src->resource.width-rsrc->left)
1680 w = src->resource.width-rsrc->left;
1682 return WINEDDERR_INVALIDRECT;
1684 /* Now compute the locking rectangle... */
1685 lock_src.left = rsrc->left;
1686 lock_src.top = rsrc->top;
1687 lock_src.right = lock_src.left + w;
1688 lock_src.bottom = lock_src.top + h;
1690 lock_dst.left = dstx;
1691 lock_dst.top = dsty;
1692 lock_dst.right = dstx + w;
1693 lock_dst.bottom = dsty + h;
1695 bpp = This->resource.format->byte_count;
1697 /* We need to lock the surfaces, or we won't get refreshes when done. */
1702 UnionRect(&lock_union, &lock_src, &lock_dst);
1704 /* Lock the union of the two rectangles */
1705 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1706 if (FAILED(ret)) goto error;
1708 pitch = dlock.Pitch;
1709 slock.Pitch = dlock.Pitch;
1711 /* Since slock was originally copied from this surface's description, we can just reuse it */
1712 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1713 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1714 sEntry = src->resource.format;
1719 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1720 if (FAILED(ret)) goto error;
1721 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1722 if (FAILED(ret)) goto error;
1726 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1728 sEntry = src->resource.format;
1729 dEntry = This->resource.format;
1732 /* Handle compressed surfaces first... */
1733 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1735 UINT row_block_count;
1737 TRACE("compressed -> compressed copy\n");
1739 FIXME("trans arg not supported when a compressed surface is involved\n");
1741 FIXME("offset for destination surface is not supported\n");
1742 if (src->resource.format->id != This->resource.format->id)
1744 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1745 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1749 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1750 for (y = 0; y < h; y += dEntry->block_height)
1752 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1753 dbuf += dlock.Pitch;
1754 sbuf += slock.Pitch;
1759 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1761 /* TODO: Use the libtxc_dxtn.so shared library to do
1762 * software decompression
1764 ERR("Software decompression not supported.\n");
1768 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1770 DWORD keylow, keyhigh;
1771 DWORD mask = src->resource.format->red_mask
1772 | src->resource.format->green_mask
1773 | src->resource.format->blue_mask;
1775 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1779 TRACE("Color keyed copy\n");
1780 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1782 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1783 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1787 /* I'm not sure if this is correct */
1788 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1789 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1790 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1793 #define COPYBOX_COLORKEY(type) { \
1794 const type *s = (const type *)sbuf; \
1795 type *d = (type *)dbuf; \
1797 for (y = 0; y < h; y++) { \
1798 for (x = 0; x < w; x++) { \
1800 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1802 s = (const type *)((const BYTE *)s + slock.Pitch); \
1803 d = (type *)((BYTE *)d + dlock.Pitch); \
1809 case 1: COPYBOX_COLORKEY(BYTE)
1810 case 2: COPYBOX_COLORKEY(WORD)
1811 case 4: COPYBOX_COLORKEY(DWORD)
1819 for (y = 0; y < h; y++)
1821 for (x = 0; x < w * 3; x += 3)
1823 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1824 if (tmp < keylow || tmp > keyhigh)
1826 d[x + 0] = s[x + 0];
1827 d[x + 1] = s[x + 1];
1828 d[x + 2] = s[x + 2];
1837 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1838 ret = WINED3DERR_NOTAVAILABLE;
1841 #undef COPYBOX_COLORKEY
1842 TRACE("Copy Done\n");
1846 int width = w * bpp;
1847 INT sbufpitch, dbufpitch;
1849 TRACE("NO color key copy\n");
1850 /* Handle overlapping surfaces */
1853 sbuf += (h - 1) * slock.Pitch;
1854 dbuf += (h - 1) * dlock.Pitch;
1855 sbufpitch = -slock.Pitch;
1856 dbufpitch = -dlock.Pitch;
1860 sbufpitch = slock.Pitch;
1861 dbufpitch = dlock.Pitch;
1863 for (y = 0; y < h; y++)
1865 /* This is pretty easy, a line for line memcpy */
1866 memmove(dbuf, sbuf, width);
1870 TRACE("Copy done\n");
1876 IWineD3DSurface_Unmap(iface);
1880 IWineD3DSurface_Unmap(iface);
1881 IWineD3DSurface_Unmap(src_surface);
1887 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1888 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1890 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1892 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1893 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1895 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1899 pLockedRect->pBits = This->resource.allocatedMemory;
1900 This->lockedRect.left = 0;
1901 This->lockedRect.top = 0;
1902 This->lockedRect.right = This->resource.width;
1903 This->lockedRect.bottom = This->resource.height;
1905 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1906 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1907 This->lockedRect.right, This->lockedRect.bottom);
1911 const struct wined3d_format *format = This->resource.format;
1913 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1914 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1916 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1918 /* Compressed textures are block based, so calculate the offset of
1919 * the block that contains the top-left pixel of the locked rectangle. */
1920 pLockedRect->pBits = This->resource.allocatedMemory
1921 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1922 + ((pRect->left / format->block_width) * format->block_byte_count);
1926 pLockedRect->pBits = This->resource.allocatedMemory +
1927 (pLockedRect->Pitch * pRect->top) +
1928 (pRect->left * format->byte_count);
1930 This->lockedRect.left = pRect->left;
1931 This->lockedRect.top = pRect->top;
1932 This->lockedRect.right = pRect->right;
1933 This->lockedRect.bottom = pRect->bottom;
1936 /* No dirtifying is needed for this surface implementation */
1937 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);