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) {
191 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
192 TRACE("(%p)->(%x)\n", This, 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 GlPixelFormatDesc *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;
400 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
402 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
404 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
406 TRACE("(%p): Not an overlay surface\n", This);
407 return WINEDDERR_NOTAOVERLAYSURFACE;
413 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
414 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
416 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
417 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
418 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
420 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
422 WARN("(%p): Not an overlay surface\n", This);
423 return WINEDDERR_NOTAOVERLAYSURFACE;
424 } else if(!DstSurface) {
425 WARN("(%p): Dest surface is NULL\n", This);
426 return WINED3DERR_INVALIDCALL;
430 This->overlay_srcrect = *SrcRect;
432 This->overlay_srcrect.left = 0;
433 This->overlay_srcrect.top = 0;
434 This->overlay_srcrect.right = This->currentDesc.Width;
435 This->overlay_srcrect.bottom = This->currentDesc.Height;
439 This->overlay_destrect = *DstRect;
441 This->overlay_destrect.left = 0;
442 This->overlay_destrect.top = 0;
443 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
444 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
447 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
448 list_remove(&This->overlay_entry);
451 if(Flags & WINEDDOVER_SHOW) {
452 if(This->overlay_dest != Dst) {
453 This->overlay_dest = Dst;
454 list_add_tail(&Dst->overlays, &This->overlay_entry);
456 } else if(Flags & WINEDDOVER_HIDE) {
457 /* tests show that the rectangles are erased on hide */
458 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
459 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
460 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
461 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
462 This->overlay_dest = NULL;
465 IWineD3DSurface_DrawOverlay(iface);
470 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
472 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
473 TRACE("(%p)->(%p)\n", This, clipper);
475 This->clipper = clipper;
479 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
481 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
482 TRACE("(%p)->(%p)\n", This, clipper);
484 *clipper = This->clipper;
486 IWineD3DClipper_AddRef(*clipper);
491 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
492 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
494 TRACE("This %p, container %p\n", This, container);
496 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
498 TRACE("Setting container to %p from %p\n", container, This->container);
499 This->container = container;
504 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
505 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
506 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
507 &This->resource.device->adapter->gl_info);
509 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
511 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
512 return WINED3DERR_INVALIDCALL;
515 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
517 This->resource.size = surface_calculate_size(format_desc, This->resource.device->surface_alignment,
518 This->pow2Width, This->pow2Height);
520 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
522 This->resource.format_desc = format_desc;
524 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
529 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
530 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
531 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
539 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
541 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
542 return WINED3DERR_INVALIDCALL;
545 switch (format_desc->byte_count)
549 /* Allocate extra space to store the RGB bit masks. */
550 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
554 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
558 /* Allocate extra space for a palette. */
559 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
560 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
565 return E_OUTOFMEMORY;
567 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
568 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
569 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
570 * add an extra line to the dib section
572 GetSystemInfo(&sysInfo);
573 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
575 TRACE("Adding an extra line to the dib section\n");
578 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
579 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
580 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
581 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
582 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
583 b_info->bmiHeader.biPlanes = 1;
584 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
586 b_info->bmiHeader.biXPelsPerMeter = 0;
587 b_info->bmiHeader.biYPelsPerMeter = 0;
588 b_info->bmiHeader.biClrUsed = 0;
589 b_info->bmiHeader.biClrImportant = 0;
591 /* Get the bit masks */
592 masks = (DWORD *)b_info->bmiColors;
593 switch (This->resource.format_desc->format)
595 case WINED3DFMT_B8G8R8_UNORM:
596 usage = DIB_RGB_COLORS;
597 b_info->bmiHeader.biCompression = BI_RGB;
600 case WINED3DFMT_B5G5R5X1_UNORM:
601 case WINED3DFMT_B5G5R5A1_UNORM:
602 case WINED3DFMT_B4G4R4A4_UNORM:
603 case WINED3DFMT_B4G4R4X4_UNORM:
604 case WINED3DFMT_B2G3R3_UNORM:
605 case WINED3DFMT_B2G3R3A8_UNORM:
606 case WINED3DFMT_R10G10B10A2_UNORM:
607 case WINED3DFMT_R8G8B8A8_UNORM:
608 case WINED3DFMT_R8G8B8X8_UNORM:
609 case WINED3DFMT_B10G10R10A2_UNORM:
610 case WINED3DFMT_B5G6R5_UNORM:
611 case WINED3DFMT_R16G16B16A16_UNORM:
613 b_info->bmiHeader.biCompression = BI_BITFIELDS;
614 masks[0] = format_desc->red_mask;
615 masks[1] = format_desc->green_mask;
616 masks[2] = format_desc->blue_mask;
620 /* Don't know palette */
621 b_info->bmiHeader.biCompression = BI_RGB;
628 HeapFree(GetProcessHeap(), 0, b_info);
629 return HRESULT_FROM_WIN32(GetLastError());
632 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);
633 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
636 if (!This->dib.DIBsection) {
637 ERR("CreateDIBSection failed!\n");
638 HeapFree(GetProcessHeap(), 0, b_info);
639 return HRESULT_FROM_WIN32(GetLastError());
642 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
643 /* copy the existing surface to the dib section */
644 if(This->resource.allocatedMemory) {
645 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
647 /* This is to make LockRect read the gl Texture although memory is allocated */
648 This->Flags &= ~SFLAG_INSYSMEM;
650 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
652 HeapFree(GetProcessHeap(), 0, b_info);
654 /* Now allocate a HDC */
655 This->hDC = CreateCompatibleDC(0);
656 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
657 TRACE("using wined3d palette %p\n", This->palette);
658 SelectPalette(This->hDC,
659 This->palette ? This->palette->hpal : 0,
662 This->Flags |= SFLAG_DIBSECTION;
664 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
665 This->resource.heapMemory = NULL;
670 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
671 unsigned int w, unsigned int h)
675 unsigned short *dst_s;
677 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
678 for(y = 0; y < h; y++) {
679 src_f = (const float *)(src + y * pitch_in);
680 dst_s = (unsigned short *) (dst + y * pitch_out);
681 for(x = 0; x < w; x++) {
682 dst_s[x] = float_32_to_16(src_f + x);
687 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
688 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
690 static const unsigned char convert_5to8[] =
692 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
693 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
694 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
695 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
697 static const unsigned char convert_6to8[] =
699 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
700 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
701 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
702 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
703 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
704 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
705 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
706 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
710 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
712 for (y = 0; y < h; ++y)
714 const WORD *src_line = (const WORD *)(src + y * pitch_in);
715 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
716 for (x = 0; x < w; ++x)
718 WORD pixel = src_line[x];
719 dst_line[x] = 0xff000000
720 | convert_5to8[(pixel & 0xf800) >> 11] << 16
721 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
722 | convert_5to8[(pixel & 0x001f)];
727 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
728 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
732 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
734 for (y = 0; y < h; ++y)
736 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
737 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
739 for (x = 0; x < w; ++x)
741 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
746 struct d3dfmt_convertor_desc {
747 WINED3DFORMAT from, to;
748 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
751 static const struct d3dfmt_convertor_desc convertors[] =
753 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
754 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
755 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
758 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
761 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
762 if(convertors[i].from == from && convertors[i].to == to) {
763 return &convertors[i];
769 /*****************************************************************************
770 * surface_convert_format
772 * Creates a duplicate of a surface in a different format. Is used by Blt to
773 * blit between surfaces with different formats
776 * source: Source surface
777 * fmt: Requested destination format
779 *****************************************************************************/
780 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
781 IWineD3DSurface *ret = NULL;
782 const struct d3dfmt_convertor_desc *conv;
783 WINED3DLOCKED_RECT lock_src, lock_dst;
786 conv = find_convertor(source->resource.format_desc->format, to_fmt);
788 FIXME("Cannot find a conversion function from format %s to %s\n",
789 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
793 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
794 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
795 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
796 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
797 NULL /* parent */, &wined3d_null_parent_ops);
799 ERR("Failed to create a destination surface for conversion\n");
803 memset(&lock_src, 0, sizeof(lock_src));
804 memset(&lock_dst, 0, sizeof(lock_dst));
806 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
808 ERR("Failed to lock the source surface\n");
809 IWineD3DSurface_Release(ret);
812 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
814 ERR("Failed to lock the dest surface\n");
815 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
816 IWineD3DSurface_Release(ret);
820 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
821 source->currentDesc.Width, source->currentDesc.Height);
823 IWineD3DSurface_UnlockRect(ret);
824 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
826 return (IWineD3DSurfaceImpl *) ret;
829 /*****************************************************************************
832 * Helper function that fills a memory area with a specific color
835 * buf: memory address to start filling at
836 * width, height: Dimensions of the area to fill
837 * bpp: Bit depth of the surface
838 * lPitch: pitch of the surface
839 * color: Color to fill with
841 *****************************************************************************/
843 _Blt_ColorFill(BYTE *buf,
844 int width, int height,
845 int bpp, LONG lPitch,
853 #define COLORFILL_ROW(type) \
855 type *d = (type *) buf; \
856 for (x = 0; x < width; x++) \
857 d[x] = (type) color; \
862 case 1: COLORFILL_ROW(BYTE)
863 case 2: COLORFILL_ROW(WORD)
867 for (x = 0; x < width; x++,d+=3)
869 d[0] = (color ) & 0xFF;
870 d[1] = (color>> 8) & 0xFF;
871 d[2] = (color>>16) & 0xFF;
875 case 4: COLORFILL_ROW(DWORD)
877 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
878 return WINED3DERR_NOTAVAILABLE;
883 /* Now copy first row */
885 for (y = 1; y < height; y++)
888 memcpy(buf, first, width * bpp);
893 /*****************************************************************************
894 * IWineD3DSurface::Blt, SW emulation version
896 * Performs blits to a surface, eigher from a source of source-less blts
897 * This is the main functionality of DirectDraw
900 * DestRect: Destination rectangle to write to
901 * SrcSurface: Source surface, can be NULL
902 * SrcRect: Source rectangle
903 *****************************************************************************/
904 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
905 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
907 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
908 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
910 HRESULT ret = WINED3D_OK;
911 WINED3DLOCKED_RECT dlock, slock;
912 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
913 const struct GlPixelFormatDesc *sEntry, *dEntry;
917 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
919 if (TRACE_ON(d3d_surface))
921 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
922 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
923 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
924 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
927 DDRAW_dump_DDBLT(Flags);
928 if (Flags & WINEDDBLT_DDFX)
931 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
936 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
938 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
939 return WINEDDERR_SURFACEBUSY;
942 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
943 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
944 FIXME("Filters not supported in software blit\n");
947 /* First check for the validity of source / destination rectangles. This was
948 * verified using a test application + by MSDN.
950 if ((Src != NULL) && (SrcRect != NULL) &&
951 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
952 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
953 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
954 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
955 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
957 WARN("Application gave us bad source rectangle for Blt.\n");
958 return WINEDDERR_INVALIDRECT;
960 /* For the Destination rect, it can be out of bounds on the condition that a clipper
961 * is set for the given surface.
963 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
964 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
965 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
966 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
967 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
968 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
970 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
971 return WINEDDERR_INVALIDRECT;
974 /* Now handle negative values in the rectangles. Warning: only supported for now
975 in the 'simple' cases (ie not in any stretching / rotation cases).
977 First, the case where nothing is to be done.
979 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
980 (DestRect->top >= (int) This->currentDesc.Height) ||
981 (DestRect->left >= (int) This->currentDesc.Width))) ||
982 ((Src != NULL) && (SrcRect != NULL) &&
983 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
984 (SrcRect->top >= (int) Src->currentDesc.Height) ||
985 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
987 TRACE("Nothing to be done !\n");
998 xdst.bottom = This->currentDesc.Height;
1000 xdst.right = This->currentDesc.Width;
1012 xsrc.bottom = Src->currentDesc.Height;
1014 xsrc.right = Src->currentDesc.Width;
1018 memset(&xsrc,0,sizeof(xsrc));
1022 /* The easy case : the source-less blits.... */
1023 if (Src == NULL && DestRect)
1026 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1030 full_rect.right = This->currentDesc.Width;
1031 full_rect.bottom = This->currentDesc.Height;
1032 IntersectRect(&temp_rect, &full_rect, DestRect);
1037 /* Only handle clipping on the destination rectangle */
1038 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1039 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1040 if (clip_vert || clip_horiz)
1042 /* Now check if this is a special case or not... */
1043 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1044 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1045 (Flags & WINEDDBLT_DDFX))
1047 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1053 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1054 if (DestRect->right > This->currentDesc.Width)
1056 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1057 xdst.right = (int) This->currentDesc.Width;
1062 if (DestRect->top < 0)
1064 xsrc.top -= DestRect->top;
1067 if (DestRect->bottom > This->currentDesc.Height)
1069 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1070 xdst.bottom = (int) This->currentDesc.Height;
1073 /* And check if after clipping something is still to be done... */
1074 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1075 (xdst.top >= (int) This->currentDesc.Height) ||
1076 (xdst.left >= (int) This->currentDesc.Width) ||
1077 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1078 (xsrc.top >= (int) Src->currentDesc.Height) ||
1079 (xsrc.left >= (int) Src->currentDesc.Width))
1081 TRACE("Nothing to be done after clipping !\n");
1089 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1091 sEntry = This->resource.format_desc;
1096 dEntry = This->resource.format_desc;
1099 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1101 Src = surface_convert_format(Src, dEntry->format);
1103 /* The conv function writes a FIXME */
1104 WARN("Cannot convert source surface format to dest format\n");
1108 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1109 sEntry = Src->resource.format_desc;
1116 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1118 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1121 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1123 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1125 if (!DestRect || Src == This)
1127 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1132 bpp = This->resource.format_desc->byte_count;
1133 srcheight = xsrc.bottom - xsrc.top;
1134 srcwidth = xsrc.right - xsrc.left;
1135 dstheight = xdst.bottom - xdst.top;
1136 dstwidth = xdst.right - xdst.left;
1137 width = (xdst.right - xdst.left) * bpp;
1139 if (DestRect && Src != This)
1142 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1144 if (Flags & WINEDDBLT_WAIT)
1146 Flags &= ~WINEDDBLT_WAIT;
1148 if (Flags & WINEDDBLT_ASYNC)
1150 static BOOL displayed = FALSE;
1152 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1154 Flags &= ~WINEDDBLT_ASYNC;
1156 if (Flags & WINEDDBLT_DONOTWAIT)
1158 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1159 static BOOL displayed = FALSE;
1161 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1163 Flags &= ~WINEDDBLT_DONOTWAIT;
1166 /* First, all the 'source-less' blits */
1167 if (Flags & WINEDDBLT_COLORFILL)
1169 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1170 dlock.Pitch, DDBltFx->u5.dwFillColor);
1171 Flags &= ~WINEDDBLT_COLORFILL;
1174 if (Flags & WINEDDBLT_DEPTHFILL)
1176 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1178 if (Flags & WINEDDBLT_ROP)
1180 /* Catch some degenerate cases here */
1181 switch(DDBltFx->dwROP)
1184 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1186 case 0xAA0029: /* No-op */
1189 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1191 case SRCCOPY: /* well, we do that below ? */
1194 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1197 Flags &= ~WINEDDBLT_ROP;
1199 if (Flags & WINEDDBLT_DDROPS)
1201 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1203 /* Now the 'with source' blits */
1207 int sx, xinc, sy, yinc;
1209 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1211 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1212 xinc = (srcwidth << 16) / dstwidth;
1213 yinc = (srcheight << 16) / dstheight;
1217 /* No effects, we can cheat here */
1218 if (dstwidth == srcwidth)
1220 if (dstheight == srcheight)
1222 /* No stretching in either direction. This needs to be as
1223 * fast as possible */
1226 /* check for overlapping surfaces */
1227 if (Src != This || xdst.top < xsrc.top ||
1228 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1230 /* no overlap, or dst above src, so copy from top downwards */
1231 for (y = 0; y < dstheight; y++)
1233 memcpy(dbuf, sbuf, width);
1234 sbuf += slock.Pitch;
1235 dbuf += dlock.Pitch;
1238 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1240 sbuf += (slock.Pitch*dstheight);
1241 dbuf += (dlock.Pitch*dstheight);
1242 for (y = 0; y < dstheight; y++)
1244 sbuf -= slock.Pitch;
1245 dbuf -= dlock.Pitch;
1246 memcpy(dbuf, sbuf, width);
1249 else /* src and dst overlapping on the same line, use memmove */
1251 for (y = 0; y < dstheight; y++)
1253 memmove(dbuf, sbuf, width);
1254 sbuf += slock.Pitch;
1255 dbuf += dlock.Pitch;
1259 /* Stretching in Y direction only */
1260 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1261 sbuf = sbase + (sy >> 16) * slock.Pitch;
1262 memcpy(dbuf, sbuf, width);
1263 dbuf += dlock.Pitch;
1269 /* Stretching in X direction */
1271 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1273 sbuf = sbase + (sy >> 16) * slock.Pitch;
1275 if ((sy >> 16) == (last_sy >> 16))
1277 /* this sourcerow is the same as last sourcerow -
1278 * copy already stretched row
1280 memcpy(dbuf, dbuf - dlock.Pitch, width);
1284 #define STRETCH_ROW(type) { \
1285 const type *s = (const type *)sbuf; \
1286 type *d = (type *)dbuf; \
1287 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1288 d[x] = s[sx >> 16]; \
1293 case 1: STRETCH_ROW(BYTE)
1294 case 2: STRETCH_ROW(WORD)
1295 case 4: STRETCH_ROW(DWORD)
1300 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1304 s = sbuf+3*(sx>>16);
1305 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1306 d[0] = (pixel )&0xff;
1307 d[1] = (pixel>> 8)&0xff;
1308 d[2] = (pixel>>16)&0xff;
1314 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1315 ret = WINED3DERR_NOTAVAILABLE;
1320 dbuf += dlock.Pitch;
1327 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1328 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1329 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1330 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1332 /* The color keying flags are checked for correctness in ddraw */
1333 if (Flags & WINEDDBLT_KEYSRC)
1335 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1336 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1338 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1340 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1341 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1344 if (Flags & WINEDDBLT_KEYDEST)
1346 /* Destination color keys are taken from the source surface ! */
1347 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1348 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1350 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1352 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1353 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1362 keymask = sEntry->red_mask
1363 | sEntry->green_mask
1364 | sEntry->blue_mask;
1366 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1369 if (Flags & WINEDDBLT_DDFX)
1371 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1374 dTopRight = dbuf+((dstwidth-1)*bpp);
1375 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1376 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1378 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1380 /* I don't think we need to do anything about this flag */
1381 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1383 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1386 dTopRight = dTopLeft;
1389 dBottomRight = dBottomLeft;
1391 dstxinc = dstxinc *-1;
1393 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1396 dTopLeft = dBottomLeft;
1399 dTopRight = dBottomRight;
1401 dstyinc = dstyinc *-1;
1403 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1405 /* I don't think we need to do anything about this flag */
1406 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1408 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1411 dBottomRight = dTopLeft;
1414 dBottomLeft = dTopRight;
1416 dstxinc = dstxinc * -1;
1417 dstyinc = dstyinc * -1;
1419 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1422 dTopLeft = dBottomLeft;
1423 dBottomLeft = dBottomRight;
1424 dBottomRight = dTopRight;
1429 dstxinc = dstxinc * -1;
1431 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1434 dTopLeft = dTopRight;
1435 dTopRight = dBottomRight;
1436 dBottomRight = dBottomLeft;
1441 dstyinc = dstyinc * -1;
1443 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1445 /* I don't think we need to do anything about this flag */
1446 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1449 Flags &= ~(WINEDDBLT_DDFX);
1452 #define COPY_COLORKEY_FX(type) { \
1454 type *d = (type *)dbuf, *dx, tmp; \
1455 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1456 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1458 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1459 tmp = s[sx >> 16]; \
1460 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1461 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1464 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1466 d = (type*)(((LPBYTE)d)+dstyinc); \
1471 case 1: COPY_COLORKEY_FX(BYTE)
1472 case 2: COPY_COLORKEY_FX(WORD)
1473 case 4: COPY_COLORKEY_FX(DWORD)
1477 BYTE *d = dbuf, *dx;
1478 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1480 sbuf = sbase + (sy >> 16) * slock.Pitch;
1482 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1484 DWORD pixel, dpixel = 0;
1485 s = sbuf+3*(sx>>16);
1486 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1487 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1488 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1489 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1491 dx[0] = (pixel )&0xff;
1492 dx[1] = (pixel>> 8)&0xff;
1493 dx[2] = (pixel>>16)&0xff;
1502 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1503 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1504 ret = WINED3DERR_NOTAVAILABLE;
1506 #undef COPY_COLORKEY_FX
1512 if (Flags && FIXME_ON(d3d_surface))
1514 FIXME("\tUnsupported flags: %08x\n", Flags);
1518 IWineD3DSurface_UnlockRect(iface);
1519 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1520 /* Release the converted surface if any */
1521 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1525 /*****************************************************************************
1526 * IWineD3DSurface::BltFast, SW emulation version
1528 * This is the software implementation of BltFast, as used by GDI surfaces
1529 * and as a fallback for OpenGL surfaces. This code is taken from the old
1530 * DirectDraw code, and was originally written by TransGaming.
1535 * Source: Source surface to copy from
1536 * rsrc: Source rectangle
1540 * WINED3D_OK on success
1542 *****************************************************************************/
1543 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1544 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1546 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1547 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1549 int bpp, w, h, x, y;
1550 WINED3DLOCKED_RECT dlock,slock;
1551 HRESULT ret = WINED3D_OK;
1553 RECT lock_src, lock_dst, lock_union;
1556 const struct GlPixelFormatDesc *sEntry, *dEntry;
1558 if (TRACE_ON(d3d_surface))
1560 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1564 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1565 rsrc->right,rsrc->bottom);
1569 TRACE(" srcrect: NULL\n");
1573 if ((This->Flags & SFLAG_LOCKED) ||
1574 (Src->Flags & SFLAG_LOCKED))
1576 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1577 return WINEDDERR_SURFACEBUSY;
1582 WARN("rsrc is NULL!\n");
1585 rsrc2.right = Src->currentDesc.Width;
1586 rsrc2.bottom = Src->currentDesc.Height;
1590 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1591 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1592 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1593 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1594 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1595 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1597 WARN("Application gave us bad source rectangle for BltFast.\n");
1598 return WINEDDERR_INVALIDRECT;
1601 h = rsrc->bottom - rsrc->top;
1602 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1603 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1604 if (h <= 0) return WINEDDERR_INVALIDRECT;
1606 w = rsrc->right - rsrc->left;
1607 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1608 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1609 if (w <= 0) return WINEDDERR_INVALIDRECT;
1611 /* Now compute the locking rectangle... */
1612 lock_src.left = rsrc->left;
1613 lock_src.top = rsrc->top;
1614 lock_src.right = lock_src.left + w;
1615 lock_src.bottom = lock_src.top + h;
1617 lock_dst.left = dstx;
1618 lock_dst.top = dsty;
1619 lock_dst.right = dstx + w;
1620 lock_dst.bottom = dsty + h;
1622 bpp = This->resource.format_desc->byte_count;
1624 /* We need to lock the surfaces, or we won't get refreshes when done. */
1629 UnionRect(&lock_union, &lock_src, &lock_dst);
1631 /* Lock the union of the two rectangles */
1632 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1633 if(ret != WINED3D_OK) goto error;
1635 pitch = dlock.Pitch;
1636 slock.Pitch = dlock.Pitch;
1638 /* Since slock was originally copied from this surface's description, we can just reuse it */
1639 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1640 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1641 sEntry = Src->resource.format_desc;
1646 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1647 if(ret != WINED3D_OK) goto error;
1648 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1649 if(ret != WINED3D_OK) goto error;
1653 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1655 sEntry = Src->resource.format_desc;
1656 dEntry = This->resource.format_desc;
1659 /* Handle compressed surfaces first... */
1660 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1662 UINT row_block_count;
1664 TRACE("compressed -> compressed copy\n");
1666 FIXME("trans arg not supported when a compressed surface is involved\n");
1668 FIXME("offset for destination surface is not supported\n");
1669 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1671 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1672 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1676 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1677 for (y = 0; y < h; y += dEntry->block_height)
1679 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1680 dbuf += dlock.Pitch;
1681 sbuf += slock.Pitch;
1686 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1688 /* TODO: Use the libtxc_dxtn.so shared library to do
1689 * software decompression
1691 ERR("Software decompression not supported.\n");
1695 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1697 DWORD keylow, keyhigh;
1698 TRACE("Color keyed copy\n");
1699 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1701 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1702 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1706 /* I'm not sure if this is correct */
1707 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1708 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1709 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1712 #define COPYBOX_COLORKEY(type) { \
1713 const type *s = (const type *)sbuf; \
1714 type *d = (type *)dbuf; \
1716 for (y = 0; y < h; y++) { \
1717 for (x = 0; x < w; x++) { \
1719 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1721 s = (const type *)((const BYTE *)s + slock.Pitch); \
1722 d = (type *)((BYTE *)d + dlock.Pitch); \
1728 case 1: COPYBOX_COLORKEY(BYTE)
1729 case 2: COPYBOX_COLORKEY(WORD)
1730 case 4: COPYBOX_COLORKEY(DWORD)
1738 for (y = 0; y < h; y++)
1740 for (x = 0; x < w * 3; x += 3)
1742 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1743 if (tmp < keylow || tmp > keyhigh)
1745 d[x + 0] = s[x + 0];
1746 d[x + 1] = s[x + 1];
1747 d[x + 2] = s[x + 2];
1756 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1757 ret = WINED3DERR_NOTAVAILABLE;
1760 #undef COPYBOX_COLORKEY
1761 TRACE("Copy Done\n");
1765 int width = w * bpp;
1766 INT sbufpitch, dbufpitch;
1768 TRACE("NO color key copy\n");
1769 /* Handle overlapping surfaces */
1772 sbuf += (h - 1) * slock.Pitch;
1773 dbuf += (h - 1) * dlock.Pitch;
1774 sbufpitch = -slock.Pitch;
1775 dbufpitch = -dlock.Pitch;
1779 sbufpitch = slock.Pitch;
1780 dbufpitch = dlock.Pitch;
1782 for (y = 0; y < h; y++)
1784 /* This is pretty easy, a line for line memcpy */
1785 memmove(dbuf, sbuf, width);
1789 TRACE("Copy done\n");
1795 IWineD3DSurface_UnlockRect(iface);
1799 IWineD3DSurface_UnlockRect(iface);
1800 IWineD3DSurface_UnlockRect(Source);
1806 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1808 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1810 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1811 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1813 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1817 pLockedRect->pBits = This->resource.allocatedMemory;
1818 This->lockedRect.left = 0;
1819 This->lockedRect.top = 0;
1820 This->lockedRect.right = This->currentDesc.Width;
1821 This->lockedRect.bottom = This->currentDesc.Height;
1823 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1824 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1825 This->lockedRect.right, This->lockedRect.bottom);
1829 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1831 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1832 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1834 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1836 /* Compressed textures are block based, so calculate the offset of
1837 * the block that contains the top-left pixel of the locked rectangle. */
1838 pLockedRect->pBits = This->resource.allocatedMemory
1839 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1840 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1844 pLockedRect->pBits = This->resource.allocatedMemory +
1845 (pLockedRect->Pitch * pRect->top) +
1846 (pRect->left * format_desc->byte_count);
1848 This->lockedRect.left = pRect->left;
1849 This->lockedRect.top = pRect->top;
1850 This->lockedRect.right = pRect->right;
1851 This->lockedRect.bottom = pRect->bottom;
1854 /* No dirtifying is needed for this surface implementation */
1855 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1860 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1861 ERR("Should not be called on base texture\n");
1865 /* TODO: think about moving this down to resource? */
1866 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1868 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1870 /* This should only be called for sysmem textures, it may be a good idea
1871 * to extend this to all pools at some point in the future */
1872 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1874 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1876 return This->resource.allocatedMemory;