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 struct d3dfmt_convertor_desc
787 enum wined3d_format_id from, to;
788 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
791 static const struct d3dfmt_convertor_desc convertors[] =
793 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
794 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
795 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
796 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
799 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
802 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
803 if(convertors[i].from == from && convertors[i].to == to) {
804 return &convertors[i];
810 /*****************************************************************************
811 * surface_convert_format
813 * Creates a duplicate of a surface in a different format. Is used by Blt to
814 * blit between surfaces with different formats
817 * source: Source surface
818 * fmt: Requested destination format
820 *****************************************************************************/
821 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
823 IWineD3DSurface *ret = NULL;
824 const struct d3dfmt_convertor_desc *conv;
825 WINED3DLOCKED_RECT lock_src, lock_dst;
828 conv = find_convertor(source->resource.format->id, to_fmt);
831 FIXME("Cannot find a conversion function from format %s to %s.\n",
832 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
836 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
837 source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
838 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
839 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
840 NULL /* parent */, &wined3d_null_parent_ops, &ret);
842 ERR("Failed to create a destination surface for conversion\n");
846 memset(&lock_src, 0, sizeof(lock_src));
847 memset(&lock_dst, 0, sizeof(lock_dst));
849 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
852 ERR("Failed to lock the source surface.\n");
853 IWineD3DSurface_Release(ret);
856 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
859 ERR("Failed to lock the dest surface\n");
860 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
861 IWineD3DSurface_Release(ret);
865 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
866 source->resource.width, source->resource.height);
868 IWineD3DSurface_Unmap(ret);
869 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
871 return (IWineD3DSurfaceImpl *) ret;
874 /*****************************************************************************
877 * Helper function that fills a memory area with a specific color
880 * buf: memory address to start filling at
881 * width, height: Dimensions of the area to fill
882 * bpp: Bit depth of the surface
883 * lPitch: pitch of the surface
884 * color: Color to fill with
886 *****************************************************************************/
888 _Blt_ColorFill(BYTE *buf,
889 int width, int height,
890 int bpp, LONG lPitch,
898 #define COLORFILL_ROW(type) \
900 type *d = (type *) buf; \
901 for (x = 0; x < width; x++) \
902 d[x] = (type) color; \
907 case 1: COLORFILL_ROW(BYTE)
908 case 2: COLORFILL_ROW(WORD)
912 for (x = 0; x < width; x++,d+=3)
914 d[0] = (color ) & 0xFF;
915 d[1] = (color>> 8) & 0xFF;
916 d[2] = (color>>16) & 0xFF;
920 case 4: COLORFILL_ROW(DWORD)
922 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
923 return WINED3DERR_NOTAVAILABLE;
928 /* Now copy first row */
930 for (y = 1; y < height; y++)
933 memcpy(buf, first, width * bpp);
938 /*****************************************************************************
939 * IWineD3DSurface::Blt, SW emulation version
941 * Performs a blit to a surface, with or without a source surface.
942 * This is the main functionality of DirectDraw
945 * DestRect: Destination rectangle to write to
946 * src_surface: Source surface, can be NULL
947 * SrcRect: Source rectangle
948 *****************************************************************************/
949 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
950 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
952 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
953 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
955 HRESULT ret = WINED3D_OK;
956 WINED3DLOCKED_RECT dlock, slock;
957 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
958 const struct wined3d_format *sEntry, *dEntry;
963 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
964 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
965 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
967 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
969 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
970 return WINEDDERR_SURFACEBUSY;
973 /* First check for the validity of source / destination rectangles.
974 * This was verified using a test application + by MSDN. */
980 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
981 || SrcRect->left > src->resource.width || SrcRect->left < 0
982 || SrcRect->top > src->resource.height || SrcRect->top < 0
983 || SrcRect->right > src->resource.width || SrcRect->right < 0
984 || SrcRect->bottom > src->resource.height || SrcRect->bottom < 0)
986 WARN("Application gave us bad source rectangle for Blt.\n");
987 return WINEDDERR_INVALIDRECT;
990 if (!SrcRect->right || !SrcRect->bottom
991 || SrcRect->left == (int)src->resource.width
992 || SrcRect->top == (int)src->resource.height)
994 TRACE("Nothing to be done.\n");
1005 xsrc.right = src->resource.width;
1006 xsrc.bottom = src->resource.height;
1010 memset(&xsrc, 0, sizeof(xsrc));
1015 /* For the Destination rect, it can be out of bounds on the condition
1016 * that a clipper is set for the given surface. */
1017 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1018 || DestRect->left > This->resource.width || DestRect->left < 0
1019 || DestRect->top > This->resource.height || DestRect->top < 0
1020 || DestRect->right > This->resource.width || DestRect->right < 0
1021 || DestRect->bottom > This->resource.height || DestRect->bottom < 0))
1023 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1024 return WINEDDERR_INVALIDRECT;
1027 if (DestRect->right <= 0 || DestRect->bottom <= 0
1028 || DestRect->left >= (int)This->resource.width
1029 || DestRect->top >= (int)This->resource.height)
1031 TRACE("Nothing to be done.\n");
1041 full_rect.right = This->resource.width;
1042 full_rect.bottom = This->resource.height;
1043 IntersectRect(&xdst, &full_rect, DestRect);
1047 BOOL clip_horiz, clip_vert;
1050 clip_horiz = xdst.left < 0 || xdst.right > (int)This->resource.width;
1051 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->resource.height;
1053 if (clip_vert || clip_horiz)
1055 /* Now check if this is a special case or not... */
1056 if ((flags & WINEDDBLT_DDFX)
1057 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1058 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1060 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1068 xsrc.left -= xdst.left;
1071 if (xdst.right > This->resource.width)
1073 xsrc.right -= (xdst.right - (int)This->resource.width);
1074 xdst.right = (int)This->resource.width;
1082 xsrc.top -= xdst.top;
1085 if (xdst.bottom > This->resource.height)
1087 xsrc.bottom -= (xdst.bottom - (int)This->resource.height);
1088 xdst.bottom = (int)This->resource.height;
1092 /* And check if after clipping something is still to be done... */
1093 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1094 || (xdst.left >= (int)This->resource.width)
1095 || (xdst.top >= (int)This->resource.height)
1096 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1097 || (xsrc.left >= (int)src->resource.width)
1098 || (xsrc.top >= (int)src->resource.height))
1100 TRACE("Nothing to be done after clipping.\n");
1110 xdst.right = This->resource.width;
1111 xdst.bottom = This->resource.height;
1116 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1118 sEntry = This->resource.format;
1123 dEntry = This->resource.format;
1126 if (This->resource.format->id != src->resource.format->id)
1128 src = surface_convert_format(src, dEntry->id);
1131 /* The conv function writes a FIXME */
1132 WARN("Cannot convert source surface format to dest format\n");
1136 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1137 sEntry = src->resource.format;
1144 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1146 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1149 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1151 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1153 if (!DestRect || src == This)
1155 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1160 bpp = This->resource.format->byte_count;
1161 srcheight = xsrc.bottom - xsrc.top;
1162 srcwidth = xsrc.right - xsrc.left;
1163 dstheight = xdst.bottom - xdst.top;
1164 dstwidth = xdst.right - xdst.left;
1165 width = (xdst.right - xdst.left) * bpp;
1167 if (DestRect && src != This)
1170 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1172 if (flags & WINEDDBLT_WAIT)
1174 flags &= ~WINEDDBLT_WAIT;
1176 if (flags & WINEDDBLT_ASYNC)
1178 static BOOL displayed = FALSE;
1180 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1182 flags &= ~WINEDDBLT_ASYNC;
1184 if (flags & WINEDDBLT_DONOTWAIT)
1186 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1187 static BOOL displayed = FALSE;
1189 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1191 flags &= ~WINEDDBLT_DONOTWAIT;
1194 /* First, all the 'source-less' blits */
1195 if (flags & WINEDDBLT_COLORFILL)
1197 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1198 dlock.Pitch, DDBltFx->u5.dwFillColor);
1199 flags &= ~WINEDDBLT_COLORFILL;
1202 if (flags & WINEDDBLT_DEPTHFILL)
1204 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1206 if (flags & WINEDDBLT_ROP)
1208 /* Catch some degenerate cases here */
1209 switch(DDBltFx->dwROP)
1212 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1214 case 0xAA0029: /* No-op */
1217 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1219 case SRCCOPY: /* well, we do that below ? */
1222 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1225 flags &= ~WINEDDBLT_ROP;
1227 if (flags & WINEDDBLT_DDROPS)
1229 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1231 /* Now the 'with source' blits */
1235 int sx, xinc, sy, yinc;
1237 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1240 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1241 && (srcwidth != dstwidth || srcheight != dstheight))
1243 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1244 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1247 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1248 xinc = (srcwidth << 16) / dstwidth;
1249 yinc = (srcheight << 16) / dstheight;
1253 /* No effects, we can cheat here */
1254 if (dstwidth == srcwidth)
1256 if (dstheight == srcheight)
1258 /* No stretching in either direction. This needs to be as
1259 * fast as possible */
1262 /* check for overlapping surfaces */
1263 if (src != This || xdst.top < xsrc.top ||
1264 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1266 /* no overlap, or dst above src, so copy from top downwards */
1267 for (y = 0; y < dstheight; y++)
1269 memcpy(dbuf, sbuf, width);
1270 sbuf += slock.Pitch;
1271 dbuf += dlock.Pitch;
1274 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1276 sbuf += (slock.Pitch*dstheight);
1277 dbuf += (dlock.Pitch*dstheight);
1278 for (y = 0; y < dstheight; y++)
1280 sbuf -= slock.Pitch;
1281 dbuf -= dlock.Pitch;
1282 memcpy(dbuf, sbuf, width);
1285 else /* src and dst overlapping on the same line, use memmove */
1287 for (y = 0; y < dstheight; y++)
1289 memmove(dbuf, sbuf, width);
1290 sbuf += slock.Pitch;
1291 dbuf += dlock.Pitch;
1295 /* Stretching in Y direction only */
1296 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1297 sbuf = sbase + (sy >> 16) * slock.Pitch;
1298 memcpy(dbuf, sbuf, width);
1299 dbuf += dlock.Pitch;
1305 /* Stretching in X direction */
1307 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1309 sbuf = sbase + (sy >> 16) * slock.Pitch;
1311 if ((sy >> 16) == (last_sy >> 16))
1313 /* this sourcerow is the same as last sourcerow -
1314 * copy already stretched row
1316 memcpy(dbuf, dbuf - dlock.Pitch, width);
1320 #define STRETCH_ROW(type) { \
1321 const type *s = (const type *)sbuf; \
1322 type *d = (type *)dbuf; \
1323 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1324 d[x] = s[sx >> 16]; \
1329 case 1: STRETCH_ROW(BYTE)
1330 case 2: STRETCH_ROW(WORD)
1331 case 4: STRETCH_ROW(DWORD)
1336 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1340 s = sbuf+3*(sx>>16);
1341 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1342 d[0] = (pixel )&0xff;
1343 d[1] = (pixel>> 8)&0xff;
1344 d[2] = (pixel>>16)&0xff;
1350 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1351 ret = WINED3DERR_NOTAVAILABLE;
1356 dbuf += dlock.Pitch;
1363 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1364 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1365 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1366 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1368 /* The color keying flags are checked for correctness in ddraw */
1369 if (flags & WINEDDBLT_KEYSRC)
1371 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1372 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1374 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1376 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1377 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1380 if (flags & WINEDDBLT_KEYDEST)
1382 /* Destination color keys are taken from the source surface ! */
1383 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1384 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1386 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1388 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1389 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1398 keymask = sEntry->red_mask
1399 | sEntry->green_mask
1400 | sEntry->blue_mask;
1402 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1405 if (flags & WINEDDBLT_DDFX)
1407 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1410 dTopRight = dbuf+((dstwidth-1)*bpp);
1411 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1412 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1414 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1416 /* I don't think we need to do anything about this flag */
1417 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1419 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1422 dTopRight = dTopLeft;
1425 dBottomRight = dBottomLeft;
1427 dstxinc = dstxinc *-1;
1429 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1432 dTopLeft = dBottomLeft;
1435 dTopRight = dBottomRight;
1437 dstyinc = dstyinc *-1;
1439 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1441 /* I don't think we need to do anything about this flag */
1442 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1444 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1447 dBottomRight = dTopLeft;
1450 dBottomLeft = dTopRight;
1452 dstxinc = dstxinc * -1;
1453 dstyinc = dstyinc * -1;
1455 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1458 dTopLeft = dBottomLeft;
1459 dBottomLeft = dBottomRight;
1460 dBottomRight = dTopRight;
1465 dstxinc = dstxinc * -1;
1467 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1470 dTopLeft = dTopRight;
1471 dTopRight = dBottomRight;
1472 dBottomRight = dBottomLeft;
1477 dstyinc = dstyinc * -1;
1479 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1481 /* I don't think we need to do anything about this flag */
1482 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1485 flags &= ~(WINEDDBLT_DDFX);
1488 #define COPY_COLORKEY_FX(type) { \
1490 type *d = (type *)dbuf, *dx, tmp; \
1491 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1492 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1494 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1495 tmp = s[sx >> 16]; \
1496 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1497 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1500 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1502 d = (type*)(((LPBYTE)d)+dstyinc); \
1507 case 1: COPY_COLORKEY_FX(BYTE)
1508 case 2: COPY_COLORKEY_FX(WORD)
1509 case 4: COPY_COLORKEY_FX(DWORD)
1513 BYTE *d = dbuf, *dx;
1514 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1516 sbuf = sbase + (sy >> 16) * slock.Pitch;
1518 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1520 DWORD pixel, dpixel = 0;
1521 s = sbuf+3*(sx>>16);
1522 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1523 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1524 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1525 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1527 dx[0] = (pixel )&0xff;
1528 dx[1] = (pixel>> 8)&0xff;
1529 dx[2] = (pixel>>16)&0xff;
1538 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1539 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1540 ret = WINED3DERR_NOTAVAILABLE;
1542 #undef COPY_COLORKEY_FX
1548 if (flags && FIXME_ON(d3d_surface))
1550 FIXME("\tUnsupported flags: %#x.\n", flags);
1554 IWineD3DSurface_Unmap(iface);
1555 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1556 /* Release the converted surface if any */
1557 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1561 /*****************************************************************************
1562 * IWineD3DSurface::BltFast, SW emulation version
1564 * This is the software implementation of BltFast, as used by GDI surfaces
1565 * and as a fallback for OpenGL surfaces. This code is taken from the old
1566 * DirectDraw code, and was originally written by TransGaming.
1571 * src_surface: Source surface to copy from
1572 * rsrc: Source rectangle
1576 * WINED3D_OK on success
1578 *****************************************************************************/
1579 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1580 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1582 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1583 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1585 int bpp, w, h, x, y;
1586 WINED3DLOCKED_RECT dlock,slock;
1587 HRESULT ret = WINED3D_OK;
1589 RECT lock_src, lock_dst, lock_union;
1592 const struct wined3d_format *sEntry, *dEntry;
1594 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1595 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1597 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1599 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1600 return WINEDDERR_SURFACEBUSY;
1605 WARN("rsrc is NULL!\n");
1608 rsrc2.right = src->resource.width;
1609 rsrc2.bottom = src->resource.height;
1613 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1614 if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
1615 || (rsrc->top > src->resource.height) || (rsrc->top < 0)
1616 || (rsrc->left > src->resource.width) || (rsrc->left < 0)
1617 || (rsrc->right > src->resource.width) || (rsrc->right < 0)
1618 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1620 WARN("Application gave us bad source rectangle for BltFast.\n");
1621 return WINEDDERR_INVALIDRECT;
1624 h = rsrc->bottom - rsrc->top;
1625 if (h > This->resource.height-dsty)
1626 h = This->resource.height-dsty;
1627 if (h > src->resource.height-rsrc->top)
1628 h = src->resource.height-rsrc->top;
1630 return WINEDDERR_INVALIDRECT;
1632 w = rsrc->right - rsrc->left;
1633 if (w > This->resource.width-dstx)
1634 w = This->resource.width-dstx;
1635 if (w > src->resource.width-rsrc->left)
1636 w = src->resource.width-rsrc->left;
1638 return WINEDDERR_INVALIDRECT;
1640 /* Now compute the locking rectangle... */
1641 lock_src.left = rsrc->left;
1642 lock_src.top = rsrc->top;
1643 lock_src.right = lock_src.left + w;
1644 lock_src.bottom = lock_src.top + h;
1646 lock_dst.left = dstx;
1647 lock_dst.top = dsty;
1648 lock_dst.right = dstx + w;
1649 lock_dst.bottom = dsty + h;
1651 bpp = This->resource.format->byte_count;
1653 /* We need to lock the surfaces, or we won't get refreshes when done. */
1658 UnionRect(&lock_union, &lock_src, &lock_dst);
1660 /* Lock the union of the two rectangles */
1661 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1662 if (FAILED(ret)) goto error;
1664 pitch = dlock.Pitch;
1665 slock.Pitch = dlock.Pitch;
1667 /* Since slock was originally copied from this surface's description, we can just reuse it */
1668 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1669 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1670 sEntry = src->resource.format;
1675 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1676 if (FAILED(ret)) goto error;
1677 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1678 if (FAILED(ret)) goto error;
1682 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1684 sEntry = src->resource.format;
1685 dEntry = This->resource.format;
1688 /* Handle compressed surfaces first... */
1689 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1691 UINT row_block_count;
1693 TRACE("compressed -> compressed copy\n");
1695 FIXME("trans arg not supported when a compressed surface is involved\n");
1697 FIXME("offset for destination surface is not supported\n");
1698 if (src->resource.format->id != This->resource.format->id)
1700 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1701 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1705 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1706 for (y = 0; y < h; y += dEntry->block_height)
1708 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1709 dbuf += dlock.Pitch;
1710 sbuf += slock.Pitch;
1715 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1717 /* TODO: Use the libtxc_dxtn.so shared library to do
1718 * software decompression
1720 ERR("Software decompression not supported.\n");
1724 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1726 DWORD keylow, keyhigh;
1727 DWORD mask = src->resource.format->red_mask
1728 | src->resource.format->green_mask
1729 | src->resource.format->blue_mask;
1731 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1735 TRACE("Color keyed copy\n");
1736 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1738 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1739 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1743 /* I'm not sure if this is correct */
1744 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1745 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1746 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1749 #define COPYBOX_COLORKEY(type) { \
1750 const type *s = (const type *)sbuf; \
1751 type *d = (type *)dbuf; \
1753 for (y = 0; y < h; y++) { \
1754 for (x = 0; x < w; x++) { \
1756 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1758 s = (const type *)((const BYTE *)s + slock.Pitch); \
1759 d = (type *)((BYTE *)d + dlock.Pitch); \
1765 case 1: COPYBOX_COLORKEY(BYTE)
1766 case 2: COPYBOX_COLORKEY(WORD)
1767 case 4: COPYBOX_COLORKEY(DWORD)
1775 for (y = 0; y < h; y++)
1777 for (x = 0; x < w * 3; x += 3)
1779 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1780 if (tmp < keylow || tmp > keyhigh)
1782 d[x + 0] = s[x + 0];
1783 d[x + 1] = s[x + 1];
1784 d[x + 2] = s[x + 2];
1793 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1794 ret = WINED3DERR_NOTAVAILABLE;
1797 #undef COPYBOX_COLORKEY
1798 TRACE("Copy Done\n");
1802 int width = w * bpp;
1803 INT sbufpitch, dbufpitch;
1805 TRACE("NO color key copy\n");
1806 /* Handle overlapping surfaces */
1809 sbuf += (h - 1) * slock.Pitch;
1810 dbuf += (h - 1) * dlock.Pitch;
1811 sbufpitch = -slock.Pitch;
1812 dbufpitch = -dlock.Pitch;
1816 sbufpitch = slock.Pitch;
1817 dbufpitch = dlock.Pitch;
1819 for (y = 0; y < h; y++)
1821 /* This is pretty easy, a line for line memcpy */
1822 memmove(dbuf, sbuf, width);
1826 TRACE("Copy done\n");
1832 IWineD3DSurface_Unmap(iface);
1836 IWineD3DSurface_Unmap(iface);
1837 IWineD3DSurface_Unmap(src_surface);
1843 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1844 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1846 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1848 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1849 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1851 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1855 pLockedRect->pBits = This->resource.allocatedMemory;
1856 This->lockedRect.left = 0;
1857 This->lockedRect.top = 0;
1858 This->lockedRect.right = This->resource.width;
1859 This->lockedRect.bottom = This->resource.height;
1861 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1862 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1863 This->lockedRect.right, This->lockedRect.bottom);
1867 const struct wined3d_format *format = This->resource.format;
1869 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1870 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1872 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1874 /* Compressed textures are block based, so calculate the offset of
1875 * the block that contains the top-left pixel of the locked rectangle. */
1876 pLockedRect->pBits = This->resource.allocatedMemory
1877 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1878 + ((pRect->left / format->block_width) * format->block_byte_count);
1882 pLockedRect->pBits = This->resource.allocatedMemory +
1883 (pLockedRect->Pitch * pRect->top) +
1884 (pRect->left * format->byte_count);
1886 This->lockedRect.left = pRect->left;
1887 This->lockedRect.top = pRect->top;
1888 This->lockedRect.right = pRect->right;
1889 This->lockedRect.bottom = pRect->bottom;
1892 /* No dirtifying is needed for this surface implementation */
1893 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);