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_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
828 ERR("Failed to lock the source surface\n");
829 IWineD3DSurface_Release(ret);
832 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
834 ERR("Failed to lock the dest surface\n");
835 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
836 IWineD3DSurface_Release(ret);
840 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
841 source->currentDesc.Width, source->currentDesc.Height);
843 IWineD3DSurface_UnlockRect(ret);
844 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
846 return (IWineD3DSurfaceImpl *) ret;
849 /*****************************************************************************
852 * Helper function that fills a memory area with a specific color
855 * buf: memory address to start filling at
856 * width, height: Dimensions of the area to fill
857 * bpp: Bit depth of the surface
858 * lPitch: pitch of the surface
859 * color: Color to fill with
861 *****************************************************************************/
863 _Blt_ColorFill(BYTE *buf,
864 int width, int height,
865 int bpp, LONG lPitch,
873 #define COLORFILL_ROW(type) \
875 type *d = (type *) buf; \
876 for (x = 0; x < width; x++) \
877 d[x] = (type) color; \
882 case 1: COLORFILL_ROW(BYTE)
883 case 2: COLORFILL_ROW(WORD)
887 for (x = 0; x < width; x++,d+=3)
889 d[0] = (color ) & 0xFF;
890 d[1] = (color>> 8) & 0xFF;
891 d[2] = (color>>16) & 0xFF;
895 case 4: COLORFILL_ROW(DWORD)
897 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
898 return WINED3DERR_NOTAVAILABLE;
903 /* Now copy first row */
905 for (y = 1; y < height; y++)
908 memcpy(buf, first, width * bpp);
913 /*****************************************************************************
914 * IWineD3DSurface::Blt, SW emulation version
916 * Performs a blit to a surface, with or without a source surface.
917 * This is the main functionality of DirectDraw
920 * DestRect: Destination rectangle to write to
921 * src_surface: Source surface, can be NULL
922 * SrcRect: Source rectangle
923 *****************************************************************************/
924 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
925 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
927 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
928 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
930 HRESULT ret = WINED3D_OK;
931 WINED3DLOCKED_RECT dlock, slock;
932 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
933 const struct wined3d_format *sEntry, *dEntry;
938 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
939 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
940 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
942 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
944 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
945 return WINEDDERR_SURFACEBUSY;
948 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
949 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
950 FIXME("Filters not supported in software blit\n");
953 /* First check for the validity of source / destination rectangles.
954 * This was verified using a test application + by MSDN. */
960 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
961 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
962 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
963 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
964 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
966 WARN("Application gave us bad source rectangle for Blt.\n");
967 return WINEDDERR_INVALIDRECT;
970 if (!SrcRect->right || !SrcRect->bottom
971 || SrcRect->left == (int)src->currentDesc.Width
972 || SrcRect->top == (int)src->currentDesc.Height)
974 TRACE("Nothing to be done.\n");
985 xsrc.right = src->currentDesc.Width;
986 xsrc.bottom = src->currentDesc.Height;
990 memset(&xsrc, 0, sizeof(xsrc));
995 /* For the Destination rect, it can be out of bounds on the condition
996 * that a clipper is set for the given surface. */
997 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
998 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
999 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1000 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1001 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1003 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1004 return WINEDDERR_INVALIDRECT;
1007 if (DestRect->right <= 0 || DestRect->bottom <= 0
1008 || DestRect->left >= (int)This->currentDesc.Width
1009 || DestRect->top >= (int)This->currentDesc.Height)
1011 TRACE("Nothing to be done.\n");
1021 full_rect.right = This->currentDesc.Width;
1022 full_rect.bottom = This->currentDesc.Height;
1023 IntersectRect(&xdst, &full_rect, DestRect);
1027 BOOL clip_horiz, clip_vert;
1030 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1031 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1033 if (clip_vert || clip_horiz)
1035 /* Now check if this is a special case or not... */
1036 if ((Flags & WINEDDBLT_DDFX)
1037 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1038 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1040 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1048 xsrc.left -= xdst.left;
1051 if (xdst.right > This->currentDesc.Width)
1053 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1054 xdst.right = (int)This->currentDesc.Width;
1062 xsrc.top -= xdst.top;
1065 if (xdst.bottom > This->currentDesc.Height)
1067 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1068 xdst.bottom = (int)This->currentDesc.Height;
1072 /* And check if after clipping something is still to be done... */
1073 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1074 || (xdst.left >= (int)This->currentDesc.Width)
1075 || (xdst.top >= (int)This->currentDesc.Height)
1076 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1077 || (xsrc.left >= (int)src->currentDesc.Width)
1078 || (xsrc.top >= (int)src->currentDesc.Height))
1080 TRACE("Nothing to be done after clipping.\n");
1090 xdst.right = This->currentDesc.Width;
1091 xdst.bottom = This->currentDesc.Height;
1096 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1098 sEntry = This->resource.format;
1103 dEntry = This->resource.format;
1106 if (This->resource.format->id != src->resource.format->id)
1108 src = surface_convert_format(src, dEntry->id);
1111 /* The conv function writes a FIXME */
1112 WARN("Cannot convert source surface format to dest format\n");
1116 IWineD3DSurface_LockRect((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1117 sEntry = src->resource.format;
1124 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1126 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1129 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1131 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1133 if (!DestRect || src == This)
1135 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1140 bpp = This->resource.format->byte_count;
1141 srcheight = xsrc.bottom - xsrc.top;
1142 srcwidth = xsrc.right - xsrc.left;
1143 dstheight = xdst.bottom - xdst.top;
1144 dstwidth = xdst.right - xdst.left;
1145 width = (xdst.right - xdst.left) * bpp;
1147 if (DestRect && src != This)
1150 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1152 if (Flags & WINEDDBLT_WAIT)
1154 Flags &= ~WINEDDBLT_WAIT;
1156 if (Flags & WINEDDBLT_ASYNC)
1158 static BOOL displayed = FALSE;
1160 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1162 Flags &= ~WINEDDBLT_ASYNC;
1164 if (Flags & WINEDDBLT_DONOTWAIT)
1166 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1167 static BOOL displayed = FALSE;
1169 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1171 Flags &= ~WINEDDBLT_DONOTWAIT;
1174 /* First, all the 'source-less' blits */
1175 if (Flags & WINEDDBLT_COLORFILL)
1177 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1178 dlock.Pitch, DDBltFx->u5.dwFillColor);
1179 Flags &= ~WINEDDBLT_COLORFILL;
1182 if (Flags & WINEDDBLT_DEPTHFILL)
1184 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1186 if (Flags & WINEDDBLT_ROP)
1188 /* Catch some degenerate cases here */
1189 switch(DDBltFx->dwROP)
1192 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1194 case 0xAA0029: /* No-op */
1197 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1199 case SRCCOPY: /* well, we do that below ? */
1202 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1205 Flags &= ~WINEDDBLT_ROP;
1207 if (Flags & WINEDDBLT_DDROPS)
1209 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1211 /* Now the 'with source' blits */
1215 int sx, xinc, sy, yinc;
1217 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1219 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1220 xinc = (srcwidth << 16) / dstwidth;
1221 yinc = (srcheight << 16) / dstheight;
1225 /* No effects, we can cheat here */
1226 if (dstwidth == srcwidth)
1228 if (dstheight == srcheight)
1230 /* No stretching in either direction. This needs to be as
1231 * fast as possible */
1234 /* check for overlapping surfaces */
1235 if (src != This || xdst.top < xsrc.top ||
1236 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1238 /* no overlap, or dst above src, so copy from top downwards */
1239 for (y = 0; y < dstheight; y++)
1241 memcpy(dbuf, sbuf, width);
1242 sbuf += slock.Pitch;
1243 dbuf += dlock.Pitch;
1246 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1248 sbuf += (slock.Pitch*dstheight);
1249 dbuf += (dlock.Pitch*dstheight);
1250 for (y = 0; y < dstheight; y++)
1252 sbuf -= slock.Pitch;
1253 dbuf -= dlock.Pitch;
1254 memcpy(dbuf, sbuf, width);
1257 else /* src and dst overlapping on the same line, use memmove */
1259 for (y = 0; y < dstheight; y++)
1261 memmove(dbuf, sbuf, width);
1262 sbuf += slock.Pitch;
1263 dbuf += dlock.Pitch;
1267 /* Stretching in Y direction only */
1268 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1269 sbuf = sbase + (sy >> 16) * slock.Pitch;
1270 memcpy(dbuf, sbuf, width);
1271 dbuf += dlock.Pitch;
1277 /* Stretching in X direction */
1279 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1281 sbuf = sbase + (sy >> 16) * slock.Pitch;
1283 if ((sy >> 16) == (last_sy >> 16))
1285 /* this sourcerow is the same as last sourcerow -
1286 * copy already stretched row
1288 memcpy(dbuf, dbuf - dlock.Pitch, width);
1292 #define STRETCH_ROW(type) { \
1293 const type *s = (const type *)sbuf; \
1294 type *d = (type *)dbuf; \
1295 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1296 d[x] = s[sx >> 16]; \
1301 case 1: STRETCH_ROW(BYTE)
1302 case 2: STRETCH_ROW(WORD)
1303 case 4: STRETCH_ROW(DWORD)
1308 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1312 s = sbuf+3*(sx>>16);
1313 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1314 d[0] = (pixel )&0xff;
1315 d[1] = (pixel>> 8)&0xff;
1316 d[2] = (pixel>>16)&0xff;
1322 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1323 ret = WINED3DERR_NOTAVAILABLE;
1328 dbuf += dlock.Pitch;
1335 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1336 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1337 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1338 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1340 /* The color keying flags are checked for correctness in ddraw */
1341 if (Flags & WINEDDBLT_KEYSRC)
1343 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1344 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1346 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1348 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1349 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1352 if (Flags & WINEDDBLT_KEYDEST)
1354 /* Destination color keys are taken from the source surface ! */
1355 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1356 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1358 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1360 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1361 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1370 keymask = sEntry->red_mask
1371 | sEntry->green_mask
1372 | sEntry->blue_mask;
1374 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1377 if (Flags & WINEDDBLT_DDFX)
1379 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1382 dTopRight = dbuf+((dstwidth-1)*bpp);
1383 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1384 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1386 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1388 /* I don't think we need to do anything about this flag */
1389 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1391 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1394 dTopRight = dTopLeft;
1397 dBottomRight = dBottomLeft;
1399 dstxinc = dstxinc *-1;
1401 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1404 dTopLeft = dBottomLeft;
1407 dTopRight = dBottomRight;
1409 dstyinc = dstyinc *-1;
1411 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1413 /* I don't think we need to do anything about this flag */
1414 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1416 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1419 dBottomRight = dTopLeft;
1422 dBottomLeft = dTopRight;
1424 dstxinc = dstxinc * -1;
1425 dstyinc = dstyinc * -1;
1427 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1430 dTopLeft = dBottomLeft;
1431 dBottomLeft = dBottomRight;
1432 dBottomRight = dTopRight;
1437 dstxinc = dstxinc * -1;
1439 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1442 dTopLeft = dTopRight;
1443 dTopRight = dBottomRight;
1444 dBottomRight = dBottomLeft;
1449 dstyinc = dstyinc * -1;
1451 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1453 /* I don't think we need to do anything about this flag */
1454 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1457 Flags &= ~(WINEDDBLT_DDFX);
1460 #define COPY_COLORKEY_FX(type) { \
1462 type *d = (type *)dbuf, *dx, tmp; \
1463 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1464 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1466 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1467 tmp = s[sx >> 16]; \
1468 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1469 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1472 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1474 d = (type*)(((LPBYTE)d)+dstyinc); \
1479 case 1: COPY_COLORKEY_FX(BYTE)
1480 case 2: COPY_COLORKEY_FX(WORD)
1481 case 4: COPY_COLORKEY_FX(DWORD)
1485 BYTE *d = dbuf, *dx;
1486 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1488 sbuf = sbase + (sy >> 16) * slock.Pitch;
1490 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1492 DWORD pixel, dpixel = 0;
1493 s = sbuf+3*(sx>>16);
1494 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1495 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1496 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1497 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1499 dx[0] = (pixel )&0xff;
1500 dx[1] = (pixel>> 8)&0xff;
1501 dx[2] = (pixel>>16)&0xff;
1510 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1511 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1512 ret = WINED3DERR_NOTAVAILABLE;
1514 #undef COPY_COLORKEY_FX
1520 if (Flags && FIXME_ON(d3d_surface))
1522 FIXME("\tUnsupported flags: %08x\n", Flags);
1526 IWineD3DSurface_UnlockRect(iface);
1527 if (src && src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *)src);
1528 /* Release the converted surface if any */
1529 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1533 /*****************************************************************************
1534 * IWineD3DSurface::BltFast, SW emulation version
1536 * This is the software implementation of BltFast, as used by GDI surfaces
1537 * and as a fallback for OpenGL surfaces. This code is taken from the old
1538 * DirectDraw code, and was originally written by TransGaming.
1543 * src_surface: Source surface to copy from
1544 * rsrc: Source rectangle
1548 * WINED3D_OK on success
1550 *****************************************************************************/
1551 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1552 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1554 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1555 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1557 int bpp, w, h, x, y;
1558 WINED3DLOCKED_RECT dlock,slock;
1559 HRESULT ret = WINED3D_OK;
1561 RECT lock_src, lock_dst, lock_union;
1564 const struct wined3d_format *sEntry, *dEntry;
1566 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1567 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1569 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1571 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1572 return WINEDDERR_SURFACEBUSY;
1577 WARN("rsrc is NULL!\n");
1580 rsrc2.right = src->currentDesc.Width;
1581 rsrc2.bottom = src->currentDesc.Height;
1585 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1586 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1587 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1588 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1589 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1590 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1592 WARN("Application gave us bad source rectangle for BltFast.\n");
1593 return WINEDDERR_INVALIDRECT;
1596 h = rsrc->bottom - rsrc->top;
1597 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1598 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1599 if (h <= 0) return WINEDDERR_INVALIDRECT;
1601 w = rsrc->right - rsrc->left;
1602 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1603 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1604 if (w <= 0) return WINEDDERR_INVALIDRECT;
1606 /* Now compute the locking rectangle... */
1607 lock_src.left = rsrc->left;
1608 lock_src.top = rsrc->top;
1609 lock_src.right = lock_src.left + w;
1610 lock_src.bottom = lock_src.top + h;
1612 lock_dst.left = dstx;
1613 lock_dst.top = dsty;
1614 lock_dst.right = dstx + w;
1615 lock_dst.bottom = dsty + h;
1617 bpp = This->resource.format->byte_count;
1619 /* We need to lock the surfaces, or we won't get refreshes when done. */
1624 UnionRect(&lock_union, &lock_src, &lock_dst);
1626 /* Lock the union of the two rectangles */
1627 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1628 if(ret != WINED3D_OK) goto error;
1630 pitch = dlock.Pitch;
1631 slock.Pitch = dlock.Pitch;
1633 /* Since slock was originally copied from this surface's description, we can just reuse it */
1634 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1635 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1636 sEntry = src->resource.format;
1641 ret = IWineD3DSurface_LockRect(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1642 if(ret != WINED3D_OK) goto error;
1643 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1644 if(ret != WINED3D_OK) goto error;
1648 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1650 sEntry = src->resource.format;
1651 dEntry = This->resource.format;
1654 /* Handle compressed surfaces first... */
1655 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1657 UINT row_block_count;
1659 TRACE("compressed -> compressed copy\n");
1661 FIXME("trans arg not supported when a compressed surface is involved\n");
1663 FIXME("offset for destination surface is not supported\n");
1664 if (src->resource.format->id != This->resource.format->id)
1666 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1667 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1671 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1672 for (y = 0; y < h; y += dEntry->block_height)
1674 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1675 dbuf += dlock.Pitch;
1676 sbuf += slock.Pitch;
1681 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1683 /* TODO: Use the libtxc_dxtn.so shared library to do
1684 * software decompression
1686 ERR("Software decompression not supported.\n");
1690 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1692 DWORD keylow, keyhigh;
1693 DWORD mask = src->resource.format->red_mask
1694 | src->resource.format->green_mask
1695 | src->resource.format->blue_mask;
1697 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1701 TRACE("Color keyed copy\n");
1702 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1704 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1705 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1709 /* I'm not sure if this is correct */
1710 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1711 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1712 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1715 #define COPYBOX_COLORKEY(type) { \
1716 const type *s = (const type *)sbuf; \
1717 type *d = (type *)dbuf; \
1719 for (y = 0; y < h; y++) { \
1720 for (x = 0; x < w; x++) { \
1722 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1724 s = (const type *)((const BYTE *)s + slock.Pitch); \
1725 d = (type *)((BYTE *)d + dlock.Pitch); \
1731 case 1: COPYBOX_COLORKEY(BYTE)
1732 case 2: COPYBOX_COLORKEY(WORD)
1733 case 4: COPYBOX_COLORKEY(DWORD)
1741 for (y = 0; y < h; y++)
1743 for (x = 0; x < w * 3; x += 3)
1745 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1746 if (tmp < keylow || tmp > keyhigh)
1748 d[x + 0] = s[x + 0];
1749 d[x + 1] = s[x + 1];
1750 d[x + 2] = s[x + 2];
1759 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1760 ret = WINED3DERR_NOTAVAILABLE;
1763 #undef COPYBOX_COLORKEY
1764 TRACE("Copy Done\n");
1768 int width = w * bpp;
1769 INT sbufpitch, dbufpitch;
1771 TRACE("NO color key copy\n");
1772 /* Handle overlapping surfaces */
1775 sbuf += (h - 1) * slock.Pitch;
1776 dbuf += (h - 1) * dlock.Pitch;
1777 sbufpitch = -slock.Pitch;
1778 dbufpitch = -dlock.Pitch;
1782 sbufpitch = slock.Pitch;
1783 dbufpitch = dlock.Pitch;
1785 for (y = 0; y < h; y++)
1787 /* This is pretty easy, a line for line memcpy */
1788 memmove(dbuf, sbuf, width);
1792 TRACE("Copy done\n");
1798 IWineD3DSurface_UnlockRect(iface);
1802 IWineD3DSurface_UnlockRect(iface);
1803 IWineD3DSurface_UnlockRect(src_surface);
1809 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1811 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1813 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1814 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1816 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1820 pLockedRect->pBits = This->resource.allocatedMemory;
1821 This->lockedRect.left = 0;
1822 This->lockedRect.top = 0;
1823 This->lockedRect.right = This->currentDesc.Width;
1824 This->lockedRect.bottom = This->currentDesc.Height;
1826 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1827 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1828 This->lockedRect.right, This->lockedRect.bottom);
1832 const struct wined3d_format *format = This->resource.format;
1834 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1835 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1837 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1839 /* Compressed textures are block based, so calculate the offset of
1840 * the block that contains the top-left pixel of the locked rectangle. */
1841 pLockedRect->pBits = This->resource.allocatedMemory
1842 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1843 + ((pRect->left / format->block_width) * format->block_byte_count);
1847 pLockedRect->pBits = This->resource.allocatedMemory +
1848 (pLockedRect->Pitch * pRect->top) +
1849 (pRect->left * format->byte_count);
1851 This->lockedRect.left = pRect->left;
1852 This->lockedRect.top = pRect->top;
1853 This->lockedRect.right = pRect->right;
1854 This->lockedRect.bottom = pRect->bottom;
1857 /* No dirtifying is needed for this surface implementation */
1858 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1863 /* TODO: think about moving this down to resource? */
1864 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1866 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1868 /* This should only be called for sysmem textures, it may be a good idea
1869 * to extend this to all pools at some point in the future */
1870 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1872 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1874 return This->resource.allocatedMemory;