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 < pow(2, 10)) {
54 }while(tmp < pow(2, 10));
55 } else if(tmp >= pow(2, 11)) {
60 }while(tmp >= pow(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 */
87 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
89 /* *******************************************
90 IWineD3DSurface IUnknown parts follow
91 ******************************************* */
92 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
94 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
95 /* Warn ,but be nice about things */
96 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
98 if (IsEqualGUID(riid, &IID_IUnknown)
99 || IsEqualGUID(riid, &IID_IWineD3DBase)
100 || IsEqualGUID(riid, &IID_IWineD3DResource)
101 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
102 IUnknown_AddRef((IUnknown*)iface);
107 return E_NOINTERFACE;
110 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
111 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
112 ULONG ref = InterlockedIncrement(&This->resource.ref);
113 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
117 /* ****************************************************
118 IWineD3DSurface IWineD3DResource parts follow
119 **************************************************** */
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
121 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
124 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
125 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
128 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
129 return resource_free_private_data((IWineD3DResource *)iface, refguid);
132 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
133 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
137 return resource_get_priority((IWineD3DResource *)iface);
140 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
141 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
142 return resource_get_type((IWineD3DResource *)iface);
145 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
146 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
147 return resource_get_parent((IWineD3DResource *)iface, pParent);
150 /* ******************************************************
151 IWineD3DSurface IWineD3DSurface parts follow
152 ****************************************************** */
154 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
155 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
156 IWineD3DBase *container = 0;
158 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
161 ERR("Called without a valid ppContainer.\n");
164 /* Standalone surfaces return the device as container. */
165 if (This->container) container = This->container;
166 else container = (IWineD3DBase *)This->resource.device;
168 TRACE("Relaying to QueryInterface\n");
169 return IUnknown_QueryInterface(container, riid, ppContainer);
172 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
173 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
175 TRACE("(%p) : copying into %p\n", This, pDesc);
177 pDesc->format = This->resource.format_desc->format;
178 pDesc->resource_type = This->resource.resourceType;
179 pDesc->usage = This->resource.usage;
180 pDesc->pool = This->resource.pool;
181 pDesc->size = This->resource.size; /* dx8 only */
182 pDesc->multisample_type = This->currentDesc.MultiSampleType;
183 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
184 pDesc->width = This->currentDesc.Width;
185 pDesc->height = This->currentDesc.Height;
190 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
192 TRACE("iface %p, flags %#x.\n", iface, Flags);
196 case WINEDDGBS_CANBLT:
197 case WINEDDGBS_ISBLTDONE:
201 return WINED3DERR_INVALIDCALL;
205 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
206 /* XXX: DDERR_INVALIDSURFACETYPE */
208 TRACE("(%p)->(%08x)\n",iface,Flags);
210 case WINEDDGFS_CANFLIP:
211 case WINEDDGFS_ISFLIPDONE:
215 return WINED3DERR_INVALIDCALL;
219 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
220 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
221 TRACE("(%p)\n", This);
223 /* D3D8 and 9 loose full devices, ddraw only surfaces */
224 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
227 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
228 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
229 TRACE("(%p)\n", This);
231 /* So far we don't lose anything :) */
232 This->Flags &= ~SFLAG_LOST;
236 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
237 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
238 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
239 TRACE("(%p)->(%p)\n", This, Pal);
241 if(This->palette == PalImpl) {
242 TRACE("Nop palette change\n");
246 if(This->palette != NULL)
247 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
248 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
250 This->palette = PalImpl;
252 if(PalImpl != NULL) {
253 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
254 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
257 return IWineD3DSurface_RealizePalette(iface);
259 else return WINED3D_OK;
262 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
264 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
265 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
267 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
268 FIXME(" colorkey value not supported (%08x) !\n", Flags);
269 return WINED3DERR_INVALIDCALL;
272 /* Dirtify the surface, but only if a key was changed */
274 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
275 case WINEDDCKEY_DESTBLT:
276 This->DestBltCKey = *CKey;
277 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
280 case WINEDDCKEY_DESTOVERLAY:
281 This->DestOverlayCKey = *CKey;
282 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
285 case WINEDDCKEY_SRCOVERLAY:
286 This->SrcOverlayCKey = *CKey;
287 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
290 case WINEDDCKEY_SRCBLT:
291 This->SrcBltCKey = *CKey;
292 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
297 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
298 case WINEDDCKEY_DESTBLT:
299 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
302 case WINEDDCKEY_DESTOVERLAY:
303 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
306 case WINEDDCKEY_SRCOVERLAY:
307 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
310 case WINEDDCKEY_SRCBLT:
311 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
319 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
320 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
321 TRACE("(%p)->(%p)\n", This, Pal);
323 *Pal = (IWineD3DPalette *) This->palette;
327 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
328 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
329 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
331 TRACE("(%p)\n", This);
333 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
335 /* Since compressed formats are block based, pitch means the amount of
336 * bytes to the next row of block rather than the next row of pixels. */
337 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
338 ret = row_block_count * format_desc->block_byte_count;
342 unsigned char alignment = This->resource.device->surface_alignment;
343 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
344 ret = (ret + alignment - 1) & ~(alignment - 1);
346 TRACE("(%p) Returning %d\n", This, ret);
350 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
351 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
354 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
356 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
358 TRACE("(%p): Not an overlay surface\n", This);
359 return WINEDDERR_NOTAOVERLAYSURFACE;
362 w = This->overlay_destrect.right - This->overlay_destrect.left;
363 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
364 This->overlay_destrect.left = X;
365 This->overlay_destrect.top = Y;
366 This->overlay_destrect.right = X + w;
367 This->overlay_destrect.bottom = Y + h;
369 IWineD3DSurface_DrawOverlay(iface);
374 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
375 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
378 TRACE("(%p)->(%p,%p)\n", This, X, Y);
380 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
382 TRACE("(%p): Not an overlay surface\n", This);
383 return WINEDDERR_NOTAOVERLAYSURFACE;
385 if(This->overlay_dest == NULL) {
387 hr = WINEDDERR_OVERLAYNOTVISIBLE;
389 *X = This->overlay_destrect.left;
390 *Y = This->overlay_destrect.top;
394 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
398 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
399 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
401 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
403 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
405 TRACE("(%p): Not an overlay surface\n", This);
406 return WINEDDERR_NOTAOVERLAYSURFACE;
412 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
413 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
415 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
416 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
417 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
419 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
421 WARN("(%p): Not an overlay surface\n", This);
422 return WINEDDERR_NOTAOVERLAYSURFACE;
423 } else if(!DstSurface) {
424 WARN("(%p): Dest surface is NULL\n", This);
425 return WINED3DERR_INVALIDCALL;
429 This->overlay_srcrect = *SrcRect;
431 This->overlay_srcrect.left = 0;
432 This->overlay_srcrect.top = 0;
433 This->overlay_srcrect.right = This->currentDesc.Width;
434 This->overlay_srcrect.bottom = This->currentDesc.Height;
438 This->overlay_destrect = *DstRect;
440 This->overlay_destrect.left = 0;
441 This->overlay_destrect.top = 0;
442 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
443 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
446 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
447 list_remove(&This->overlay_entry);
450 if(Flags & WINEDDOVER_SHOW) {
451 if(This->overlay_dest != Dst) {
452 This->overlay_dest = Dst;
453 list_add_tail(&Dst->overlays, &This->overlay_entry);
455 } else if(Flags & WINEDDOVER_HIDE) {
456 /* tests show that the rectangles are erased on hide */
457 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
458 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
459 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
460 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
461 This->overlay_dest = NULL;
464 IWineD3DSurface_DrawOverlay(iface);
469 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
471 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
472 TRACE("(%p)->(%p)\n", This, clipper);
474 This->clipper = clipper;
478 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
480 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
481 TRACE("(%p)->(%p)\n", This, clipper);
483 *clipper = This->clipper;
485 IWineD3DClipper_AddRef(*clipper);
490 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
491 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
493 TRACE("This %p, container %p\n", This, container);
495 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
497 TRACE("Setting container to %p from %p\n", container, This->container);
498 This->container = container;
503 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
504 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
505 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format,
506 &This->resource.device->adapter->gl_info);
508 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
510 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
511 return WINED3DERR_INVALIDCALL;
514 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
516 This->resource.size = surface_calculate_size(format_desc, This->resource.device->surface_alignment,
517 This->pow2Width, This->pow2Height);
519 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
521 This->resource.format_desc = format_desc;
523 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
528 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
529 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
530 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
538 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
540 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
541 return WINED3DERR_INVALIDCALL;
544 switch (format_desc->byte_count)
548 /* Allocate extra space to store the RGB bit masks. */
549 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
553 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
557 /* Allocate extra space for a palette. */
558 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
559 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
564 return E_OUTOFMEMORY;
566 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
567 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
568 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
569 * add an extra line to the dib section
571 GetSystemInfo(&sysInfo);
572 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
574 TRACE("Adding an extra line to the dib section\n");
577 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
578 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
579 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
580 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
581 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
582 b_info->bmiHeader.biPlanes = 1;
583 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
585 b_info->bmiHeader.biXPelsPerMeter = 0;
586 b_info->bmiHeader.biYPelsPerMeter = 0;
587 b_info->bmiHeader.biClrUsed = 0;
588 b_info->bmiHeader.biClrImportant = 0;
590 /* Get the bit masks */
591 masks = (DWORD *)b_info->bmiColors;
592 switch (This->resource.format_desc->format)
594 case WINED3DFMT_B8G8R8_UNORM:
595 usage = DIB_RGB_COLORS;
596 b_info->bmiHeader.biCompression = BI_RGB;
599 case WINED3DFMT_B5G5R5X1_UNORM:
600 case WINED3DFMT_B5G5R5A1_UNORM:
601 case WINED3DFMT_B4G4R4A4_UNORM:
602 case WINED3DFMT_B4G4R4X4_UNORM:
603 case WINED3DFMT_B2G3R3_UNORM:
604 case WINED3DFMT_B2G3R3A8_UNORM:
605 case WINED3DFMT_R10G10B10A2_UNORM:
606 case WINED3DFMT_R8G8B8A8_UNORM:
607 case WINED3DFMT_R8G8B8X8_UNORM:
608 case WINED3DFMT_B10G10R10A2_UNORM:
609 case WINED3DFMT_B5G6R5_UNORM:
610 case WINED3DFMT_R16G16B16A16_UNORM:
612 b_info->bmiHeader.biCompression = BI_BITFIELDS;
613 masks[0] = format_desc->red_mask;
614 masks[1] = format_desc->green_mask;
615 masks[2] = format_desc->blue_mask;
619 /* Don't know palette */
620 b_info->bmiHeader.biCompression = BI_RGB;
627 HeapFree(GetProcessHeap(), 0, b_info);
628 return HRESULT_FROM_WIN32(GetLastError());
631 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);
632 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
635 if (!This->dib.DIBsection) {
636 ERR("CreateDIBSection failed!\n");
637 HeapFree(GetProcessHeap(), 0, b_info);
638 return HRESULT_FROM_WIN32(GetLastError());
641 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
642 /* copy the existing surface to the dib section */
643 if(This->resource.allocatedMemory) {
644 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
646 /* This is to make LockRect read the gl Texture although memory is allocated */
647 This->Flags &= ~SFLAG_INSYSMEM;
649 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
651 HeapFree(GetProcessHeap(), 0, b_info);
653 /* Now allocate a HDC */
654 This->hDC = CreateCompatibleDC(0);
655 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
656 TRACE("using wined3d palette %p\n", This->palette);
657 SelectPalette(This->hDC,
658 This->palette ? This->palette->hpal : 0,
661 This->Flags |= SFLAG_DIBSECTION;
663 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
664 This->resource.heapMemory = NULL;
669 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
670 unsigned int w, unsigned int h)
674 unsigned short *dst_s;
676 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
677 for(y = 0; y < h; y++) {
678 src_f = (const float *)(src + y * pitch_in);
679 dst_s = (unsigned short *) (dst + y * pitch_out);
680 for(x = 0; x < w; x++) {
681 dst_s[x] = float_32_to_16(src_f + x);
686 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
687 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
689 static const unsigned char convert_5to8[] =
691 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
692 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
693 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
694 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
696 static const unsigned char convert_6to8[] =
698 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
699 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
700 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
701 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
702 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
703 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
704 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
705 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
709 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
711 for (y = 0; y < h; ++y)
713 const WORD *src_line = (const WORD *)(src + y * pitch_in);
714 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
715 for (x = 0; x < w; ++x)
717 WORD pixel = src_line[x];
718 dst_line[x] = 0xff000000
719 | convert_5to8[(pixel & 0xf800) >> 11] << 16
720 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
721 | convert_5to8[(pixel & 0x001f)];
726 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
727 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
731 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
733 for (y = 0; y < h; ++y)
735 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
736 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
738 for (x = 0; x < w; ++x)
740 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
745 static inline BYTE cliptobyte(int x)
747 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
750 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
751 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
754 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
756 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
758 for (y = 0; y < h; ++y)
760 const BYTE *src_line = src + y * pitch_in;
761 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
762 for (x = 0; x < w; ++x)
764 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
765 * C = Y - 16; D = U - 128; E = V - 128;
766 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
767 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
768 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
769 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
770 * U and V are shared between the pixels.
772 if (!(x & 1)) /* for every even pixel, read new U and V */
774 d = (int) src_line[1] - 128;
775 e = (int) src_line[3] - 128;
777 g2 = - 100 * d - 208 * e + 128;
780 c2 = 298 * ((int) src_line[0] - 16);
781 dst_line[x] = 0xff000000
782 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
783 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
784 | cliptobyte((c2 + b2) >> 8); /* blue */
785 /* Scale RGB values to 0..255 range,
786 * then clip them if still not in range (may be negative),
787 * then shift them within DWORD if necessary.
794 struct d3dfmt_convertor_desc {
795 WINED3DFORMAT from, to;
796 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
799 static const struct d3dfmt_convertor_desc convertors[] =
801 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
802 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
803 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
804 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
807 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
810 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
811 if(convertors[i].from == from && convertors[i].to == to) {
812 return &convertors[i];
818 /*****************************************************************************
819 * surface_convert_format
821 * Creates a duplicate of a surface in a different format. Is used by Blt to
822 * blit between surfaces with different formats
825 * source: Source surface
826 * fmt: Requested destination format
828 *****************************************************************************/
829 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
830 IWineD3DSurface *ret = NULL;
831 const struct d3dfmt_convertor_desc *conv;
832 WINED3DLOCKED_RECT lock_src, lock_dst;
835 conv = find_convertor(source->resource.format_desc->format, to_fmt);
837 FIXME("Cannot find a conversion function from format %s to %s\n",
838 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
842 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
843 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
844 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
845 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
846 NULL /* parent */, &wined3d_null_parent_ops);
848 ERR("Failed to create a destination surface for conversion\n");
852 memset(&lock_src, 0, sizeof(lock_src));
853 memset(&lock_dst, 0, sizeof(lock_dst));
855 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
857 ERR("Failed to lock the source surface\n");
858 IWineD3DSurface_Release(ret);
861 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
863 ERR("Failed to lock the dest surface\n");
864 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
865 IWineD3DSurface_Release(ret);
869 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
870 source->currentDesc.Width, source->currentDesc.Height);
872 IWineD3DSurface_UnlockRect(ret);
873 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
875 return (IWineD3DSurfaceImpl *) ret;
878 /*****************************************************************************
881 * Helper function that fills a memory area with a specific color
884 * buf: memory address to start filling at
885 * width, height: Dimensions of the area to fill
886 * bpp: Bit depth of the surface
887 * lPitch: pitch of the surface
888 * color: Color to fill with
890 *****************************************************************************/
892 _Blt_ColorFill(BYTE *buf,
893 int width, int height,
894 int bpp, LONG lPitch,
902 #define COLORFILL_ROW(type) \
904 type *d = (type *) buf; \
905 for (x = 0; x < width; x++) \
906 d[x] = (type) color; \
911 case 1: COLORFILL_ROW(BYTE)
912 case 2: COLORFILL_ROW(WORD)
916 for (x = 0; x < width; x++,d+=3)
918 d[0] = (color ) & 0xFF;
919 d[1] = (color>> 8) & 0xFF;
920 d[2] = (color>>16) & 0xFF;
924 case 4: COLORFILL_ROW(DWORD)
926 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
927 return WINED3DERR_NOTAVAILABLE;
932 /* Now copy first row */
934 for (y = 1; y < height; y++)
937 memcpy(buf, first, width * bpp);
942 /*****************************************************************************
943 * IWineD3DSurface::Blt, SW emulation version
945 * Performs blits to a surface, eigher from a source of source-less blts
946 * This is the main functionality of DirectDraw
949 * DestRect: Destination rectangle to write to
950 * SrcSurface: Source surface, can be NULL
951 * SrcRect: Source rectangle
952 *****************************************************************************/
953 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
954 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
956 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
957 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
959 HRESULT ret = WINED3D_OK;
960 WINED3DLOCKED_RECT dlock, slock;
961 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
962 const struct wined3d_format_desc *sEntry, *dEntry;
966 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
968 if (TRACE_ON(d3d_surface))
970 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
971 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
972 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
973 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
976 DDRAW_dump_DDBLT(Flags);
977 if (Flags & WINEDDBLT_DDFX)
980 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
985 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
987 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
988 return WINEDDERR_SURFACEBUSY;
991 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
992 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
993 FIXME("Filters not supported in software blit\n");
996 /* First check for the validity of source / destination rectangles. This was
997 * verified using a test application + by MSDN.
999 if ((Src != NULL) && (SrcRect != NULL) &&
1000 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
1001 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
1002 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
1003 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
1004 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
1006 WARN("Application gave us bad source rectangle for Blt.\n");
1007 return WINEDDERR_INVALIDRECT;
1009 /* For the Destination rect, it can be out of bounds on the condition that a clipper
1010 * is set for the given surface.
1012 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
1013 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
1014 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
1015 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
1016 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
1017 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
1019 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1020 return WINEDDERR_INVALIDRECT;
1023 /* Now handle negative values in the rectangles. Warning: only supported for now
1024 in the 'simple' cases (ie not in any stretching / rotation cases).
1026 First, the case where nothing is to be done.
1028 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
1029 (DestRect->top >= (int) This->currentDesc.Height) ||
1030 (DestRect->left >= (int) This->currentDesc.Width))) ||
1031 ((Src != NULL) && (SrcRect != NULL) &&
1032 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
1033 (SrcRect->top >= (int) Src->currentDesc.Height) ||
1034 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
1036 TRACE("Nothing to be done !\n");
1047 xdst.bottom = This->currentDesc.Height;
1049 xdst.right = This->currentDesc.Width;
1061 xsrc.bottom = Src->currentDesc.Height;
1063 xsrc.right = Src->currentDesc.Width;
1067 memset(&xsrc,0,sizeof(xsrc));
1071 /* The easy case : the source-less blits.... */
1072 if (Src == NULL && DestRect)
1075 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1079 full_rect.right = This->currentDesc.Width;
1080 full_rect.bottom = This->currentDesc.Height;
1081 IntersectRect(&temp_rect, &full_rect, DestRect);
1086 /* Only handle clipping on the destination rectangle */
1087 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1088 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1089 if (clip_vert || clip_horiz)
1091 /* Now check if this is a special case or not... */
1092 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1093 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1094 (Flags & WINEDDBLT_DDFX))
1096 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1102 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1103 if (DestRect->right > This->currentDesc.Width)
1105 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1106 xdst.right = (int) This->currentDesc.Width;
1111 if (DestRect->top < 0)
1113 xsrc.top -= DestRect->top;
1116 if (DestRect->bottom > This->currentDesc.Height)
1118 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1119 xdst.bottom = (int) This->currentDesc.Height;
1122 /* And check if after clipping something is still to be done... */
1123 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1124 (xdst.top >= (int) This->currentDesc.Height) ||
1125 (xdst.left >= (int) This->currentDesc.Width) ||
1126 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1127 (xsrc.top >= (int) Src->currentDesc.Height) ||
1128 (xsrc.left >= (int) Src->currentDesc.Width))
1130 TRACE("Nothing to be done after clipping !\n");
1138 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1140 sEntry = This->resource.format_desc;
1145 dEntry = This->resource.format_desc;
1148 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1150 Src = surface_convert_format(Src, dEntry->format);
1152 /* The conv function writes a FIXME */
1153 WARN("Cannot convert source surface format to dest format\n");
1157 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1158 sEntry = Src->resource.format_desc;
1165 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1167 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1170 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1172 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1174 if (!DestRect || Src == This)
1176 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1181 bpp = This->resource.format_desc->byte_count;
1182 srcheight = xsrc.bottom - xsrc.top;
1183 srcwidth = xsrc.right - xsrc.left;
1184 dstheight = xdst.bottom - xdst.top;
1185 dstwidth = xdst.right - xdst.left;
1186 width = (xdst.right - xdst.left) * bpp;
1188 if (DestRect && Src != This)
1191 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1193 if (Flags & WINEDDBLT_WAIT)
1195 Flags &= ~WINEDDBLT_WAIT;
1197 if (Flags & WINEDDBLT_ASYNC)
1199 static BOOL displayed = FALSE;
1201 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1203 Flags &= ~WINEDDBLT_ASYNC;
1205 if (Flags & WINEDDBLT_DONOTWAIT)
1207 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1208 static BOOL displayed = FALSE;
1210 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1212 Flags &= ~WINEDDBLT_DONOTWAIT;
1215 /* First, all the 'source-less' blits */
1216 if (Flags & WINEDDBLT_COLORFILL)
1218 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1219 dlock.Pitch, DDBltFx->u5.dwFillColor);
1220 Flags &= ~WINEDDBLT_COLORFILL;
1223 if (Flags & WINEDDBLT_DEPTHFILL)
1225 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1227 if (Flags & WINEDDBLT_ROP)
1229 /* Catch some degenerate cases here */
1230 switch(DDBltFx->dwROP)
1233 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1235 case 0xAA0029: /* No-op */
1238 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1240 case SRCCOPY: /* well, we do that below ? */
1243 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1246 Flags &= ~WINEDDBLT_ROP;
1248 if (Flags & WINEDDBLT_DDROPS)
1250 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1252 /* Now the 'with source' blits */
1256 int sx, xinc, sy, yinc;
1258 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1260 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1261 xinc = (srcwidth << 16) / dstwidth;
1262 yinc = (srcheight << 16) / dstheight;
1266 /* No effects, we can cheat here */
1267 if (dstwidth == srcwidth)
1269 if (dstheight == srcheight)
1271 /* No stretching in either direction. This needs to be as
1272 * fast as possible */
1275 /* check for overlapping surfaces */
1276 if (Src != This || xdst.top < xsrc.top ||
1277 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1279 /* no overlap, or dst above src, so copy from top downwards */
1280 for (y = 0; y < dstheight; y++)
1282 memcpy(dbuf, sbuf, width);
1283 sbuf += slock.Pitch;
1284 dbuf += dlock.Pitch;
1287 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1289 sbuf += (slock.Pitch*dstheight);
1290 dbuf += (dlock.Pitch*dstheight);
1291 for (y = 0; y < dstheight; y++)
1293 sbuf -= slock.Pitch;
1294 dbuf -= dlock.Pitch;
1295 memcpy(dbuf, sbuf, width);
1298 else /* src and dst overlapping on the same line, use memmove */
1300 for (y = 0; y < dstheight; y++)
1302 memmove(dbuf, sbuf, width);
1303 sbuf += slock.Pitch;
1304 dbuf += dlock.Pitch;
1308 /* Stretching in Y direction only */
1309 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1310 sbuf = sbase + (sy >> 16) * slock.Pitch;
1311 memcpy(dbuf, sbuf, width);
1312 dbuf += dlock.Pitch;
1318 /* Stretching in X direction */
1320 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1322 sbuf = sbase + (sy >> 16) * slock.Pitch;
1324 if ((sy >> 16) == (last_sy >> 16))
1326 /* this sourcerow is the same as last sourcerow -
1327 * copy already stretched row
1329 memcpy(dbuf, dbuf - dlock.Pitch, width);
1333 #define STRETCH_ROW(type) { \
1334 const type *s = (const type *)sbuf; \
1335 type *d = (type *)dbuf; \
1336 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1337 d[x] = s[sx >> 16]; \
1342 case 1: STRETCH_ROW(BYTE)
1343 case 2: STRETCH_ROW(WORD)
1344 case 4: STRETCH_ROW(DWORD)
1349 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1353 s = sbuf+3*(sx>>16);
1354 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1355 d[0] = (pixel )&0xff;
1356 d[1] = (pixel>> 8)&0xff;
1357 d[2] = (pixel>>16)&0xff;
1363 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1364 ret = WINED3DERR_NOTAVAILABLE;
1369 dbuf += dlock.Pitch;
1376 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1377 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1378 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1379 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1381 /* The color keying flags are checked for correctness in ddraw */
1382 if (Flags & WINEDDBLT_KEYSRC)
1384 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1385 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1387 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1389 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1390 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1393 if (Flags & WINEDDBLT_KEYDEST)
1395 /* Destination color keys are taken from the source surface ! */
1396 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1397 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1399 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1401 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1402 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1411 keymask = sEntry->red_mask
1412 | sEntry->green_mask
1413 | sEntry->blue_mask;
1415 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1418 if (Flags & WINEDDBLT_DDFX)
1420 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1423 dTopRight = dbuf+((dstwidth-1)*bpp);
1424 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1425 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1427 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1429 /* I don't think we need to do anything about this flag */
1430 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1432 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1435 dTopRight = dTopLeft;
1438 dBottomRight = dBottomLeft;
1440 dstxinc = dstxinc *-1;
1442 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1445 dTopLeft = dBottomLeft;
1448 dTopRight = dBottomRight;
1450 dstyinc = dstyinc *-1;
1452 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1454 /* I don't think we need to do anything about this flag */
1455 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1457 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1460 dBottomRight = dTopLeft;
1463 dBottomLeft = dTopRight;
1465 dstxinc = dstxinc * -1;
1466 dstyinc = dstyinc * -1;
1468 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1471 dTopLeft = dBottomLeft;
1472 dBottomLeft = dBottomRight;
1473 dBottomRight = dTopRight;
1478 dstxinc = dstxinc * -1;
1480 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1483 dTopLeft = dTopRight;
1484 dTopRight = dBottomRight;
1485 dBottomRight = dBottomLeft;
1490 dstyinc = dstyinc * -1;
1492 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1494 /* I don't think we need to do anything about this flag */
1495 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1498 Flags &= ~(WINEDDBLT_DDFX);
1501 #define COPY_COLORKEY_FX(type) { \
1503 type *d = (type *)dbuf, *dx, tmp; \
1504 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1505 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1507 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1508 tmp = s[sx >> 16]; \
1509 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1510 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1513 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1515 d = (type*)(((LPBYTE)d)+dstyinc); \
1520 case 1: COPY_COLORKEY_FX(BYTE)
1521 case 2: COPY_COLORKEY_FX(WORD)
1522 case 4: COPY_COLORKEY_FX(DWORD)
1526 BYTE *d = dbuf, *dx;
1527 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1529 sbuf = sbase + (sy >> 16) * slock.Pitch;
1531 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1533 DWORD pixel, dpixel = 0;
1534 s = sbuf+3*(sx>>16);
1535 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1536 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1537 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1538 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1540 dx[0] = (pixel )&0xff;
1541 dx[1] = (pixel>> 8)&0xff;
1542 dx[2] = (pixel>>16)&0xff;
1551 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1552 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1553 ret = WINED3DERR_NOTAVAILABLE;
1555 #undef COPY_COLORKEY_FX
1561 if (Flags && FIXME_ON(d3d_surface))
1563 FIXME("\tUnsupported flags: %08x\n", Flags);
1567 IWineD3DSurface_UnlockRect(iface);
1568 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1569 /* Release the converted surface if any */
1570 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1574 /*****************************************************************************
1575 * IWineD3DSurface::BltFast, SW emulation version
1577 * This is the software implementation of BltFast, as used by GDI surfaces
1578 * and as a fallback for OpenGL surfaces. This code is taken from the old
1579 * DirectDraw code, and was originally written by TransGaming.
1584 * Source: Source surface to copy from
1585 * rsrc: Source rectangle
1589 * WINED3D_OK on success
1591 *****************************************************************************/
1592 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1593 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1595 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1596 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1598 int bpp, w, h, x, y;
1599 WINED3DLOCKED_RECT dlock,slock;
1600 HRESULT ret = WINED3D_OK;
1602 RECT lock_src, lock_dst, lock_union;
1605 const struct wined3d_format_desc *sEntry, *dEntry;
1607 if (TRACE_ON(d3d_surface))
1609 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1613 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1614 rsrc->right,rsrc->bottom);
1618 TRACE(" srcrect: NULL\n");
1622 if ((This->Flags & SFLAG_LOCKED) ||
1623 (Src->Flags & SFLAG_LOCKED))
1625 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1626 return WINEDDERR_SURFACEBUSY;
1631 WARN("rsrc is NULL!\n");
1634 rsrc2.right = Src->currentDesc.Width;
1635 rsrc2.bottom = Src->currentDesc.Height;
1639 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1640 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1641 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1642 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1643 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1644 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1646 WARN("Application gave us bad source rectangle for BltFast.\n");
1647 return WINEDDERR_INVALIDRECT;
1650 h = rsrc->bottom - rsrc->top;
1651 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1652 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1653 if (h <= 0) return WINEDDERR_INVALIDRECT;
1655 w = rsrc->right - rsrc->left;
1656 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1657 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1658 if (w <= 0) return WINEDDERR_INVALIDRECT;
1660 /* Now compute the locking rectangle... */
1661 lock_src.left = rsrc->left;
1662 lock_src.top = rsrc->top;
1663 lock_src.right = lock_src.left + w;
1664 lock_src.bottom = lock_src.top + h;
1666 lock_dst.left = dstx;
1667 lock_dst.top = dsty;
1668 lock_dst.right = dstx + w;
1669 lock_dst.bottom = dsty + h;
1671 bpp = This->resource.format_desc->byte_count;
1673 /* We need to lock the surfaces, or we won't get refreshes when done. */
1678 UnionRect(&lock_union, &lock_src, &lock_dst);
1680 /* Lock the union of the two rectangles */
1681 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1682 if(ret != WINED3D_OK) goto error;
1684 pitch = dlock.Pitch;
1685 slock.Pitch = dlock.Pitch;
1687 /* Since slock was originally copied from this surface's description, we can just reuse it */
1688 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1689 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1690 sEntry = Src->resource.format_desc;
1695 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1696 if(ret != WINED3D_OK) goto error;
1697 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1698 if(ret != WINED3D_OK) goto error;
1702 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1704 sEntry = Src->resource.format_desc;
1705 dEntry = This->resource.format_desc;
1708 /* Handle compressed surfaces first... */
1709 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1711 UINT row_block_count;
1713 TRACE("compressed -> compressed copy\n");
1715 FIXME("trans arg not supported when a compressed surface is involved\n");
1717 FIXME("offset for destination surface is not supported\n");
1718 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1720 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1721 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1725 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1726 for (y = 0; y < h; y += dEntry->block_height)
1728 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1729 dbuf += dlock.Pitch;
1730 sbuf += slock.Pitch;
1735 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1737 /* TODO: Use the libtxc_dxtn.so shared library to do
1738 * software decompression
1740 ERR("Software decompression not supported.\n");
1744 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1746 DWORD keylow, keyhigh;
1747 DWORD mask = Src->resource.format_desc->red_mask |
1748 Src->resource.format_desc->green_mask |
1749 Src->resource.format_desc->blue_mask;
1751 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1755 TRACE("Color keyed copy\n");
1756 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1758 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1759 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1763 /* I'm not sure if this is correct */
1764 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1765 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1766 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1769 #define COPYBOX_COLORKEY(type) { \
1770 const type *s = (const type *)sbuf; \
1771 type *d = (type *)dbuf; \
1773 for (y = 0; y < h; y++) { \
1774 for (x = 0; x < w; x++) { \
1776 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1778 s = (const type *)((const BYTE *)s + slock.Pitch); \
1779 d = (type *)((BYTE *)d + dlock.Pitch); \
1785 case 1: COPYBOX_COLORKEY(BYTE)
1786 case 2: COPYBOX_COLORKEY(WORD)
1787 case 4: COPYBOX_COLORKEY(DWORD)
1795 for (y = 0; y < h; y++)
1797 for (x = 0; x < w * 3; x += 3)
1799 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1800 if (tmp < keylow || tmp > keyhigh)
1802 d[x + 0] = s[x + 0];
1803 d[x + 1] = s[x + 1];
1804 d[x + 2] = s[x + 2];
1813 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1814 ret = WINED3DERR_NOTAVAILABLE;
1817 #undef COPYBOX_COLORKEY
1818 TRACE("Copy Done\n");
1822 int width = w * bpp;
1823 INT sbufpitch, dbufpitch;
1825 TRACE("NO color key copy\n");
1826 /* Handle overlapping surfaces */
1829 sbuf += (h - 1) * slock.Pitch;
1830 dbuf += (h - 1) * dlock.Pitch;
1831 sbufpitch = -slock.Pitch;
1832 dbufpitch = -dlock.Pitch;
1836 sbufpitch = slock.Pitch;
1837 dbufpitch = dlock.Pitch;
1839 for (y = 0; y < h; y++)
1841 /* This is pretty easy, a line for line memcpy */
1842 memmove(dbuf, sbuf, width);
1846 TRACE("Copy done\n");
1852 IWineD3DSurface_UnlockRect(iface);
1856 IWineD3DSurface_UnlockRect(iface);
1857 IWineD3DSurface_UnlockRect(Source);
1863 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1865 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1867 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1868 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1870 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1874 pLockedRect->pBits = This->resource.allocatedMemory;
1875 This->lockedRect.left = 0;
1876 This->lockedRect.top = 0;
1877 This->lockedRect.right = This->currentDesc.Width;
1878 This->lockedRect.bottom = This->currentDesc.Height;
1880 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1881 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1882 This->lockedRect.right, This->lockedRect.bottom);
1886 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1888 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1889 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1891 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1893 /* Compressed textures are block based, so calculate the offset of
1894 * the block that contains the top-left pixel of the locked rectangle. */
1895 pLockedRect->pBits = This->resource.allocatedMemory
1896 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1897 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1901 pLockedRect->pBits = This->resource.allocatedMemory +
1902 (pLockedRect->Pitch * pRect->top) +
1903 (pRect->left * format_desc->byte_count);
1905 This->lockedRect.left = pRect->left;
1906 This->lockedRect.top = pRect->top;
1907 This->lockedRect.right = pRect->right;
1908 This->lockedRect.bottom = pRect->bottom;
1911 /* No dirtifying is needed for this surface implementation */
1912 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1917 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1918 ERR("Should not be called on base texture\n");
1921 /* TODO: think about moving this down to resource? */
1922 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1924 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1926 /* This should only be called for sysmem textures, it may be a good idea
1927 * to extend this to all pools at some point in the future */
1928 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1930 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1932 return This->resource.allocatedMemory;