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((IWineD3DResource *)iface, 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((IWineD3DResourceImpl *)iface, guid, data, data_size);
126 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
128 return resource_free_private_data((IWineD3DResourceImpl *)iface, refguid);
131 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
132 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
135 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
136 return resource_get_priority((IWineD3DResource *)iface);
139 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
140 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
141 return resource_get_type((IWineD3DResource *)iface);
144 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
146 TRACE("iface %p.\n", iface);
148 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
151 void WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *desc)
153 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
155 TRACE("iface %p, desc %p.\n", iface, desc);
157 desc->format = surface->resource.format->id;
158 desc->resource_type = surface->resource.resourceType;
159 desc->usage = surface->resource.usage;
160 desc->pool = surface->resource.pool;
161 desc->size = surface->resource.size; /* dx8 only */
162 desc->multisample_type = surface->currentDesc.MultiSampleType;
163 desc->multisample_quality = surface->currentDesc.MultiSampleQuality;
164 desc->width = surface->currentDesc.Width;
165 desc->height = surface->currentDesc.Height;
168 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
170 TRACE("iface %p, flags %#x.\n", iface, flags);
174 case WINEDDGBS_CANBLT:
175 case WINEDDGBS_ISBLTDONE:
179 return WINED3DERR_INVALIDCALL;
183 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
185 /* XXX: DDERR_INVALIDSURFACETYPE */
187 TRACE("iface %p, flags %#x.\n", iface, flags);
191 case WINEDDGFS_CANFLIP:
192 case WINEDDGFS_ISFLIPDONE:
196 return WINED3DERR_INVALIDCALL;
200 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
201 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
202 TRACE("(%p)\n", This);
204 /* D3D8 and 9 loose full devices, ddraw only surfaces */
205 return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
208 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
209 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
210 TRACE("(%p)\n", This);
212 /* So far we don't lose anything :) */
213 This->flags &= ~SFLAG_LOST;
217 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
218 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
219 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
220 TRACE("(%p)->(%p)\n", This, Pal);
222 if(This->palette == PalImpl) {
223 TRACE("Nop palette change\n");
228 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
229 This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
231 This->palette = PalImpl;
235 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
236 PalImpl->flags |= WINEDDPCAPS_PRIMARYSURFACE;
238 return IWineD3DSurface_RealizePalette(iface);
240 else return WINED3D_OK;
243 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
245 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
247 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
249 if (flags & WINEDDCKEY_COLORSPACE)
251 FIXME(" colorkey value not supported (%08x) !\n", flags);
252 return WINED3DERR_INVALIDCALL;
255 /* Dirtify the surface, but only if a key was changed */
258 switch (flags & ~WINEDDCKEY_COLORSPACE)
260 case WINEDDCKEY_DESTBLT:
261 This->DestBltCKey = *CKey;
262 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
265 case WINEDDCKEY_DESTOVERLAY:
266 This->DestOverlayCKey = *CKey;
267 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
270 case WINEDDCKEY_SRCOVERLAY:
271 This->SrcOverlayCKey = *CKey;
272 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
275 case WINEDDCKEY_SRCBLT:
276 This->SrcBltCKey = *CKey;
277 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
283 switch (flags & ~WINEDDCKEY_COLORSPACE)
285 case WINEDDCKEY_DESTBLT:
286 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
289 case WINEDDCKEY_DESTOVERLAY:
290 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
293 case WINEDDCKEY_SRCOVERLAY:
294 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
297 case WINEDDCKEY_SRCBLT:
298 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
306 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
307 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
308 TRACE("(%p)->(%p)\n", This, Pal);
310 *Pal = (IWineD3DPalette *) This->palette;
314 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
316 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
317 const struct wined3d_format *format = This->resource.format;
319 TRACE("(%p)\n", This);
321 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
323 /* Since compressed formats are block based, pitch means the amount of
324 * bytes to the next row of block rather than the next row of pixels. */
325 UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
326 ret = row_block_count * format->block_byte_count;
330 unsigned char alignment = This->resource.device->surface_alignment;
331 ret = This->resource.format->byte_count * This->currentDesc.Width; /* Bytes / row */
332 ret = (ret + alignment - 1) & ~(alignment - 1);
334 TRACE("(%p) Returning %d\n", This, ret);
338 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
339 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
342 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
344 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
346 TRACE("(%p): Not an overlay surface\n", This);
347 return WINEDDERR_NOTAOVERLAYSURFACE;
350 w = This->overlay_destrect.right - This->overlay_destrect.left;
351 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
352 This->overlay_destrect.left = X;
353 This->overlay_destrect.top = Y;
354 This->overlay_destrect.right = X + w;
355 This->overlay_destrect.bottom = Y + h;
357 IWineD3DSurface_DrawOverlay(iface);
362 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
363 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
366 TRACE("(%p)->(%p,%p)\n", This, X, Y);
368 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
370 TRACE("(%p): Not an overlay surface\n", This);
371 return WINEDDERR_NOTAOVERLAYSURFACE;
374 if (!This->overlay_dest)
377 hr = WINEDDERR_OVERLAYNOTVISIBLE;
379 *X = This->overlay_destrect.left;
380 *Y = This->overlay_destrect.top;
384 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
388 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
390 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
392 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
394 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
396 TRACE("(%p): Not an overlay surface\n", This);
397 return WINEDDERR_NOTAOVERLAYSURFACE;
403 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
404 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
406 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
407 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
409 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
410 iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
412 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
414 WARN("(%p): Not an overlay surface\n", This);
415 return WINEDDERR_NOTAOVERLAYSURFACE;
416 } else if(!DstSurface) {
417 WARN("(%p): Dest surface is NULL\n", This);
418 return WINED3DERR_INVALIDCALL;
422 This->overlay_srcrect = *SrcRect;
424 This->overlay_srcrect.left = 0;
425 This->overlay_srcrect.top = 0;
426 This->overlay_srcrect.right = This->currentDesc.Width;
427 This->overlay_srcrect.bottom = This->currentDesc.Height;
431 This->overlay_destrect = *DstRect;
433 This->overlay_destrect.left = 0;
434 This->overlay_destrect.top = 0;
435 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
436 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
439 if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
441 list_remove(&This->overlay_entry);
444 if (flags & WINEDDOVER_SHOW)
446 if (This->overlay_dest != Dst)
448 This->overlay_dest = Dst;
449 list_add_tail(&Dst->overlays, &This->overlay_entry);
452 else if (flags & WINEDDOVER_HIDE)
454 /* tests show that the rectangles are erased on hide */
455 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
456 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
457 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
458 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
459 This->overlay_dest = NULL;
462 IWineD3DSurface_DrawOverlay(iface);
467 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
469 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
470 TRACE("(%p)->(%p)\n", This, clipper);
472 This->clipper = clipper;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 *clipper = This->clipper;
483 IWineD3DClipper_AddRef(*clipper);
488 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
490 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
491 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
493 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
495 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
496 return WINED3DERR_INVALIDCALL;
499 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
501 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
502 This->pow2Width, This->pow2Height);
504 This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
506 This->resource.format = format;
508 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
513 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
515 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
516 const struct wined3d_format *format = This->resource.format;
524 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
526 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
527 return WINED3DERR_INVALIDCALL;
530 switch (format->byte_count)
534 /* Allocate extra space to store the RGB bit masks. */
535 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
539 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
543 /* Allocate extra space for a palette. */
544 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
545 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
550 return E_OUTOFMEMORY;
552 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
553 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
554 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
555 * add an extra line to the dib section
557 GetSystemInfo(&sysInfo);
558 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
560 TRACE("Adding an extra line to the dib section\n");
563 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
564 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
565 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
566 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
567 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
568 b_info->bmiHeader.biPlanes = 1;
569 b_info->bmiHeader.biBitCount = format->byte_count * 8;
571 b_info->bmiHeader.biXPelsPerMeter = 0;
572 b_info->bmiHeader.biYPelsPerMeter = 0;
573 b_info->bmiHeader.biClrUsed = 0;
574 b_info->bmiHeader.biClrImportant = 0;
576 /* Get the bit masks */
577 masks = (DWORD *)b_info->bmiColors;
578 switch (This->resource.format->id)
580 case WINED3DFMT_B8G8R8_UNORM:
581 usage = DIB_RGB_COLORS;
582 b_info->bmiHeader.biCompression = BI_RGB;
585 case WINED3DFMT_B5G5R5X1_UNORM:
586 case WINED3DFMT_B5G5R5A1_UNORM:
587 case WINED3DFMT_B4G4R4A4_UNORM:
588 case WINED3DFMT_B4G4R4X4_UNORM:
589 case WINED3DFMT_B2G3R3_UNORM:
590 case WINED3DFMT_B2G3R3A8_UNORM:
591 case WINED3DFMT_R10G10B10A2_UNORM:
592 case WINED3DFMT_R8G8B8A8_UNORM:
593 case WINED3DFMT_R8G8B8X8_UNORM:
594 case WINED3DFMT_B10G10R10A2_UNORM:
595 case WINED3DFMT_B5G6R5_UNORM:
596 case WINED3DFMT_R16G16B16A16_UNORM:
598 b_info->bmiHeader.biCompression = BI_BITFIELDS;
599 masks[0] = format->red_mask;
600 masks[1] = format->green_mask;
601 masks[2] = format->blue_mask;
605 /* Don't know palette */
606 b_info->bmiHeader.biCompression = BI_RGB;
611 if (!(ddc = GetDC(0)))
613 HeapFree(GetProcessHeap(), 0, b_info);
614 return HRESULT_FROM_WIN32(GetLastError());
617 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
618 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
621 if (!This->dib.DIBsection) {
622 ERR("CreateDIBSection failed!\n");
623 HeapFree(GetProcessHeap(), 0, b_info);
624 return HRESULT_FROM_WIN32(GetLastError());
627 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
628 /* copy the existing surface to the dib section */
629 if(This->resource.allocatedMemory) {
630 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
632 /* This is to make LockRect read the gl Texture although memory is allocated */
633 This->flags &= ~SFLAG_INSYSMEM;
635 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
637 HeapFree(GetProcessHeap(), 0, b_info);
639 /* Now allocate a HDC */
640 This->hDC = CreateCompatibleDC(0);
641 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
642 TRACE("using wined3d palette %p\n", This->palette);
643 SelectPalette(This->hDC,
644 This->palette ? This->palette->hpal : 0,
647 This->flags |= SFLAG_DIBSECTION;
649 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
650 This->resource.heapMemory = NULL;
655 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
656 unsigned int w, unsigned int h)
660 unsigned short *dst_s;
662 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
663 for(y = 0; y < h; y++) {
664 src_f = (const float *)(src + y * pitch_in);
665 dst_s = (unsigned short *) (dst + y * pitch_out);
666 for(x = 0; x < w; x++) {
667 dst_s[x] = float_32_to_16(src_f + x);
672 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
673 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
675 static const unsigned char convert_5to8[] =
677 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
678 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
679 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
680 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
682 static const unsigned char convert_6to8[] =
684 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
685 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
686 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
687 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
688 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
689 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
690 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
691 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
695 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
697 for (y = 0; y < h; ++y)
699 const WORD *src_line = (const WORD *)(src + y * pitch_in);
700 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
701 for (x = 0; x < w; ++x)
703 WORD pixel = src_line[x];
704 dst_line[x] = 0xff000000
705 | convert_5to8[(pixel & 0xf800) >> 11] << 16
706 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
707 | convert_5to8[(pixel & 0x001f)];
712 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
713 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
717 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
719 for (y = 0; y < h; ++y)
721 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
722 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
724 for (x = 0; x < w; ++x)
726 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
731 static inline BYTE cliptobyte(int x)
733 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
736 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
737 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
740 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
742 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
744 for (y = 0; y < h; ++y)
746 const BYTE *src_line = src + y * pitch_in;
747 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
748 for (x = 0; x < w; ++x)
750 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
751 * C = Y - 16; D = U - 128; E = V - 128;
752 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
753 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
754 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
755 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
756 * U and V are shared between the pixels.
758 if (!(x & 1)) /* for every even pixel, read new U and V */
760 d = (int) src_line[1] - 128;
761 e = (int) src_line[3] - 128;
763 g2 = - 100 * d - 208 * e + 128;
766 c2 = 298 * ((int) src_line[0] - 16);
767 dst_line[x] = 0xff000000
768 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
769 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
770 | cliptobyte((c2 + b2) >> 8); /* blue */
771 /* Scale RGB values to 0..255 range,
772 * then clip them if still not in range (may be negative),
773 * then shift them within DWORD if necessary.
780 struct d3dfmt_convertor_desc
782 enum wined3d_format_id from, to;
783 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
786 static const struct d3dfmt_convertor_desc convertors[] =
788 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
789 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
790 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
791 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
794 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
797 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
798 if(convertors[i].from == from && convertors[i].to == to) {
799 return &convertors[i];
805 /*****************************************************************************
806 * surface_convert_format
808 * Creates a duplicate of a surface in a different format. Is used by Blt to
809 * blit between surfaces with different formats
812 * source: Source surface
813 * fmt: Requested destination format
815 *****************************************************************************/
816 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
818 IWineD3DSurface *ret = NULL;
819 const struct d3dfmt_convertor_desc *conv;
820 WINED3DLOCKED_RECT lock_src, lock_dst;
823 conv = find_convertor(source->resource.format->id, to_fmt);
826 FIXME("Cannot find a conversion function from format %s to %s.\n",
827 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
831 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
832 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
833 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
834 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
835 NULL /* parent */, &wined3d_null_parent_ops, &ret);
837 ERR("Failed to create a destination surface for conversion\n");
841 memset(&lock_src, 0, sizeof(lock_src));
842 memset(&lock_dst, 0, sizeof(lock_dst));
844 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
847 ERR("Failed to lock the source surface.\n");
848 IWineD3DSurface_Release(ret);
851 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
854 ERR("Failed to lock the dest surface\n");
855 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
856 IWineD3DSurface_Release(ret);
860 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
861 source->currentDesc.Width, source->currentDesc.Height);
863 IWineD3DSurface_Unmap(ret);
864 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
866 return (IWineD3DSurfaceImpl *) ret;
869 /*****************************************************************************
872 * Helper function that fills a memory area with a specific color
875 * buf: memory address to start filling at
876 * width, height: Dimensions of the area to fill
877 * bpp: Bit depth of the surface
878 * lPitch: pitch of the surface
879 * color: Color to fill with
881 *****************************************************************************/
883 _Blt_ColorFill(BYTE *buf,
884 int width, int height,
885 int bpp, LONG lPitch,
893 #define COLORFILL_ROW(type) \
895 type *d = (type *) buf; \
896 for (x = 0; x < width; x++) \
897 d[x] = (type) color; \
902 case 1: COLORFILL_ROW(BYTE)
903 case 2: COLORFILL_ROW(WORD)
907 for (x = 0; x < width; x++,d+=3)
909 d[0] = (color ) & 0xFF;
910 d[1] = (color>> 8) & 0xFF;
911 d[2] = (color>>16) & 0xFF;
915 case 4: COLORFILL_ROW(DWORD)
917 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
918 return WINED3DERR_NOTAVAILABLE;
923 /* Now copy first row */
925 for (y = 1; y < height; y++)
928 memcpy(buf, first, width * bpp);
933 /*****************************************************************************
934 * IWineD3DSurface::Blt, SW emulation version
936 * Performs a blit to a surface, with or without a source surface.
937 * This is the main functionality of DirectDraw
940 * DestRect: Destination rectangle to write to
941 * src_surface: Source surface, can be NULL
942 * SrcRect: Source rectangle
943 *****************************************************************************/
944 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
945 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
947 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
948 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
950 HRESULT ret = WINED3D_OK;
951 WINED3DLOCKED_RECT dlock, slock;
952 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
953 const struct wined3d_format *sEntry, *dEntry;
958 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
959 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
960 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
962 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
964 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
965 return WINEDDERR_SURFACEBUSY;
968 /* First check for the validity of source / destination rectangles.
969 * This was verified using a test application + by MSDN. */
975 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
976 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
977 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
978 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
979 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
981 WARN("Application gave us bad source rectangle for Blt.\n");
982 return WINEDDERR_INVALIDRECT;
985 if (!SrcRect->right || !SrcRect->bottom
986 || SrcRect->left == (int)src->currentDesc.Width
987 || SrcRect->top == (int)src->currentDesc.Height)
989 TRACE("Nothing to be done.\n");
1000 xsrc.right = src->currentDesc.Width;
1001 xsrc.bottom = src->currentDesc.Height;
1005 memset(&xsrc, 0, sizeof(xsrc));
1010 /* For the Destination rect, it can be out of bounds on the condition
1011 * that a clipper is set for the given surface. */
1012 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1013 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1014 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1015 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1016 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1018 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1019 return WINEDDERR_INVALIDRECT;
1022 if (DestRect->right <= 0 || DestRect->bottom <= 0
1023 || DestRect->left >= (int)This->currentDesc.Width
1024 || DestRect->top >= (int)This->currentDesc.Height)
1026 TRACE("Nothing to be done.\n");
1036 full_rect.right = This->currentDesc.Width;
1037 full_rect.bottom = This->currentDesc.Height;
1038 IntersectRect(&xdst, &full_rect, DestRect);
1042 BOOL clip_horiz, clip_vert;
1045 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1046 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1048 if (clip_vert || clip_horiz)
1050 /* Now check if this is a special case or not... */
1051 if ((flags & WINEDDBLT_DDFX)
1052 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1053 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1055 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1063 xsrc.left -= xdst.left;
1066 if (xdst.right > This->currentDesc.Width)
1068 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1069 xdst.right = (int)This->currentDesc.Width;
1077 xsrc.top -= xdst.top;
1080 if (xdst.bottom > This->currentDesc.Height)
1082 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1083 xdst.bottom = (int)This->currentDesc.Height;
1087 /* And check if after clipping something is still to be done... */
1088 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1089 || (xdst.left >= (int)This->currentDesc.Width)
1090 || (xdst.top >= (int)This->currentDesc.Height)
1091 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1092 || (xsrc.left >= (int)src->currentDesc.Width)
1093 || (xsrc.top >= (int)src->currentDesc.Height))
1095 TRACE("Nothing to be done after clipping.\n");
1105 xdst.right = This->currentDesc.Width;
1106 xdst.bottom = This->currentDesc.Height;
1111 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1113 sEntry = This->resource.format;
1118 dEntry = This->resource.format;
1121 if (This->resource.format->id != src->resource.format->id)
1123 src = surface_convert_format(src, dEntry->id);
1126 /* The conv function writes a FIXME */
1127 WARN("Cannot convert source surface format to dest format\n");
1131 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1132 sEntry = src->resource.format;
1139 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1141 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1144 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1146 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1148 if (!DestRect || src == This)
1150 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1155 bpp = This->resource.format->byte_count;
1156 srcheight = xsrc.bottom - xsrc.top;
1157 srcwidth = xsrc.right - xsrc.left;
1158 dstheight = xdst.bottom - xdst.top;
1159 dstwidth = xdst.right - xdst.left;
1160 width = (xdst.right - xdst.left) * bpp;
1162 if (DestRect && src != This)
1165 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1167 if (flags & WINEDDBLT_WAIT)
1169 flags &= ~WINEDDBLT_WAIT;
1171 if (flags & WINEDDBLT_ASYNC)
1173 static BOOL displayed = FALSE;
1175 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1177 flags &= ~WINEDDBLT_ASYNC;
1179 if (flags & WINEDDBLT_DONOTWAIT)
1181 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1182 static BOOL displayed = FALSE;
1184 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1186 flags &= ~WINEDDBLT_DONOTWAIT;
1189 /* First, all the 'source-less' blits */
1190 if (flags & WINEDDBLT_COLORFILL)
1192 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1193 dlock.Pitch, DDBltFx->u5.dwFillColor);
1194 flags &= ~WINEDDBLT_COLORFILL;
1197 if (flags & WINEDDBLT_DEPTHFILL)
1199 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1201 if (flags & WINEDDBLT_ROP)
1203 /* Catch some degenerate cases here */
1204 switch(DDBltFx->dwROP)
1207 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1209 case 0xAA0029: /* No-op */
1212 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1214 case SRCCOPY: /* well, we do that below ? */
1217 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1220 flags &= ~WINEDDBLT_ROP;
1222 if (flags & WINEDDBLT_DDROPS)
1224 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1226 /* Now the 'with source' blits */
1230 int sx, xinc, sy, yinc;
1232 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1235 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1236 && (srcwidth != dstwidth || srcheight != dstheight))
1238 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1239 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1242 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1243 xinc = (srcwidth << 16) / dstwidth;
1244 yinc = (srcheight << 16) / dstheight;
1248 /* No effects, we can cheat here */
1249 if (dstwidth == srcwidth)
1251 if (dstheight == srcheight)
1253 /* No stretching in either direction. This needs to be as
1254 * fast as possible */
1257 /* check for overlapping surfaces */
1258 if (src != This || xdst.top < xsrc.top ||
1259 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1261 /* no overlap, or dst above src, so copy from top downwards */
1262 for (y = 0; y < dstheight; y++)
1264 memcpy(dbuf, sbuf, width);
1265 sbuf += slock.Pitch;
1266 dbuf += dlock.Pitch;
1269 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1271 sbuf += (slock.Pitch*dstheight);
1272 dbuf += (dlock.Pitch*dstheight);
1273 for (y = 0; y < dstheight; y++)
1275 sbuf -= slock.Pitch;
1276 dbuf -= dlock.Pitch;
1277 memcpy(dbuf, sbuf, width);
1280 else /* src and dst overlapping on the same line, use memmove */
1282 for (y = 0; y < dstheight; y++)
1284 memmove(dbuf, sbuf, width);
1285 sbuf += slock.Pitch;
1286 dbuf += dlock.Pitch;
1290 /* Stretching in Y direction only */
1291 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1292 sbuf = sbase + (sy >> 16) * slock.Pitch;
1293 memcpy(dbuf, sbuf, width);
1294 dbuf += dlock.Pitch;
1300 /* Stretching in X direction */
1302 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1304 sbuf = sbase + (sy >> 16) * slock.Pitch;
1306 if ((sy >> 16) == (last_sy >> 16))
1308 /* this sourcerow is the same as last sourcerow -
1309 * copy already stretched row
1311 memcpy(dbuf, dbuf - dlock.Pitch, width);
1315 #define STRETCH_ROW(type) { \
1316 const type *s = (const type *)sbuf; \
1317 type *d = (type *)dbuf; \
1318 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1319 d[x] = s[sx >> 16]; \
1324 case 1: STRETCH_ROW(BYTE)
1325 case 2: STRETCH_ROW(WORD)
1326 case 4: STRETCH_ROW(DWORD)
1331 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1335 s = sbuf+3*(sx>>16);
1336 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1337 d[0] = (pixel )&0xff;
1338 d[1] = (pixel>> 8)&0xff;
1339 d[2] = (pixel>>16)&0xff;
1345 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1346 ret = WINED3DERR_NOTAVAILABLE;
1351 dbuf += dlock.Pitch;
1358 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1359 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1360 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1361 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1363 /* The color keying flags are checked for correctness in ddraw */
1364 if (flags & WINEDDBLT_KEYSRC)
1366 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1367 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1369 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1371 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1372 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1375 if (flags & WINEDDBLT_KEYDEST)
1377 /* Destination color keys are taken from the source surface ! */
1378 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1379 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1381 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1383 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1384 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1393 keymask = sEntry->red_mask
1394 | sEntry->green_mask
1395 | sEntry->blue_mask;
1397 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1400 if (flags & WINEDDBLT_DDFX)
1402 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1405 dTopRight = dbuf+((dstwidth-1)*bpp);
1406 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1407 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1409 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1411 /* I don't think we need to do anything about this flag */
1412 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1414 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1417 dTopRight = dTopLeft;
1420 dBottomRight = dBottomLeft;
1422 dstxinc = dstxinc *-1;
1424 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1427 dTopLeft = dBottomLeft;
1430 dTopRight = dBottomRight;
1432 dstyinc = dstyinc *-1;
1434 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1436 /* I don't think we need to do anything about this flag */
1437 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1439 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1442 dBottomRight = dTopLeft;
1445 dBottomLeft = dTopRight;
1447 dstxinc = dstxinc * -1;
1448 dstyinc = dstyinc * -1;
1450 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1453 dTopLeft = dBottomLeft;
1454 dBottomLeft = dBottomRight;
1455 dBottomRight = dTopRight;
1460 dstxinc = dstxinc * -1;
1462 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1465 dTopLeft = dTopRight;
1466 dTopRight = dBottomRight;
1467 dBottomRight = dBottomLeft;
1472 dstyinc = dstyinc * -1;
1474 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1476 /* I don't think we need to do anything about this flag */
1477 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1480 flags &= ~(WINEDDBLT_DDFX);
1483 #define COPY_COLORKEY_FX(type) { \
1485 type *d = (type *)dbuf, *dx, tmp; \
1486 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1487 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1489 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1490 tmp = s[sx >> 16]; \
1491 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1492 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1495 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1497 d = (type*)(((LPBYTE)d)+dstyinc); \
1502 case 1: COPY_COLORKEY_FX(BYTE)
1503 case 2: COPY_COLORKEY_FX(WORD)
1504 case 4: COPY_COLORKEY_FX(DWORD)
1508 BYTE *d = dbuf, *dx;
1509 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1511 sbuf = sbase + (sy >> 16) * slock.Pitch;
1513 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1515 DWORD pixel, dpixel = 0;
1516 s = sbuf+3*(sx>>16);
1517 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1518 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1519 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1520 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1522 dx[0] = (pixel )&0xff;
1523 dx[1] = (pixel>> 8)&0xff;
1524 dx[2] = (pixel>>16)&0xff;
1533 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1534 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1535 ret = WINED3DERR_NOTAVAILABLE;
1537 #undef COPY_COLORKEY_FX
1543 if (flags && FIXME_ON(d3d_surface))
1545 FIXME("\tUnsupported flags: %#x.\n", flags);
1549 IWineD3DSurface_Unmap(iface);
1550 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1551 /* Release the converted surface if any */
1552 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1556 /*****************************************************************************
1557 * IWineD3DSurface::BltFast, SW emulation version
1559 * This is the software implementation of BltFast, as used by GDI surfaces
1560 * and as a fallback for OpenGL surfaces. This code is taken from the old
1561 * DirectDraw code, and was originally written by TransGaming.
1566 * src_surface: Source surface to copy from
1567 * rsrc: Source rectangle
1571 * WINED3D_OK on success
1573 *****************************************************************************/
1574 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1575 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1577 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1578 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1580 int bpp, w, h, x, y;
1581 WINED3DLOCKED_RECT dlock,slock;
1582 HRESULT ret = WINED3D_OK;
1584 RECT lock_src, lock_dst, lock_union;
1587 const struct wined3d_format *sEntry, *dEntry;
1589 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1590 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1592 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1594 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1595 return WINEDDERR_SURFACEBUSY;
1600 WARN("rsrc is NULL!\n");
1603 rsrc2.right = src->currentDesc.Width;
1604 rsrc2.bottom = src->currentDesc.Height;
1608 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1609 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1610 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1611 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1612 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1613 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1615 WARN("Application gave us bad source rectangle for BltFast.\n");
1616 return WINEDDERR_INVALIDRECT;
1619 h = rsrc->bottom - rsrc->top;
1620 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1621 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1622 if (h <= 0) return WINEDDERR_INVALIDRECT;
1624 w = rsrc->right - rsrc->left;
1625 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1626 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1627 if (w <= 0) return WINEDDERR_INVALIDRECT;
1629 /* Now compute the locking rectangle... */
1630 lock_src.left = rsrc->left;
1631 lock_src.top = rsrc->top;
1632 lock_src.right = lock_src.left + w;
1633 lock_src.bottom = lock_src.top + h;
1635 lock_dst.left = dstx;
1636 lock_dst.top = dsty;
1637 lock_dst.right = dstx + w;
1638 lock_dst.bottom = dsty + h;
1640 bpp = This->resource.format->byte_count;
1642 /* We need to lock the surfaces, or we won't get refreshes when done. */
1647 UnionRect(&lock_union, &lock_src, &lock_dst);
1649 /* Lock the union of the two rectangles */
1650 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1651 if (FAILED(ret)) goto error;
1653 pitch = dlock.Pitch;
1654 slock.Pitch = dlock.Pitch;
1656 /* Since slock was originally copied from this surface's description, we can just reuse it */
1657 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1658 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1659 sEntry = src->resource.format;
1664 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1665 if (FAILED(ret)) goto error;
1666 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1667 if (FAILED(ret)) goto error;
1671 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1673 sEntry = src->resource.format;
1674 dEntry = This->resource.format;
1677 /* Handle compressed surfaces first... */
1678 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1680 UINT row_block_count;
1682 TRACE("compressed -> compressed copy\n");
1684 FIXME("trans arg not supported when a compressed surface is involved\n");
1686 FIXME("offset for destination surface is not supported\n");
1687 if (src->resource.format->id != This->resource.format->id)
1689 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1690 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1694 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1695 for (y = 0; y < h; y += dEntry->block_height)
1697 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1698 dbuf += dlock.Pitch;
1699 sbuf += slock.Pitch;
1704 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1706 /* TODO: Use the libtxc_dxtn.so shared library to do
1707 * software decompression
1709 ERR("Software decompression not supported.\n");
1713 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1715 DWORD keylow, keyhigh;
1716 DWORD mask = src->resource.format->red_mask
1717 | src->resource.format->green_mask
1718 | src->resource.format->blue_mask;
1720 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1724 TRACE("Color keyed copy\n");
1725 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1727 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1728 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1732 /* I'm not sure if this is correct */
1733 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1734 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1735 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1738 #define COPYBOX_COLORKEY(type) { \
1739 const type *s = (const type *)sbuf; \
1740 type *d = (type *)dbuf; \
1742 for (y = 0; y < h; y++) { \
1743 for (x = 0; x < w; x++) { \
1745 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1747 s = (const type *)((const BYTE *)s + slock.Pitch); \
1748 d = (type *)((BYTE *)d + dlock.Pitch); \
1754 case 1: COPYBOX_COLORKEY(BYTE)
1755 case 2: COPYBOX_COLORKEY(WORD)
1756 case 4: COPYBOX_COLORKEY(DWORD)
1764 for (y = 0; y < h; y++)
1766 for (x = 0; x < w * 3; x += 3)
1768 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1769 if (tmp < keylow || tmp > keyhigh)
1771 d[x + 0] = s[x + 0];
1772 d[x + 1] = s[x + 1];
1773 d[x + 2] = s[x + 2];
1782 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1783 ret = WINED3DERR_NOTAVAILABLE;
1786 #undef COPYBOX_COLORKEY
1787 TRACE("Copy Done\n");
1791 int width = w * bpp;
1792 INT sbufpitch, dbufpitch;
1794 TRACE("NO color key copy\n");
1795 /* Handle overlapping surfaces */
1798 sbuf += (h - 1) * slock.Pitch;
1799 dbuf += (h - 1) * dlock.Pitch;
1800 sbufpitch = -slock.Pitch;
1801 dbufpitch = -dlock.Pitch;
1805 sbufpitch = slock.Pitch;
1806 dbufpitch = dlock.Pitch;
1808 for (y = 0; y < h; y++)
1810 /* This is pretty easy, a line for line memcpy */
1811 memmove(dbuf, sbuf, width);
1815 TRACE("Copy done\n");
1821 IWineD3DSurface_Unmap(iface);
1825 IWineD3DSurface_Unmap(iface);
1826 IWineD3DSurface_Unmap(src_surface);
1832 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1833 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1835 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1837 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1838 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1840 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1844 pLockedRect->pBits = This->resource.allocatedMemory;
1845 This->lockedRect.left = 0;
1846 This->lockedRect.top = 0;
1847 This->lockedRect.right = This->currentDesc.Width;
1848 This->lockedRect.bottom = This->currentDesc.Height;
1850 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1851 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1852 This->lockedRect.right, This->lockedRect.bottom);
1856 const struct wined3d_format *format = This->resource.format;
1858 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1859 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1861 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1863 /* Compressed textures are block based, so calculate the offset of
1864 * the block that contains the top-left pixel of the locked rectangle. */
1865 pLockedRect->pBits = This->resource.allocatedMemory
1866 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1867 + ((pRect->left / format->block_width) * format->block_byte_count);
1871 pLockedRect->pBits = This->resource.allocatedMemory +
1872 (pLockedRect->Pitch * pRect->top) +
1873 (pRect->left * format->byte_count);
1875 This->lockedRect.left = pRect->left;
1876 This->lockedRect.top = pRect->top;
1877 This->lockedRect.right = pRect->right;
1878 This->lockedRect.bottom = pRect->bottom;
1881 /* No dirtifying is needed for this surface implementation */
1882 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1887 /* TODO: think about moving this down to resource? */
1888 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1890 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1892 /* This should only be called for sysmem textures, it may be a good idea
1893 * to extend this to all pools at some point in the future */
1894 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1896 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1898 return This->resource.allocatedMemory;