2 * IWineD3DSurface Implementation of management(non-rendering) functions
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in)
40 float tmp = fabs(*in);
41 unsigned int mantissa;
44 /* Deal with special numbers */
45 if (*in == 0.0f) return 0x0000;
46 if(isnan(*in)) return 0x7C01;
47 if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
49 if(tmp < powf(2, 10)) {
54 }while(tmp < powf(2, 10));
55 } else if(tmp >= powf(2, 11)) {
60 }while(tmp >= powf(2, 11));
63 mantissa = (unsigned int) tmp;
64 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
66 exp += 10; /* Normalize the mantissa */
67 exp += 15; /* Exponent is encoded with excess 15 */
69 if(exp > 30) { /* too big */
70 ret = 0x7c00; /* INF */
72 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
74 mantissa = mantissa >> 1;
77 ret = mantissa & 0x3ff;
79 ret = (exp << 10) | (mantissa & 0x3ff);
82 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
86 /* *******************************************
87 IWineD3DSurface IUnknown parts follow
88 ******************************************* */
89 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
91 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
92 /* Warn ,but be nice about things */
93 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
95 if (IsEqualGUID(riid, &IID_IUnknown)
96 || IsEqualGUID(riid, &IID_IWineD3DBase)
97 || IsEqualGUID(riid, &IID_IWineD3DResource)
98 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
99 IUnknown_AddRef((IUnknown*)iface);
104 return E_NOINTERFACE;
107 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
109 ULONG ref = InterlockedIncrement(&This->resource.ref);
110 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
114 /* ****************************************************
115 IWineD3DSurface IWineD3DResource parts follow
116 **************************************************** */
117 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
118 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
122 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
126 return resource_free_private_data((IWineD3DResource *)iface, refguid);
129 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
130 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
133 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
134 return resource_get_priority((IWineD3DResource *)iface);
137 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
138 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
139 return resource_get_type((IWineD3DResource *)iface);
142 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
144 TRACE("iface %p.\n", iface);
146 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
149 void WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *desc)
151 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
153 TRACE("iface %p, desc %p.\n", iface, desc);
155 desc->format = surface->resource.format->id;
156 desc->resource_type = surface->resource.resourceType;
157 desc->usage = surface->resource.usage;
158 desc->pool = surface->resource.pool;
159 desc->size = surface->resource.size; /* dx8 only */
160 desc->multisample_type = surface->currentDesc.MultiSampleType;
161 desc->multisample_quality = surface->currentDesc.MultiSampleQuality;
162 desc->width = surface->currentDesc.Width;
163 desc->height = surface->currentDesc.Height;
166 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
168 TRACE("iface %p, flags %#x.\n", iface, Flags);
172 case WINEDDGBS_CANBLT:
173 case WINEDDGBS_ISBLTDONE:
177 return WINED3DERR_INVALIDCALL;
181 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
182 /* XXX: DDERR_INVALIDSURFACETYPE */
184 TRACE("(%p)->(%08x)\n",iface,Flags);
186 case WINEDDGFS_CANFLIP:
187 case WINEDDGFS_ISFLIPDONE:
191 return WINED3DERR_INVALIDCALL;
195 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
196 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
197 TRACE("(%p)\n", This);
199 /* D3D8 and 9 loose full devices, ddraw only surfaces */
200 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
203 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
204 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
205 TRACE("(%p)\n", This);
207 /* So far we don't lose anything :) */
208 This->Flags &= ~SFLAG_LOST;
212 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
213 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
214 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
215 TRACE("(%p)->(%p)\n", This, Pal);
217 if(This->palette == PalImpl) {
218 TRACE("Nop palette change\n");
223 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
224 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
226 This->palette = PalImpl;
230 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
231 PalImpl->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
233 return IWineD3DSurface_RealizePalette(iface);
235 else return WINED3D_OK;
238 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
240 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
241 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
243 if (Flags & WINEDDCKEY_COLORSPACE)
245 FIXME(" colorkey value not supported (%08x) !\n", Flags);
246 return WINED3DERR_INVALIDCALL;
249 /* Dirtify the surface, but only if a key was changed */
251 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
252 case WINEDDCKEY_DESTBLT:
253 This->DestBltCKey = *CKey;
254 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
257 case WINEDDCKEY_DESTOVERLAY:
258 This->DestOverlayCKey = *CKey;
259 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
262 case WINEDDCKEY_SRCOVERLAY:
263 This->SrcOverlayCKey = *CKey;
264 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
267 case WINEDDCKEY_SRCBLT:
268 This->SrcBltCKey = *CKey;
269 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
274 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
275 case WINEDDCKEY_DESTBLT:
276 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
279 case WINEDDCKEY_DESTOVERLAY:
280 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
283 case WINEDDCKEY_SRCOVERLAY:
284 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
287 case WINEDDCKEY_SRCBLT:
288 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
296 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
297 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
298 TRACE("(%p)->(%p)\n", This, Pal);
300 *Pal = (IWineD3DPalette *) This->palette;
304 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
306 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
307 const struct wined3d_format *format = This->resource.format;
309 TRACE("(%p)\n", This);
311 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
313 /* Since compressed formats are block based, pitch means the amount of
314 * bytes to the next row of block rather than the next row of pixels. */
315 UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
316 ret = row_block_count * format->block_byte_count;
320 unsigned char alignment = This->resource.device->surface_alignment;
321 ret = This->resource.format->byte_count * This->currentDesc.Width; /* Bytes / row */
322 ret = (ret + alignment - 1) & ~(alignment - 1);
324 TRACE("(%p) Returning %d\n", This, ret);
328 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
329 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
332 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
334 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
336 TRACE("(%p): Not an overlay surface\n", This);
337 return WINEDDERR_NOTAOVERLAYSURFACE;
340 w = This->overlay_destrect.right - This->overlay_destrect.left;
341 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
342 This->overlay_destrect.left = X;
343 This->overlay_destrect.top = Y;
344 This->overlay_destrect.right = X + w;
345 This->overlay_destrect.bottom = Y + h;
347 IWineD3DSurface_DrawOverlay(iface);
352 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
353 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
356 TRACE("(%p)->(%p,%p)\n", This, X, Y);
358 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
360 TRACE("(%p): Not an overlay surface\n", This);
361 return WINEDDERR_NOTAOVERLAYSURFACE;
364 if (!This->overlay_dest)
367 hr = WINEDDERR_OVERLAYNOTVISIBLE;
369 *X = This->overlay_destrect.left;
370 *Y = This->overlay_destrect.top;
374 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
378 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
379 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
381 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
383 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
385 TRACE("(%p): Not an overlay surface\n", This);
386 return WINEDDERR_NOTAOVERLAYSURFACE;
392 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
393 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
395 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
396 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
397 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
399 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
401 WARN("(%p): Not an overlay surface\n", This);
402 return WINEDDERR_NOTAOVERLAYSURFACE;
403 } else if(!DstSurface) {
404 WARN("(%p): Dest surface is NULL\n", This);
405 return WINED3DERR_INVALIDCALL;
409 This->overlay_srcrect = *SrcRect;
411 This->overlay_srcrect.left = 0;
412 This->overlay_srcrect.top = 0;
413 This->overlay_srcrect.right = This->currentDesc.Width;
414 This->overlay_srcrect.bottom = This->currentDesc.Height;
418 This->overlay_destrect = *DstRect;
420 This->overlay_destrect.left = 0;
421 This->overlay_destrect.top = 0;
422 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
423 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
426 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
427 list_remove(&This->overlay_entry);
430 if(Flags & WINEDDOVER_SHOW) {
431 if(This->overlay_dest != Dst) {
432 This->overlay_dest = Dst;
433 list_add_tail(&Dst->overlays, &This->overlay_entry);
435 } else if(Flags & WINEDDOVER_HIDE) {
436 /* tests show that the rectangles are erased on hide */
437 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
438 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
439 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
440 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
441 This->overlay_dest = NULL;
444 IWineD3DSurface_DrawOverlay(iface);
449 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
451 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
452 TRACE("(%p)->(%p)\n", This, clipper);
454 This->clipper = clipper;
458 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
460 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
461 TRACE("(%p)->(%p)\n", This, clipper);
463 *clipper = This->clipper;
465 IWineD3DClipper_AddRef(*clipper);
470 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
472 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
473 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
475 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
477 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
478 return WINED3DERR_INVALIDCALL;
481 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
483 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
484 This->pow2Width, This->pow2Height);
486 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
488 This->resource.format = format;
490 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
495 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
497 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
498 const struct wined3d_format *format = This->resource.format;
506 if (!(format->Flags & WINED3DFMT_FLAG_GETDC))
508 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
509 return WINED3DERR_INVALIDCALL;
512 switch (format->byte_count)
516 /* Allocate extra space to store the RGB bit masks. */
517 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
521 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
525 /* Allocate extra space for a palette. */
526 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
527 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
532 return E_OUTOFMEMORY;
534 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
535 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
536 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
537 * add an extra line to the dib section
539 GetSystemInfo(&sysInfo);
540 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
542 TRACE("Adding an extra line to the dib section\n");
545 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
546 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
547 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
548 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
549 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
550 b_info->bmiHeader.biPlanes = 1;
551 b_info->bmiHeader.biBitCount = format->byte_count * 8;
553 b_info->bmiHeader.biXPelsPerMeter = 0;
554 b_info->bmiHeader.biYPelsPerMeter = 0;
555 b_info->bmiHeader.biClrUsed = 0;
556 b_info->bmiHeader.biClrImportant = 0;
558 /* Get the bit masks */
559 masks = (DWORD *)b_info->bmiColors;
560 switch (This->resource.format->id)
562 case WINED3DFMT_B8G8R8_UNORM:
563 usage = DIB_RGB_COLORS;
564 b_info->bmiHeader.biCompression = BI_RGB;
567 case WINED3DFMT_B5G5R5X1_UNORM:
568 case WINED3DFMT_B5G5R5A1_UNORM:
569 case WINED3DFMT_B4G4R4A4_UNORM:
570 case WINED3DFMT_B4G4R4X4_UNORM:
571 case WINED3DFMT_B2G3R3_UNORM:
572 case WINED3DFMT_B2G3R3A8_UNORM:
573 case WINED3DFMT_R10G10B10A2_UNORM:
574 case WINED3DFMT_R8G8B8A8_UNORM:
575 case WINED3DFMT_R8G8B8X8_UNORM:
576 case WINED3DFMT_B10G10R10A2_UNORM:
577 case WINED3DFMT_B5G6R5_UNORM:
578 case WINED3DFMT_R16G16B16A16_UNORM:
580 b_info->bmiHeader.biCompression = BI_BITFIELDS;
581 masks[0] = format->red_mask;
582 masks[1] = format->green_mask;
583 masks[2] = format->blue_mask;
587 /* Don't know palette */
588 b_info->bmiHeader.biCompression = BI_RGB;
593 if (!(ddc = GetDC(0)))
595 HeapFree(GetProcessHeap(), 0, b_info);
596 return HRESULT_FROM_WIN32(GetLastError());
599 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);
600 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
603 if (!This->dib.DIBsection) {
604 ERR("CreateDIBSection failed!\n");
605 HeapFree(GetProcessHeap(), 0, b_info);
606 return HRESULT_FROM_WIN32(GetLastError());
609 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
610 /* copy the existing surface to the dib section */
611 if(This->resource.allocatedMemory) {
612 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
614 /* This is to make LockRect read the gl Texture although memory is allocated */
615 This->Flags &= ~SFLAG_INSYSMEM;
617 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
619 HeapFree(GetProcessHeap(), 0, b_info);
621 /* Now allocate a HDC */
622 This->hDC = CreateCompatibleDC(0);
623 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
624 TRACE("using wined3d palette %p\n", This->palette);
625 SelectPalette(This->hDC,
626 This->palette ? This->palette->hpal : 0,
629 This->Flags |= SFLAG_DIBSECTION;
631 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
632 This->resource.heapMemory = NULL;
637 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
638 unsigned int w, unsigned int h)
642 unsigned short *dst_s;
644 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
645 for(y = 0; y < h; y++) {
646 src_f = (const float *)(src + y * pitch_in);
647 dst_s = (unsigned short *) (dst + y * pitch_out);
648 for(x = 0; x < w; x++) {
649 dst_s[x] = float_32_to_16(src_f + x);
654 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
655 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
657 static const unsigned char convert_5to8[] =
659 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
660 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
661 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
662 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
664 static const unsigned char convert_6to8[] =
666 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
667 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
668 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
669 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
670 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
671 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
672 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
673 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
677 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
679 for (y = 0; y < h; ++y)
681 const WORD *src_line = (const WORD *)(src + y * pitch_in);
682 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
683 for (x = 0; x < w; ++x)
685 WORD pixel = src_line[x];
686 dst_line[x] = 0xff000000
687 | convert_5to8[(pixel & 0xf800) >> 11] << 16
688 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
689 | convert_5to8[(pixel & 0x001f)];
694 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
695 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
699 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
701 for (y = 0; y < h; ++y)
703 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
704 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
706 for (x = 0; x < w; ++x)
708 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
713 static inline BYTE cliptobyte(int x)
715 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
718 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
719 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
722 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
724 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
726 for (y = 0; y < h; ++y)
728 const BYTE *src_line = src + y * pitch_in;
729 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
730 for (x = 0; x < w; ++x)
732 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
733 * C = Y - 16; D = U - 128; E = V - 128;
734 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
735 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
736 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
737 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
738 * U and V are shared between the pixels.
740 if (!(x & 1)) /* for every even pixel, read new U and V */
742 d = (int) src_line[1] - 128;
743 e = (int) src_line[3] - 128;
745 g2 = - 100 * d - 208 * e + 128;
748 c2 = 298 * ((int) src_line[0] - 16);
749 dst_line[x] = 0xff000000
750 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
751 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
752 | cliptobyte((c2 + b2) >> 8); /* blue */
753 /* Scale RGB values to 0..255 range,
754 * then clip them if still not in range (may be negative),
755 * then shift them within DWORD if necessary.
762 struct d3dfmt_convertor_desc
764 enum wined3d_format_id from, to;
765 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
768 static const struct d3dfmt_convertor_desc convertors[] =
770 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
771 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
772 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
773 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
776 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
779 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
780 if(convertors[i].from == from && convertors[i].to == to) {
781 return &convertors[i];
787 /*****************************************************************************
788 * surface_convert_format
790 * Creates a duplicate of a surface in a different format. Is used by Blt to
791 * blit between surfaces with different formats
794 * source: Source surface
795 * fmt: Requested destination format
797 *****************************************************************************/
798 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
800 IWineD3DSurface *ret = NULL;
801 const struct d3dfmt_convertor_desc *conv;
802 WINED3DLOCKED_RECT lock_src, lock_dst;
805 conv = find_convertor(source->resource.format->id, to_fmt);
808 FIXME("Cannot find a conversion function from format %s to %s.\n",
809 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
813 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
814 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
815 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
816 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
817 NULL /* parent */, &wined3d_null_parent_ops, &ret);
819 ERR("Failed to create a destination surface for conversion\n");
823 memset(&lock_src, 0, sizeof(lock_src));
824 memset(&lock_dst, 0, sizeof(lock_dst));
826 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
829 ERR("Failed to lock the source surface.\n");
830 IWineD3DSurface_Release(ret);
833 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
836 ERR("Failed to lock the dest surface\n");
837 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
838 IWineD3DSurface_Release(ret);
842 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
843 source->currentDesc.Width, source->currentDesc.Height);
845 IWineD3DSurface_Unmap(ret);
846 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
848 return (IWineD3DSurfaceImpl *) ret;
851 /*****************************************************************************
854 * Helper function that fills a memory area with a specific color
857 * buf: memory address to start filling at
858 * width, height: Dimensions of the area to fill
859 * bpp: Bit depth of the surface
860 * lPitch: pitch of the surface
861 * color: Color to fill with
863 *****************************************************************************/
865 _Blt_ColorFill(BYTE *buf,
866 int width, int height,
867 int bpp, LONG lPitch,
875 #define COLORFILL_ROW(type) \
877 type *d = (type *) buf; \
878 for (x = 0; x < width; x++) \
879 d[x] = (type) color; \
884 case 1: COLORFILL_ROW(BYTE)
885 case 2: COLORFILL_ROW(WORD)
889 for (x = 0; x < width; x++,d+=3)
891 d[0] = (color ) & 0xFF;
892 d[1] = (color>> 8) & 0xFF;
893 d[2] = (color>>16) & 0xFF;
897 case 4: COLORFILL_ROW(DWORD)
899 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
900 return WINED3DERR_NOTAVAILABLE;
905 /* Now copy first row */
907 for (y = 1; y < height; y++)
910 memcpy(buf, first, width * bpp);
915 /*****************************************************************************
916 * IWineD3DSurface::Blt, SW emulation version
918 * Performs a blit to a surface, with or without a source surface.
919 * This is the main functionality of DirectDraw
922 * DestRect: Destination rectangle to write to
923 * src_surface: Source surface, can be NULL
924 * SrcRect: Source rectangle
925 *****************************************************************************/
926 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
927 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
929 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
930 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
932 HRESULT ret = WINED3D_OK;
933 WINED3DLOCKED_RECT dlock, slock;
934 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
935 const struct wined3d_format *sEntry, *dEntry;
940 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
941 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
942 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
944 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
946 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
947 return WINEDDERR_SURFACEBUSY;
950 /* First check for the validity of source / destination rectangles.
951 * This was verified using a test application + by MSDN. */
957 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
958 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
959 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
960 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
961 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
963 WARN("Application gave us bad source rectangle for Blt.\n");
964 return WINEDDERR_INVALIDRECT;
967 if (!SrcRect->right || !SrcRect->bottom
968 || SrcRect->left == (int)src->currentDesc.Width
969 || SrcRect->top == (int)src->currentDesc.Height)
971 TRACE("Nothing to be done.\n");
982 xsrc.right = src->currentDesc.Width;
983 xsrc.bottom = src->currentDesc.Height;
987 memset(&xsrc, 0, sizeof(xsrc));
992 /* For the Destination rect, it can be out of bounds on the condition
993 * that a clipper is set for the given surface. */
994 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
995 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
996 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
997 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
998 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1000 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1001 return WINEDDERR_INVALIDRECT;
1004 if (DestRect->right <= 0 || DestRect->bottom <= 0
1005 || DestRect->left >= (int)This->currentDesc.Width
1006 || DestRect->top >= (int)This->currentDesc.Height)
1008 TRACE("Nothing to be done.\n");
1018 full_rect.right = This->currentDesc.Width;
1019 full_rect.bottom = This->currentDesc.Height;
1020 IntersectRect(&xdst, &full_rect, DestRect);
1024 BOOL clip_horiz, clip_vert;
1027 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1028 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1030 if (clip_vert || clip_horiz)
1032 /* Now check if this is a special case or not... */
1033 if ((Flags & WINEDDBLT_DDFX)
1034 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1035 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1037 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1045 xsrc.left -= xdst.left;
1048 if (xdst.right > This->currentDesc.Width)
1050 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1051 xdst.right = (int)This->currentDesc.Width;
1059 xsrc.top -= xdst.top;
1062 if (xdst.bottom > This->currentDesc.Height)
1064 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1065 xdst.bottom = (int)This->currentDesc.Height;
1069 /* And check if after clipping something is still to be done... */
1070 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1071 || (xdst.left >= (int)This->currentDesc.Width)
1072 || (xdst.top >= (int)This->currentDesc.Height)
1073 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1074 || (xsrc.left >= (int)src->currentDesc.Width)
1075 || (xsrc.top >= (int)src->currentDesc.Height))
1077 TRACE("Nothing to be done after clipping.\n");
1087 xdst.right = This->currentDesc.Width;
1088 xdst.bottom = This->currentDesc.Height;
1093 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1095 sEntry = This->resource.format;
1100 dEntry = This->resource.format;
1103 if (This->resource.format->id != src->resource.format->id)
1105 src = surface_convert_format(src, dEntry->id);
1108 /* The conv function writes a FIXME */
1109 WARN("Cannot convert source surface format to dest format\n");
1113 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1114 sEntry = src->resource.format;
1121 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1123 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1126 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1128 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1130 if (!DestRect || src == This)
1132 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1137 bpp = This->resource.format->byte_count;
1138 srcheight = xsrc.bottom - xsrc.top;
1139 srcwidth = xsrc.right - xsrc.left;
1140 dstheight = xdst.bottom - xdst.top;
1141 dstwidth = xdst.right - xdst.left;
1142 width = (xdst.right - xdst.left) * bpp;
1144 if (DestRect && src != This)
1147 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1149 if (Flags & WINEDDBLT_WAIT)
1151 Flags &= ~WINEDDBLT_WAIT;
1153 if (Flags & WINEDDBLT_ASYNC)
1155 static BOOL displayed = FALSE;
1157 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1159 Flags &= ~WINEDDBLT_ASYNC;
1161 if (Flags & WINEDDBLT_DONOTWAIT)
1163 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1164 static BOOL displayed = FALSE;
1166 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1168 Flags &= ~WINEDDBLT_DONOTWAIT;
1171 /* First, all the 'source-less' blits */
1172 if (Flags & WINEDDBLT_COLORFILL)
1174 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1175 dlock.Pitch, DDBltFx->u5.dwFillColor);
1176 Flags &= ~WINEDDBLT_COLORFILL;
1179 if (Flags & WINEDDBLT_DEPTHFILL)
1181 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1183 if (Flags & WINEDDBLT_ROP)
1185 /* Catch some degenerate cases here */
1186 switch(DDBltFx->dwROP)
1189 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1191 case 0xAA0029: /* No-op */
1194 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1196 case SRCCOPY: /* well, we do that below ? */
1199 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1202 Flags &= ~WINEDDBLT_ROP;
1204 if (Flags & WINEDDBLT_DDROPS)
1206 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1208 /* Now the 'with source' blits */
1212 int sx, xinc, sy, yinc;
1214 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1217 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1218 && (srcwidth != dstwidth || srcheight != dstheight))
1220 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1221 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1224 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1225 xinc = (srcwidth << 16) / dstwidth;
1226 yinc = (srcheight << 16) / dstheight;
1230 /* No effects, we can cheat here */
1231 if (dstwidth == srcwidth)
1233 if (dstheight == srcheight)
1235 /* No stretching in either direction. This needs to be as
1236 * fast as possible */
1239 /* check for overlapping surfaces */
1240 if (src != This || xdst.top < xsrc.top ||
1241 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1243 /* no overlap, or dst above src, so copy from top downwards */
1244 for (y = 0; y < dstheight; y++)
1246 memcpy(dbuf, sbuf, width);
1247 sbuf += slock.Pitch;
1248 dbuf += dlock.Pitch;
1251 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1253 sbuf += (slock.Pitch*dstheight);
1254 dbuf += (dlock.Pitch*dstheight);
1255 for (y = 0; y < dstheight; y++)
1257 sbuf -= slock.Pitch;
1258 dbuf -= dlock.Pitch;
1259 memcpy(dbuf, sbuf, width);
1262 else /* src and dst overlapping on the same line, use memmove */
1264 for (y = 0; y < dstheight; y++)
1266 memmove(dbuf, sbuf, width);
1267 sbuf += slock.Pitch;
1268 dbuf += dlock.Pitch;
1272 /* Stretching in Y direction only */
1273 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1274 sbuf = sbase + (sy >> 16) * slock.Pitch;
1275 memcpy(dbuf, sbuf, width);
1276 dbuf += dlock.Pitch;
1282 /* Stretching in X direction */
1284 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1286 sbuf = sbase + (sy >> 16) * slock.Pitch;
1288 if ((sy >> 16) == (last_sy >> 16))
1290 /* this sourcerow is the same as last sourcerow -
1291 * copy already stretched row
1293 memcpy(dbuf, dbuf - dlock.Pitch, width);
1297 #define STRETCH_ROW(type) { \
1298 const type *s = (const type *)sbuf; \
1299 type *d = (type *)dbuf; \
1300 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1301 d[x] = s[sx >> 16]; \
1306 case 1: STRETCH_ROW(BYTE)
1307 case 2: STRETCH_ROW(WORD)
1308 case 4: STRETCH_ROW(DWORD)
1313 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1317 s = sbuf+3*(sx>>16);
1318 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1319 d[0] = (pixel )&0xff;
1320 d[1] = (pixel>> 8)&0xff;
1321 d[2] = (pixel>>16)&0xff;
1327 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1328 ret = WINED3DERR_NOTAVAILABLE;
1333 dbuf += dlock.Pitch;
1340 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1341 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1342 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1343 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1345 /* The color keying flags are checked for correctness in ddraw */
1346 if (Flags & WINEDDBLT_KEYSRC)
1348 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1349 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1351 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1353 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1354 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1357 if (Flags & WINEDDBLT_KEYDEST)
1359 /* Destination color keys are taken from the source surface ! */
1360 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1361 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1363 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1365 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1366 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1375 keymask = sEntry->red_mask
1376 | sEntry->green_mask
1377 | sEntry->blue_mask;
1379 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1382 if (Flags & WINEDDBLT_DDFX)
1384 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1387 dTopRight = dbuf+((dstwidth-1)*bpp);
1388 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1389 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1391 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1393 /* I don't think we need to do anything about this flag */
1394 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1396 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1399 dTopRight = dTopLeft;
1402 dBottomRight = dBottomLeft;
1404 dstxinc = dstxinc *-1;
1406 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1409 dTopLeft = dBottomLeft;
1412 dTopRight = dBottomRight;
1414 dstyinc = dstyinc *-1;
1416 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1418 /* I don't think we need to do anything about this flag */
1419 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1421 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1424 dBottomRight = dTopLeft;
1427 dBottomLeft = dTopRight;
1429 dstxinc = dstxinc * -1;
1430 dstyinc = dstyinc * -1;
1432 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1435 dTopLeft = dBottomLeft;
1436 dBottomLeft = dBottomRight;
1437 dBottomRight = dTopRight;
1442 dstxinc = dstxinc * -1;
1444 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1447 dTopLeft = dTopRight;
1448 dTopRight = dBottomRight;
1449 dBottomRight = dBottomLeft;
1454 dstyinc = dstyinc * -1;
1456 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1458 /* I don't think we need to do anything about this flag */
1459 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1462 Flags &= ~(WINEDDBLT_DDFX);
1465 #define COPY_COLORKEY_FX(type) { \
1467 type *d = (type *)dbuf, *dx, tmp; \
1468 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1469 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1471 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1472 tmp = s[sx >> 16]; \
1473 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1474 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1477 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1479 d = (type*)(((LPBYTE)d)+dstyinc); \
1484 case 1: COPY_COLORKEY_FX(BYTE)
1485 case 2: COPY_COLORKEY_FX(WORD)
1486 case 4: COPY_COLORKEY_FX(DWORD)
1490 BYTE *d = dbuf, *dx;
1491 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1493 sbuf = sbase + (sy >> 16) * slock.Pitch;
1495 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1497 DWORD pixel, dpixel = 0;
1498 s = sbuf+3*(sx>>16);
1499 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1500 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1501 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1502 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1504 dx[0] = (pixel )&0xff;
1505 dx[1] = (pixel>> 8)&0xff;
1506 dx[2] = (pixel>>16)&0xff;
1515 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1516 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1517 ret = WINED3DERR_NOTAVAILABLE;
1519 #undef COPY_COLORKEY_FX
1525 if (Flags && FIXME_ON(d3d_surface))
1527 FIXME("\tUnsupported flags: %08x\n", Flags);
1531 IWineD3DSurface_Unmap(iface);
1532 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1533 /* Release the converted surface if any */
1534 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1538 /*****************************************************************************
1539 * IWineD3DSurface::BltFast, SW emulation version
1541 * This is the software implementation of BltFast, as used by GDI surfaces
1542 * and as a fallback for OpenGL surfaces. This code is taken from the old
1543 * DirectDraw code, and was originally written by TransGaming.
1548 * src_surface: Source surface to copy from
1549 * rsrc: Source rectangle
1553 * WINED3D_OK on success
1555 *****************************************************************************/
1556 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1557 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1559 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1560 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1562 int bpp, w, h, x, y;
1563 WINED3DLOCKED_RECT dlock,slock;
1564 HRESULT ret = WINED3D_OK;
1566 RECT lock_src, lock_dst, lock_union;
1569 const struct wined3d_format *sEntry, *dEntry;
1571 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1572 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1574 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1576 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1577 return WINEDDERR_SURFACEBUSY;
1582 WARN("rsrc is NULL!\n");
1585 rsrc2.right = src->currentDesc.Width;
1586 rsrc2.bottom = src->currentDesc.Height;
1590 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1591 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1592 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1593 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1594 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1595 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1597 WARN("Application gave us bad source rectangle for BltFast.\n");
1598 return WINEDDERR_INVALIDRECT;
1601 h = rsrc->bottom - rsrc->top;
1602 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1603 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1604 if (h <= 0) return WINEDDERR_INVALIDRECT;
1606 w = rsrc->right - rsrc->left;
1607 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1608 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1609 if (w <= 0) return WINEDDERR_INVALIDRECT;
1611 /* Now compute the locking rectangle... */
1612 lock_src.left = rsrc->left;
1613 lock_src.top = rsrc->top;
1614 lock_src.right = lock_src.left + w;
1615 lock_src.bottom = lock_src.top + h;
1617 lock_dst.left = dstx;
1618 lock_dst.top = dsty;
1619 lock_dst.right = dstx + w;
1620 lock_dst.bottom = dsty + h;
1622 bpp = This->resource.format->byte_count;
1624 /* We need to lock the surfaces, or we won't get refreshes when done. */
1629 UnionRect(&lock_union, &lock_src, &lock_dst);
1631 /* Lock the union of the two rectangles */
1632 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1633 if (FAILED(ret)) goto error;
1635 pitch = dlock.Pitch;
1636 slock.Pitch = dlock.Pitch;
1638 /* Since slock was originally copied from this surface's description, we can just reuse it */
1639 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1640 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1641 sEntry = src->resource.format;
1646 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1647 if (FAILED(ret)) goto error;
1648 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1649 if (FAILED(ret)) goto error;
1653 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1655 sEntry = src->resource.format;
1656 dEntry = This->resource.format;
1659 /* Handle compressed surfaces first... */
1660 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1662 UINT row_block_count;
1664 TRACE("compressed -> compressed copy\n");
1666 FIXME("trans arg not supported when a compressed surface is involved\n");
1668 FIXME("offset for destination surface is not supported\n");
1669 if (src->resource.format->id != This->resource.format->id)
1671 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1672 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1676 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1677 for (y = 0; y < h; y += dEntry->block_height)
1679 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1680 dbuf += dlock.Pitch;
1681 sbuf += slock.Pitch;
1686 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1688 /* TODO: Use the libtxc_dxtn.so shared library to do
1689 * software decompression
1691 ERR("Software decompression not supported.\n");
1695 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1697 DWORD keylow, keyhigh;
1698 DWORD mask = src->resource.format->red_mask
1699 | src->resource.format->green_mask
1700 | src->resource.format->blue_mask;
1702 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1706 TRACE("Color keyed copy\n");
1707 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1709 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1710 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1714 /* I'm not sure if this is correct */
1715 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1716 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1717 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1720 #define COPYBOX_COLORKEY(type) { \
1721 const type *s = (const type *)sbuf; \
1722 type *d = (type *)dbuf; \
1724 for (y = 0; y < h; y++) { \
1725 for (x = 0; x < w; x++) { \
1727 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1729 s = (const type *)((const BYTE *)s + slock.Pitch); \
1730 d = (type *)((BYTE *)d + dlock.Pitch); \
1736 case 1: COPYBOX_COLORKEY(BYTE)
1737 case 2: COPYBOX_COLORKEY(WORD)
1738 case 4: COPYBOX_COLORKEY(DWORD)
1746 for (y = 0; y < h; y++)
1748 for (x = 0; x < w * 3; x += 3)
1750 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1751 if (tmp < keylow || tmp > keyhigh)
1753 d[x + 0] = s[x + 0];
1754 d[x + 1] = s[x + 1];
1755 d[x + 2] = s[x + 2];
1764 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1765 ret = WINED3DERR_NOTAVAILABLE;
1768 #undef COPYBOX_COLORKEY
1769 TRACE("Copy Done\n");
1773 int width = w * bpp;
1774 INT sbufpitch, dbufpitch;
1776 TRACE("NO color key copy\n");
1777 /* Handle overlapping surfaces */
1780 sbuf += (h - 1) * slock.Pitch;
1781 dbuf += (h - 1) * dlock.Pitch;
1782 sbufpitch = -slock.Pitch;
1783 dbufpitch = -dlock.Pitch;
1787 sbufpitch = slock.Pitch;
1788 dbufpitch = dlock.Pitch;
1790 for (y = 0; y < h; y++)
1792 /* This is pretty easy, a line for line memcpy */
1793 memmove(dbuf, sbuf, width);
1797 TRACE("Copy done\n");
1803 IWineD3DSurface_Unmap(iface);
1807 IWineD3DSurface_Unmap(iface);
1808 IWineD3DSurface_Unmap(src_surface);
1814 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1815 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags)
1817 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1819 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1820 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1822 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1826 pLockedRect->pBits = This->resource.allocatedMemory;
1827 This->lockedRect.left = 0;
1828 This->lockedRect.top = 0;
1829 This->lockedRect.right = This->currentDesc.Width;
1830 This->lockedRect.bottom = This->currentDesc.Height;
1832 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1833 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1834 This->lockedRect.right, This->lockedRect.bottom);
1838 const struct wined3d_format *format = This->resource.format;
1840 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1841 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1843 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1845 /* Compressed textures are block based, so calculate the offset of
1846 * the block that contains the top-left pixel of the locked rectangle. */
1847 pLockedRect->pBits = This->resource.allocatedMemory
1848 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1849 + ((pRect->left / format->block_width) * format->block_byte_count);
1853 pLockedRect->pBits = This->resource.allocatedMemory +
1854 (pLockedRect->Pitch * pRect->top) +
1855 (pRect->left * format->byte_count);
1857 This->lockedRect.left = pRect->left;
1858 This->lockedRect.top = pRect->top;
1859 This->lockedRect.right = pRect->right;
1860 This->lockedRect.bottom = pRect->bottom;
1863 /* No dirtifying is needed for this surface implementation */
1864 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1869 /* TODO: think about moving this down to resource? */
1870 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1872 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1874 /* This should only be called for sysmem textures, it may be a good idea
1875 * to extend this to all pools at some point in the future */
1876 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1878 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1880 return This->resource.allocatedMemory;