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 HRESULT 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;
168 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
170 TRACE("iface %p, flags %#x.\n", iface, Flags);
174 case WINEDDGBS_CANBLT:
175 case WINEDDGBS_ISBLTDONE:
179 return WINED3DERR_INVALIDCALL;
183 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
184 /* XXX: DDERR_INVALIDSURFACETYPE */
186 TRACE("(%p)->(%08x)\n",iface,Flags);
188 case WINEDDGFS_CANFLIP:
189 case WINEDDGFS_ISFLIPDONE:
193 return WINED3DERR_INVALIDCALL;
197 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
198 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
199 TRACE("(%p)\n", This);
201 /* D3D8 and 9 loose full devices, ddraw only surfaces */
202 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
205 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
206 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
207 TRACE("(%p)\n", This);
209 /* So far we don't lose anything :) */
210 This->Flags &= ~SFLAG_LOST;
214 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
215 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
216 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
217 TRACE("(%p)->(%p)\n", This, Pal);
219 if(This->palette == PalImpl) {
220 TRACE("Nop palette change\n");
224 if(This->palette != NULL)
225 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
226 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
228 This->palette = PalImpl;
230 if(PalImpl != NULL) {
231 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
232 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
235 return IWineD3DSurface_RealizePalette(iface);
237 else return WINED3D_OK;
240 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
242 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
243 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
245 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
246 FIXME(" colorkey value not supported (%08x) !\n", Flags);
247 return WINED3DERR_INVALIDCALL;
250 /* Dirtify the surface, but only if a key was changed */
252 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
253 case WINEDDCKEY_DESTBLT:
254 This->DestBltCKey = *CKey;
255 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
258 case WINEDDCKEY_DESTOVERLAY:
259 This->DestOverlayCKey = *CKey;
260 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
263 case WINEDDCKEY_SRCOVERLAY:
264 This->SrcOverlayCKey = *CKey;
265 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
268 case WINEDDCKEY_SRCBLT:
269 This->SrcBltCKey = *CKey;
270 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
275 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
276 case WINEDDCKEY_DESTBLT:
277 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
280 case WINEDDCKEY_DESTOVERLAY:
281 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
284 case WINEDDCKEY_SRCOVERLAY:
285 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
288 case WINEDDCKEY_SRCBLT:
289 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
297 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
298 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
299 TRACE("(%p)->(%p)\n", This, Pal);
301 *Pal = (IWineD3DPalette *) This->palette;
305 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
307 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
308 const struct wined3d_format *format = This->resource.format;
310 TRACE("(%p)\n", This);
312 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
314 /* Since compressed formats are block based, pitch means the amount of
315 * bytes to the next row of block rather than the next row of pixels. */
316 UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
317 ret = row_block_count * format->block_byte_count;
321 unsigned char alignment = This->resource.device->surface_alignment;
322 ret = This->resource.format->byte_count * This->currentDesc.Width; /* Bytes / row */
323 ret = (ret + alignment - 1) & ~(alignment - 1);
325 TRACE("(%p) Returning %d\n", This, ret);
329 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
330 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
333 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
335 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
337 TRACE("(%p): Not an overlay surface\n", This);
338 return WINEDDERR_NOTAOVERLAYSURFACE;
341 w = This->overlay_destrect.right - This->overlay_destrect.left;
342 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
343 This->overlay_destrect.left = X;
344 This->overlay_destrect.top = Y;
345 This->overlay_destrect.right = X + w;
346 This->overlay_destrect.bottom = Y + h;
348 IWineD3DSurface_DrawOverlay(iface);
353 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
354 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
357 TRACE("(%p)->(%p,%p)\n", This, X, Y);
359 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
361 TRACE("(%p): Not an overlay surface\n", This);
362 return WINEDDERR_NOTAOVERLAYSURFACE;
364 if(This->overlay_dest == NULL) {
366 hr = WINEDDERR_OVERLAYNOTVISIBLE;
368 *X = This->overlay_destrect.left;
369 *Y = This->overlay_destrect.top;
373 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
377 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
378 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
380 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
382 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
384 TRACE("(%p): Not an overlay surface\n", This);
385 return WINEDDERR_NOTAOVERLAYSURFACE;
391 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
392 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
394 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
395 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
396 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
398 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
400 WARN("(%p): Not an overlay surface\n", This);
401 return WINEDDERR_NOTAOVERLAYSURFACE;
402 } else if(!DstSurface) {
403 WARN("(%p): Dest surface is NULL\n", This);
404 return WINED3DERR_INVALIDCALL;
408 This->overlay_srcrect = *SrcRect;
410 This->overlay_srcrect.left = 0;
411 This->overlay_srcrect.top = 0;
412 This->overlay_srcrect.right = This->currentDesc.Width;
413 This->overlay_srcrect.bottom = This->currentDesc.Height;
417 This->overlay_destrect = *DstRect;
419 This->overlay_destrect.left = 0;
420 This->overlay_destrect.top = 0;
421 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
422 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
425 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
426 list_remove(&This->overlay_entry);
429 if(Flags & WINEDDOVER_SHOW) {
430 if(This->overlay_dest != Dst) {
431 This->overlay_dest = Dst;
432 list_add_tail(&Dst->overlays, &This->overlay_entry);
434 } else if(Flags & WINEDDOVER_HIDE) {
435 /* tests show that the rectangles are erased on hide */
436 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
437 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
438 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
439 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
440 This->overlay_dest = NULL;
443 IWineD3DSurface_DrawOverlay(iface);
448 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
450 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
451 TRACE("(%p)->(%p)\n", This, clipper);
453 This->clipper = clipper;
457 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
459 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
460 TRACE("(%p)->(%p)\n", This, clipper);
462 *clipper = This->clipper;
464 IWineD3DClipper_AddRef(*clipper);
469 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
471 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
472 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
474 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
476 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
477 return WINED3DERR_INVALIDCALL;
480 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
482 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
483 This->pow2Width, This->pow2Height);
485 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
487 This->resource.format = format;
489 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
494 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
496 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
497 const struct wined3d_format *format = This->resource.format;
505 if (!(format->Flags & WINED3DFMT_FLAG_GETDC))
507 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
508 return WINED3DERR_INVALIDCALL;
511 switch (format->byte_count)
515 /* Allocate extra space to store the RGB bit masks. */
516 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
520 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
524 /* Allocate extra space for a palette. */
525 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
526 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
531 return E_OUTOFMEMORY;
533 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
534 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
535 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
536 * add an extra line to the dib section
538 GetSystemInfo(&sysInfo);
539 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
541 TRACE("Adding an extra line to the dib section\n");
544 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
545 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
546 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
547 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
548 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
549 b_info->bmiHeader.biPlanes = 1;
550 b_info->bmiHeader.biBitCount = format->byte_count * 8;
552 b_info->bmiHeader.biXPelsPerMeter = 0;
553 b_info->bmiHeader.biYPelsPerMeter = 0;
554 b_info->bmiHeader.biClrUsed = 0;
555 b_info->bmiHeader.biClrImportant = 0;
557 /* Get the bit masks */
558 masks = (DWORD *)b_info->bmiColors;
559 switch (This->resource.format->id)
561 case WINED3DFMT_B8G8R8_UNORM:
562 usage = DIB_RGB_COLORS;
563 b_info->bmiHeader.biCompression = BI_RGB;
566 case WINED3DFMT_B5G5R5X1_UNORM:
567 case WINED3DFMT_B5G5R5A1_UNORM:
568 case WINED3DFMT_B4G4R4A4_UNORM:
569 case WINED3DFMT_B4G4R4X4_UNORM:
570 case WINED3DFMT_B2G3R3_UNORM:
571 case WINED3DFMT_B2G3R3A8_UNORM:
572 case WINED3DFMT_R10G10B10A2_UNORM:
573 case WINED3DFMT_R8G8B8A8_UNORM:
574 case WINED3DFMT_R8G8B8X8_UNORM:
575 case WINED3DFMT_B10G10R10A2_UNORM:
576 case WINED3DFMT_B5G6R5_UNORM:
577 case WINED3DFMT_R16G16B16A16_UNORM:
579 b_info->bmiHeader.biCompression = BI_BITFIELDS;
580 masks[0] = format->red_mask;
581 masks[1] = format->green_mask;
582 masks[2] = format->blue_mask;
586 /* Don't know palette */
587 b_info->bmiHeader.biCompression = BI_RGB;
594 HeapFree(GetProcessHeap(), 0, b_info);
595 return HRESULT_FROM_WIN32(GetLastError());
598 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);
599 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
602 if (!This->dib.DIBsection) {
603 ERR("CreateDIBSection failed!\n");
604 HeapFree(GetProcessHeap(), 0, b_info);
605 return HRESULT_FROM_WIN32(GetLastError());
608 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
609 /* copy the existing surface to the dib section */
610 if(This->resource.allocatedMemory) {
611 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
613 /* This is to make LockRect read the gl Texture although memory is allocated */
614 This->Flags &= ~SFLAG_INSYSMEM;
616 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
618 HeapFree(GetProcessHeap(), 0, b_info);
620 /* Now allocate a HDC */
621 This->hDC = CreateCompatibleDC(0);
622 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
623 TRACE("using wined3d palette %p\n", This->palette);
624 SelectPalette(This->hDC,
625 This->palette ? This->palette->hpal : 0,
628 This->Flags |= SFLAG_DIBSECTION;
630 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
631 This->resource.heapMemory = NULL;
636 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
637 unsigned int w, unsigned int h)
641 unsigned short *dst_s;
643 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
644 for(y = 0; y < h; y++) {
645 src_f = (const float *)(src + y * pitch_in);
646 dst_s = (unsigned short *) (dst + y * pitch_out);
647 for(x = 0; x < w; x++) {
648 dst_s[x] = float_32_to_16(src_f + x);
653 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
654 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
656 static const unsigned char convert_5to8[] =
658 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
659 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
660 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
661 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
663 static const unsigned char convert_6to8[] =
665 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
666 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
667 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
668 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
669 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
670 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
671 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
672 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
676 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
678 for (y = 0; y < h; ++y)
680 const WORD *src_line = (const WORD *)(src + y * pitch_in);
681 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
682 for (x = 0; x < w; ++x)
684 WORD pixel = src_line[x];
685 dst_line[x] = 0xff000000
686 | convert_5to8[(pixel & 0xf800) >> 11] << 16
687 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
688 | convert_5to8[(pixel & 0x001f)];
693 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
694 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
698 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
700 for (y = 0; y < h; ++y)
702 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
703 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
705 for (x = 0; x < w; ++x)
707 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
712 static inline BYTE cliptobyte(int x)
714 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
717 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
718 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
721 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
723 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
725 for (y = 0; y < h; ++y)
727 const BYTE *src_line = src + y * pitch_in;
728 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
729 for (x = 0; x < w; ++x)
731 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
732 * C = Y - 16; D = U - 128; E = V - 128;
733 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
734 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
735 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
736 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
737 * U and V are shared between the pixels.
739 if (!(x & 1)) /* for every even pixel, read new U and V */
741 d = (int) src_line[1] - 128;
742 e = (int) src_line[3] - 128;
744 g2 = - 100 * d - 208 * e + 128;
747 c2 = 298 * ((int) src_line[0] - 16);
748 dst_line[x] = 0xff000000
749 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
750 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
751 | cliptobyte((c2 + b2) >> 8); /* blue */
752 /* Scale RGB values to 0..255 range,
753 * then clip them if still not in range (may be negative),
754 * then shift them within DWORD if necessary.
761 struct d3dfmt_convertor_desc
763 enum wined3d_format_id from, to;
764 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
767 static const struct d3dfmt_convertor_desc convertors[] =
769 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
770 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
771 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
772 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
775 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
778 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
779 if(convertors[i].from == from && convertors[i].to == to) {
780 return &convertors[i];
786 /*****************************************************************************
787 * surface_convert_format
789 * Creates a duplicate of a surface in a different format. Is used by Blt to
790 * blit between surfaces with different formats
793 * source: Source surface
794 * fmt: Requested destination format
796 *****************************************************************************/
797 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
799 IWineD3DSurface *ret = NULL;
800 const struct d3dfmt_convertor_desc *conv;
801 WINED3DLOCKED_RECT lock_src, lock_dst;
804 conv = find_convertor(source->resource.format->id, to_fmt);
807 FIXME("Cannot find a conversion function from format %s to %s.\n",
808 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
812 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
813 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
814 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
815 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
816 NULL /* parent */, &wined3d_null_parent_ops, &ret);
818 ERR("Failed to create a destination surface for conversion\n");
822 memset(&lock_src, 0, sizeof(lock_src));
823 memset(&lock_dst, 0, sizeof(lock_dst));
825 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
827 ERR("Failed to lock the source surface\n");
828 IWineD3DSurface_Release(ret);
831 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
833 ERR("Failed to lock the dest surface\n");
834 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
835 IWineD3DSurface_Release(ret);
839 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
840 source->currentDesc.Width, source->currentDesc.Height);
842 IWineD3DSurface_UnlockRect(ret);
843 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
845 return (IWineD3DSurfaceImpl *) ret;
848 /*****************************************************************************
851 * Helper function that fills a memory area with a specific color
854 * buf: memory address to start filling at
855 * width, height: Dimensions of the area to fill
856 * bpp: Bit depth of the surface
857 * lPitch: pitch of the surface
858 * color: Color to fill with
860 *****************************************************************************/
862 _Blt_ColorFill(BYTE *buf,
863 int width, int height,
864 int bpp, LONG lPitch,
872 #define COLORFILL_ROW(type) \
874 type *d = (type *) buf; \
875 for (x = 0; x < width; x++) \
876 d[x] = (type) color; \
881 case 1: COLORFILL_ROW(BYTE)
882 case 2: COLORFILL_ROW(WORD)
886 for (x = 0; x < width; x++,d+=3)
888 d[0] = (color ) & 0xFF;
889 d[1] = (color>> 8) & 0xFF;
890 d[2] = (color>>16) & 0xFF;
894 case 4: COLORFILL_ROW(DWORD)
896 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
897 return WINED3DERR_NOTAVAILABLE;
902 /* Now copy first row */
904 for (y = 1; y < height; y++)
907 memcpy(buf, first, width * bpp);
912 /*****************************************************************************
913 * IWineD3DSurface::Blt, SW emulation version
915 * Performs a blit to a surface, with or without a source surface.
916 * This is the main functionality of DirectDraw
919 * DestRect: Destination rectangle to write to
920 * src_surface: Source surface, can be NULL
921 * SrcRect: Source rectangle
922 *****************************************************************************/
923 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
924 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
926 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
927 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
929 HRESULT ret = WINED3D_OK;
930 WINED3DLOCKED_RECT dlock, slock;
931 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
932 const struct wined3d_format *sEntry, *dEntry;
937 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
938 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
939 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
941 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
943 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
944 return WINEDDERR_SURFACEBUSY;
947 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
948 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
949 FIXME("Filters not supported in software blit\n");
952 /* First check for the validity of source / destination rectangles.
953 * This was verified using a test application + by MSDN. */
959 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
960 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
961 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
962 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
963 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
965 WARN("Application gave us bad source rectangle for Blt.\n");
966 return WINEDDERR_INVALIDRECT;
969 if (!SrcRect->right || !SrcRect->bottom
970 || SrcRect->left == (int)src->currentDesc.Width
971 || SrcRect->top == (int)src->currentDesc.Height)
973 TRACE("Nothing to be done.\n");
984 xsrc.right = src->currentDesc.Width;
985 xsrc.bottom = src->currentDesc.Height;
989 memset(&xsrc, 0, sizeof(xsrc));
994 /* For the Destination rect, it can be out of bounds on the condition
995 * that a clipper is set for the given surface. */
996 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
997 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
998 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
999 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1000 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1002 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1003 return WINEDDERR_INVALIDRECT;
1006 if (DestRect->right <= 0 || DestRect->bottom <= 0
1007 || DestRect->left >= (int)This->currentDesc.Width
1008 || DestRect->top >= (int)This->currentDesc.Height)
1010 TRACE("Nothing to be done.\n");
1020 full_rect.right = This->currentDesc.Width;
1021 full_rect.bottom = This->currentDesc.Height;
1022 IntersectRect(&xdst, &full_rect, DestRect);
1026 BOOL clip_horiz, clip_vert;
1029 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1030 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1032 if (clip_vert || clip_horiz)
1034 /* Now check if this is a special case or not... */
1035 if ((Flags & WINEDDBLT_DDFX)
1036 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1037 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1039 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1047 xsrc.left -= xdst.left;
1050 if (xdst.right > This->currentDesc.Width)
1052 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1053 xdst.right = (int)This->currentDesc.Width;
1061 xsrc.top -= xdst.top;
1064 if (xdst.bottom > This->currentDesc.Height)
1066 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1067 xdst.bottom = (int)This->currentDesc.Height;
1071 /* And check if after clipping something is still to be done... */
1072 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1073 || (xdst.left >= (int)This->currentDesc.Width)
1074 || (xdst.top >= (int)This->currentDesc.Height)
1075 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1076 || (xsrc.left >= (int)src->currentDesc.Width)
1077 || (xsrc.top >= (int)src->currentDesc.Height))
1079 TRACE("Nothing to be done after clipping.\n");
1089 xdst.right = This->currentDesc.Width;
1090 xdst.bottom = This->currentDesc.Height;
1095 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1097 sEntry = This->resource.format;
1102 dEntry = This->resource.format;
1105 if (This->resource.format->id != src->resource.format->id)
1107 src = surface_convert_format(src, dEntry->id);
1110 /* The conv function writes a FIXME */
1111 WARN("Cannot convert source surface format to dest format\n");
1115 IWineD3DSurface_LockRect((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1116 sEntry = src->resource.format;
1123 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1125 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1128 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1130 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1132 if (!DestRect || src == This)
1134 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1139 bpp = This->resource.format->byte_count;
1140 srcheight = xsrc.bottom - xsrc.top;
1141 srcwidth = xsrc.right - xsrc.left;
1142 dstheight = xdst.bottom - xdst.top;
1143 dstwidth = xdst.right - xdst.left;
1144 width = (xdst.right - xdst.left) * bpp;
1146 if (DestRect && src != This)
1149 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1151 if (Flags & WINEDDBLT_WAIT)
1153 Flags &= ~WINEDDBLT_WAIT;
1155 if (Flags & WINEDDBLT_ASYNC)
1157 static BOOL displayed = FALSE;
1159 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1161 Flags &= ~WINEDDBLT_ASYNC;
1163 if (Flags & WINEDDBLT_DONOTWAIT)
1165 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1166 static BOOL displayed = FALSE;
1168 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1170 Flags &= ~WINEDDBLT_DONOTWAIT;
1173 /* First, all the 'source-less' blits */
1174 if (Flags & WINEDDBLT_COLORFILL)
1176 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1177 dlock.Pitch, DDBltFx->u5.dwFillColor);
1178 Flags &= ~WINEDDBLT_COLORFILL;
1181 if (Flags & WINEDDBLT_DEPTHFILL)
1183 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1185 if (Flags & WINEDDBLT_ROP)
1187 /* Catch some degenerate cases here */
1188 switch(DDBltFx->dwROP)
1191 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1193 case 0xAA0029: /* No-op */
1196 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1198 case SRCCOPY: /* well, we do that below ? */
1201 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1204 Flags &= ~WINEDDBLT_ROP;
1206 if (Flags & WINEDDBLT_DDROPS)
1208 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1210 /* Now the 'with source' blits */
1214 int sx, xinc, sy, yinc;
1216 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1218 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1219 xinc = (srcwidth << 16) / dstwidth;
1220 yinc = (srcheight << 16) / dstheight;
1224 /* No effects, we can cheat here */
1225 if (dstwidth == srcwidth)
1227 if (dstheight == srcheight)
1229 /* No stretching in either direction. This needs to be as
1230 * fast as possible */
1233 /* check for overlapping surfaces */
1234 if (src != This || xdst.top < xsrc.top ||
1235 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1237 /* no overlap, or dst above src, so copy from top downwards */
1238 for (y = 0; y < dstheight; y++)
1240 memcpy(dbuf, sbuf, width);
1241 sbuf += slock.Pitch;
1242 dbuf += dlock.Pitch;
1245 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1247 sbuf += (slock.Pitch*dstheight);
1248 dbuf += (dlock.Pitch*dstheight);
1249 for (y = 0; y < dstheight; y++)
1251 sbuf -= slock.Pitch;
1252 dbuf -= dlock.Pitch;
1253 memcpy(dbuf, sbuf, width);
1256 else /* src and dst overlapping on the same line, use memmove */
1258 for (y = 0; y < dstheight; y++)
1260 memmove(dbuf, sbuf, width);
1261 sbuf += slock.Pitch;
1262 dbuf += dlock.Pitch;
1266 /* Stretching in Y direction only */
1267 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1268 sbuf = sbase + (sy >> 16) * slock.Pitch;
1269 memcpy(dbuf, sbuf, width);
1270 dbuf += dlock.Pitch;
1276 /* Stretching in X direction */
1278 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1280 sbuf = sbase + (sy >> 16) * slock.Pitch;
1282 if ((sy >> 16) == (last_sy >> 16))
1284 /* this sourcerow is the same as last sourcerow -
1285 * copy already stretched row
1287 memcpy(dbuf, dbuf - dlock.Pitch, width);
1291 #define STRETCH_ROW(type) { \
1292 const type *s = (const type *)sbuf; \
1293 type *d = (type *)dbuf; \
1294 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1295 d[x] = s[sx >> 16]; \
1300 case 1: STRETCH_ROW(BYTE)
1301 case 2: STRETCH_ROW(WORD)
1302 case 4: STRETCH_ROW(DWORD)
1307 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1311 s = sbuf+3*(sx>>16);
1312 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1313 d[0] = (pixel )&0xff;
1314 d[1] = (pixel>> 8)&0xff;
1315 d[2] = (pixel>>16)&0xff;
1321 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1322 ret = WINED3DERR_NOTAVAILABLE;
1327 dbuf += dlock.Pitch;
1334 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1335 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1336 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1337 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1339 /* The color keying flags are checked for correctness in ddraw */
1340 if (Flags & WINEDDBLT_KEYSRC)
1342 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1343 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1345 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1347 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1348 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1351 if (Flags & WINEDDBLT_KEYDEST)
1353 /* Destination color keys are taken from the source surface ! */
1354 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1355 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1357 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1359 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1360 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1369 keymask = sEntry->red_mask
1370 | sEntry->green_mask
1371 | sEntry->blue_mask;
1373 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1376 if (Flags & WINEDDBLT_DDFX)
1378 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1381 dTopRight = dbuf+((dstwidth-1)*bpp);
1382 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1383 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1385 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1387 /* I don't think we need to do anything about this flag */
1388 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1390 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1393 dTopRight = dTopLeft;
1396 dBottomRight = dBottomLeft;
1398 dstxinc = dstxinc *-1;
1400 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1403 dTopLeft = dBottomLeft;
1406 dTopRight = dBottomRight;
1408 dstyinc = dstyinc *-1;
1410 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1412 /* I don't think we need to do anything about this flag */
1413 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1415 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1418 dBottomRight = dTopLeft;
1421 dBottomLeft = dTopRight;
1423 dstxinc = dstxinc * -1;
1424 dstyinc = dstyinc * -1;
1426 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1429 dTopLeft = dBottomLeft;
1430 dBottomLeft = dBottomRight;
1431 dBottomRight = dTopRight;
1436 dstxinc = dstxinc * -1;
1438 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1441 dTopLeft = dTopRight;
1442 dTopRight = dBottomRight;
1443 dBottomRight = dBottomLeft;
1448 dstyinc = dstyinc * -1;
1450 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1452 /* I don't think we need to do anything about this flag */
1453 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1456 Flags &= ~(WINEDDBLT_DDFX);
1459 #define COPY_COLORKEY_FX(type) { \
1461 type *d = (type *)dbuf, *dx, tmp; \
1462 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1463 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1465 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1466 tmp = s[sx >> 16]; \
1467 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1468 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1471 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1473 d = (type*)(((LPBYTE)d)+dstyinc); \
1478 case 1: COPY_COLORKEY_FX(BYTE)
1479 case 2: COPY_COLORKEY_FX(WORD)
1480 case 4: COPY_COLORKEY_FX(DWORD)
1484 BYTE *d = dbuf, *dx;
1485 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1487 sbuf = sbase + (sy >> 16) * slock.Pitch;
1489 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1491 DWORD pixel, dpixel = 0;
1492 s = sbuf+3*(sx>>16);
1493 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1494 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1495 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1496 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1498 dx[0] = (pixel )&0xff;
1499 dx[1] = (pixel>> 8)&0xff;
1500 dx[2] = (pixel>>16)&0xff;
1509 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1510 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1511 ret = WINED3DERR_NOTAVAILABLE;
1513 #undef COPY_COLORKEY_FX
1519 if (Flags && FIXME_ON(d3d_surface))
1521 FIXME("\tUnsupported flags: %08x\n", Flags);
1525 IWineD3DSurface_UnlockRect(iface);
1526 if (src && src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *)src);
1527 /* Release the converted surface if any */
1528 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1532 /*****************************************************************************
1533 * IWineD3DSurface::BltFast, SW emulation version
1535 * This is the software implementation of BltFast, as used by GDI surfaces
1536 * and as a fallback for OpenGL surfaces. This code is taken from the old
1537 * DirectDraw code, and was originally written by TransGaming.
1542 * src_surface: Source surface to copy from
1543 * rsrc: Source rectangle
1547 * WINED3D_OK on success
1549 *****************************************************************************/
1550 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1551 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1553 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1554 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1556 int bpp, w, h, x, y;
1557 WINED3DLOCKED_RECT dlock,slock;
1558 HRESULT ret = WINED3D_OK;
1560 RECT lock_src, lock_dst, lock_union;
1563 const struct wined3d_format *sEntry, *dEntry;
1565 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1566 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1568 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1570 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1571 return WINEDDERR_SURFACEBUSY;
1576 WARN("rsrc is NULL!\n");
1579 rsrc2.right = src->currentDesc.Width;
1580 rsrc2.bottom = src->currentDesc.Height;
1584 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1585 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1586 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1587 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1588 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1589 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1591 WARN("Application gave us bad source rectangle for BltFast.\n");
1592 return WINEDDERR_INVALIDRECT;
1595 h = rsrc->bottom - rsrc->top;
1596 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1597 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1598 if (h <= 0) return WINEDDERR_INVALIDRECT;
1600 w = rsrc->right - rsrc->left;
1601 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1602 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1603 if (w <= 0) return WINEDDERR_INVALIDRECT;
1605 /* Now compute the locking rectangle... */
1606 lock_src.left = rsrc->left;
1607 lock_src.top = rsrc->top;
1608 lock_src.right = lock_src.left + w;
1609 lock_src.bottom = lock_src.top + h;
1611 lock_dst.left = dstx;
1612 lock_dst.top = dsty;
1613 lock_dst.right = dstx + w;
1614 lock_dst.bottom = dsty + h;
1616 bpp = This->resource.format->byte_count;
1618 /* We need to lock the surfaces, or we won't get refreshes when done. */
1623 UnionRect(&lock_union, &lock_src, &lock_dst);
1625 /* Lock the union of the two rectangles */
1626 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1627 if(ret != WINED3D_OK) goto error;
1629 pitch = dlock.Pitch;
1630 slock.Pitch = dlock.Pitch;
1632 /* Since slock was originally copied from this surface's description, we can just reuse it */
1633 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1634 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1635 sEntry = src->resource.format;
1640 ret = IWineD3DSurface_LockRect(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1641 if(ret != WINED3D_OK) goto error;
1642 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1643 if(ret != WINED3D_OK) goto error;
1647 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1649 sEntry = src->resource.format;
1650 dEntry = This->resource.format;
1653 /* Handle compressed surfaces first... */
1654 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1656 UINT row_block_count;
1658 TRACE("compressed -> compressed copy\n");
1660 FIXME("trans arg not supported when a compressed surface is involved\n");
1662 FIXME("offset for destination surface is not supported\n");
1663 if (src->resource.format->id != This->resource.format->id)
1665 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1666 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1670 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1671 for (y = 0; y < h; y += dEntry->block_height)
1673 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1674 dbuf += dlock.Pitch;
1675 sbuf += slock.Pitch;
1680 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1682 /* TODO: Use the libtxc_dxtn.so shared library to do
1683 * software decompression
1685 ERR("Software decompression not supported.\n");
1689 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1691 DWORD keylow, keyhigh;
1692 DWORD mask = src->resource.format->red_mask
1693 | src->resource.format->green_mask
1694 | src->resource.format->blue_mask;
1696 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1700 TRACE("Color keyed copy\n");
1701 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1703 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1704 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1708 /* I'm not sure if this is correct */
1709 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1710 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1711 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1714 #define COPYBOX_COLORKEY(type) { \
1715 const type *s = (const type *)sbuf; \
1716 type *d = (type *)dbuf; \
1718 for (y = 0; y < h; y++) { \
1719 for (x = 0; x < w; x++) { \
1721 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1723 s = (const type *)((const BYTE *)s + slock.Pitch); \
1724 d = (type *)((BYTE *)d + dlock.Pitch); \
1730 case 1: COPYBOX_COLORKEY(BYTE)
1731 case 2: COPYBOX_COLORKEY(WORD)
1732 case 4: COPYBOX_COLORKEY(DWORD)
1740 for (y = 0; y < h; y++)
1742 for (x = 0; x < w * 3; x += 3)
1744 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1745 if (tmp < keylow || tmp > keyhigh)
1747 d[x + 0] = s[x + 0];
1748 d[x + 1] = s[x + 1];
1749 d[x + 2] = s[x + 2];
1758 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1759 ret = WINED3DERR_NOTAVAILABLE;
1762 #undef COPYBOX_COLORKEY
1763 TRACE("Copy Done\n");
1767 int width = w * bpp;
1768 INT sbufpitch, dbufpitch;
1770 TRACE("NO color key copy\n");
1771 /* Handle overlapping surfaces */
1774 sbuf += (h - 1) * slock.Pitch;
1775 dbuf += (h - 1) * dlock.Pitch;
1776 sbufpitch = -slock.Pitch;
1777 dbufpitch = -dlock.Pitch;
1781 sbufpitch = slock.Pitch;
1782 dbufpitch = dlock.Pitch;
1784 for (y = 0; y < h; y++)
1786 /* This is pretty easy, a line for line memcpy */
1787 memmove(dbuf, sbuf, width);
1791 TRACE("Copy done\n");
1797 IWineD3DSurface_UnlockRect(iface);
1801 IWineD3DSurface_UnlockRect(iface);
1802 IWineD3DSurface_UnlockRect(src_surface);
1808 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1810 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1812 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1813 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1815 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1819 pLockedRect->pBits = This->resource.allocatedMemory;
1820 This->lockedRect.left = 0;
1821 This->lockedRect.top = 0;
1822 This->lockedRect.right = This->currentDesc.Width;
1823 This->lockedRect.bottom = This->currentDesc.Height;
1825 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1826 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1827 This->lockedRect.right, This->lockedRect.bottom);
1831 const struct wined3d_format *format = This->resource.format;
1833 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1834 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1836 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1838 /* Compressed textures are block based, so calculate the offset of
1839 * the block that contains the top-left pixel of the locked rectangle. */
1840 pLockedRect->pBits = This->resource.allocatedMemory
1841 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1842 + ((pRect->left / format->block_width) * format->block_byte_count);
1846 pLockedRect->pBits = This->resource.allocatedMemory +
1847 (pLockedRect->Pitch * pRect->top) +
1848 (pRect->left * format->byte_count);
1850 This->lockedRect.left = pRect->left;
1851 This->lockedRect.top = pRect->top;
1852 This->lockedRect.right = pRect->right;
1853 This->lockedRect.bottom = pRect->bottom;
1856 /* No dirtifying is needed for this surface implementation */
1857 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1862 /* TODO: think about moving this down to resource? */
1863 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1865 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1867 /* This should only be called for sysmem textures, it may be a good idea
1868 * to extend this to all pools at some point in the future */
1869 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1871 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1873 return This->resource.allocatedMemory;