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
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
35 /* See also float_16_to_32() in wined3d_private.h */
36 static inline unsigned short float_32_to_16(const float *in)
39 float tmp = fabs(*in);
40 unsigned int mantissa;
43 /* Deal with special numbers */
44 if (*in == 0.0f) return 0x0000;
45 if(isnan(*in)) return 0x7C01;
46 if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
48 if(tmp < pow(2, 10)) {
53 }while(tmp < pow(2, 10));
54 } else if(tmp >= pow(2, 11)) {
59 }while(tmp >= pow(2, 11));
62 mantissa = (unsigned int) tmp;
63 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
65 exp += 10; /* Normalize the mantissa */
66 exp += 15; /* Exponent is encoded with excess 15 */
68 if(exp > 30) { /* too big */
69 ret = 0x7c00; /* INF */
71 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
73 mantissa = mantissa >> 1;
76 ret = mantissa & 0x3ff;
78 ret = (exp << 10) | (mantissa & 0x3ff);
81 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
86 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
88 /* *******************************************
89 IWineD3DSurface IUnknown parts follow
90 ******************************************* */
91 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
93 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
94 /* Warn ,but be nice about things */
95 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
97 if (IsEqualGUID(riid, &IID_IUnknown)
98 || IsEqualGUID(riid, &IID_IWineD3DBase)
99 || IsEqualGUID(riid, &IID_IWineD3DResource)
100 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
101 IUnknown_AddRef((IUnknown*)iface);
106 return E_NOINTERFACE;
109 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
110 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
111 ULONG ref = InterlockedIncrement(&This->resource.ref);
112 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
116 /* ****************************************************
117 IWineD3DSurface IWineD3DResource parts follow
118 **************************************************** */
119 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
120 return resource_get_device((IWineD3DResource *)iface, ppDevice);
123 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
124 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
127 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
128 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
131 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
132 return resource_free_private_data((IWineD3DResource *)iface, refguid);
135 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
136 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
139 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
140 return resource_get_priority((IWineD3DResource *)iface);
143 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
144 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
145 return resource_get_type((IWineD3DResource *)iface);
148 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
149 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
150 return resource_get_parent((IWineD3DResource *)iface, pParent);
153 /* ******************************************************
154 IWineD3DSurface IWineD3DSurface parts follow
155 ****************************************************** */
157 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
158 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
159 IWineD3DBase *container = 0;
161 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
164 ERR("Called without a valid ppContainer.\n");
167 /* Standalone surfaces return the device as container. */
168 if (This->container) {
169 container = This->container;
171 container = (IWineD3DBase *)This->resource.wineD3DDevice;
174 TRACE("Relaying to QueryInterface\n");
175 return IUnknown_QueryInterface(container, riid, ppContainer);
178 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
179 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
181 TRACE("(%p) : copying into %p\n", This, pDesc);
183 pDesc->format = This->resource.format_desc->format;
184 pDesc->resource_type = This->resource.resourceType;
185 pDesc->usage = This->resource.usage;
186 pDesc->pool = This->resource.pool;
187 pDesc->size = This->resource.size; /* dx8 only */
188 pDesc->multisample_type = This->currentDesc.MultiSampleType;
189 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
190 pDesc->width = This->currentDesc.Width;
191 pDesc->height = This->currentDesc.Height;
196 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
197 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
198 TRACE("(%p)->(%x)\n", This, Flags);
202 case WINEDDGBS_CANBLT:
203 case WINEDDGBS_ISBLTDONE:
207 return WINED3DERR_INVALIDCALL;
211 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
212 /* XXX: DDERR_INVALIDSURFACETYPE */
214 TRACE("(%p)->(%08x)\n",iface,Flags);
216 case WINEDDGFS_CANFLIP:
217 case WINEDDGFS_ISFLIPDONE:
221 return WINED3DERR_INVALIDCALL;
225 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
226 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
227 TRACE("(%p)\n", This);
229 /* D3D8 and 9 loose full devices, ddraw only surfaces */
230 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
234 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235 TRACE("(%p)\n", This);
237 /* So far we don't lose anything :) */
238 This->Flags &= ~SFLAG_LOST;
242 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
243 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
244 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
245 TRACE("(%p)->(%p)\n", This, Pal);
247 if(This->palette == PalImpl) {
248 TRACE("Nop palette change\n");
252 if(This->palette != NULL)
253 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
254 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
256 This->palette = PalImpl;
258 if(PalImpl != NULL) {
259 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
260 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
263 return IWineD3DSurface_RealizePalette(iface);
265 else return WINED3D_OK;
268 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
270 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
271 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
273 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
274 FIXME(" colorkey value not supported (%08x) !\n", Flags);
275 return WINED3DERR_INVALIDCALL;
278 /* Dirtify the surface, but only if a key was changed */
280 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
281 case WINEDDCKEY_DESTBLT:
282 This->DestBltCKey = *CKey;
283 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
286 case WINEDDCKEY_DESTOVERLAY:
287 This->DestOverlayCKey = *CKey;
288 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
291 case WINEDDCKEY_SRCOVERLAY:
292 This->SrcOverlayCKey = *CKey;
293 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
296 case WINEDDCKEY_SRCBLT:
297 This->SrcBltCKey = *CKey;
298 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
303 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
304 case WINEDDCKEY_DESTBLT:
305 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
308 case WINEDDCKEY_DESTOVERLAY:
309 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
312 case WINEDDCKEY_SRCOVERLAY:
313 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
316 case WINEDDCKEY_SRCBLT:
317 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
325 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
326 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
327 TRACE("(%p)->(%p)\n", This, Pal);
329 *Pal = (IWineD3DPalette *) This->palette;
333 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
334 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
335 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
337 TRACE("(%p)\n", This);
339 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
341 /* Since compressed formats are block based, pitch means the amount of
342 * bytes to the next row of block rather than the next row of pixels. */
343 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
344 ret = row_block_count * format_desc->block_byte_count;
348 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
349 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
350 ret = (ret + alignment - 1) & ~(alignment - 1);
352 TRACE("(%p) Returning %d\n", This, ret);
356 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
357 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
360 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
362 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
364 TRACE("(%p): Not an overlay surface\n", This);
365 return WINEDDERR_NOTAOVERLAYSURFACE;
368 w = This->overlay_destrect.right - This->overlay_destrect.left;
369 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
370 This->overlay_destrect.left = X;
371 This->overlay_destrect.top = Y;
372 This->overlay_destrect.right = X + w;
373 This->overlay_destrect.bottom = Y + h;
375 IWineD3DSurface_DrawOverlay(iface);
380 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
381 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
384 TRACE("(%p)->(%p,%p)\n", This, X, Y);
386 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
388 TRACE("(%p): Not an overlay surface\n", This);
389 return WINEDDERR_NOTAOVERLAYSURFACE;
391 if(This->overlay_dest == NULL) {
393 hr = WINEDDERR_OVERLAYNOTVISIBLE;
395 *X = This->overlay_destrect.left;
396 *Y = This->overlay_destrect.top;
400 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
404 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
406 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
408 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
410 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
412 TRACE("(%p): Not an overlay surface\n", This);
413 return WINEDDERR_NOTAOVERLAYSURFACE;
419 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
420 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
422 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
423 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
424 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
426 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
428 WARN("(%p): Not an overlay surface\n", This);
429 return WINEDDERR_NOTAOVERLAYSURFACE;
430 } else if(!DstSurface) {
431 WARN("(%p): Dest surface is NULL\n", This);
432 return WINED3DERR_INVALIDCALL;
436 This->overlay_srcrect = *SrcRect;
438 This->overlay_srcrect.left = 0;
439 This->overlay_srcrect.top = 0;
440 This->overlay_srcrect.right = This->currentDesc.Width;
441 This->overlay_srcrect.bottom = This->currentDesc.Height;
445 This->overlay_destrect = *DstRect;
447 This->overlay_destrect.left = 0;
448 This->overlay_destrect.top = 0;
449 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
450 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
453 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
454 list_remove(&This->overlay_entry);
457 if(Flags & WINEDDOVER_SHOW) {
458 if(This->overlay_dest != Dst) {
459 This->overlay_dest = Dst;
460 list_add_tail(&Dst->overlays, &This->overlay_entry);
462 } else if(Flags & WINEDDOVER_HIDE) {
463 /* tests show that the rectangles are erased on hide */
464 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
465 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
466 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
467 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
468 This->overlay_dest = NULL;
471 IWineD3DSurface_DrawOverlay(iface);
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 This->clipper = clipper;
485 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
487 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
488 TRACE("(%p)->(%p)\n", This, clipper);
490 *clipper = This->clipper;
492 IWineD3DClipper_AddRef(*clipper);
497 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
498 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
500 TRACE("This %p, container %p\n", This, container);
502 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
504 TRACE("Setting container to %p from %p\n", container, This->container);
505 This->container = container;
510 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
511 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
512 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
513 &This->resource.wineD3DDevice->adapter->gl_info);
515 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
517 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
518 return WINED3DERR_INVALIDCALL;
521 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
523 This->resource.size = surface_calculate_size(format_desc, This->resource.wineD3DDevice->surface_alignment,
524 This->pow2Width, This->pow2Height);
526 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
528 This->resource.format_desc = format_desc;
530 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
535 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
536 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
537 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
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_R8G8B8:
596 usage = DIB_RGB_COLORS;
597 b_info->bmiHeader.biCompression = BI_RGB;
600 case WINED3DFMT_X1R5G5B5:
601 case WINED3DFMT_A1R5G5B5:
602 case WINED3DFMT_A4R4G4B4:
603 case WINED3DFMT_X4R4G4B4:
604 case WINED3DFMT_R3G3B2:
605 case WINED3DFMT_A8R3G3B2:
606 case WINED3DFMT_R10G10B10A2_UNORM:
607 case WINED3DFMT_R8G8B8A8_UNORM:
608 case WINED3DFMT_X8B8G8R8:
609 case WINED3DFMT_A2R10G10B10:
610 case WINED3DFMT_R5G6B5:
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_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
755 {WINED3DFMT_A8R8G8B8, WINED3DFMT_X8R8G8B8, 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.wineD3DDevice, 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), NULL /* parent */);
798 ERR("Failed to create a destination surface for conversion\n");
802 memset(&lock_src, 0, sizeof(lock_src));
803 memset(&lock_dst, 0, sizeof(lock_dst));
805 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
807 ERR("Failed to lock the source surface\n");
808 IWineD3DSurface_Release(ret);
811 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
813 ERR("Failed to lock the dest surface\n");
814 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
815 IWineD3DSurface_Release(ret);
819 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
820 source->currentDesc.Width, source->currentDesc.Height);
822 IWineD3DSurface_UnlockRect(ret);
823 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
825 return (IWineD3DSurfaceImpl *) ret;
828 /*****************************************************************************
831 * Helper function that fills a memory area with a specific color
834 * buf: memory address to start filling at
835 * width, height: Dimensions of the area to fill
836 * bpp: Bit depth of the surface
837 * lPitch: pitch of the surface
838 * color: Color to fill with
840 *****************************************************************************/
842 _Blt_ColorFill(BYTE *buf,
843 int width, int height,
844 int bpp, LONG lPitch,
852 #define COLORFILL_ROW(type) \
854 type *d = (type *) buf; \
855 for (x = 0; x < width; x++) \
856 d[x] = (type) color; \
861 case 1: COLORFILL_ROW(BYTE)
862 case 2: COLORFILL_ROW(WORD)
866 for (x = 0; x < width; x++,d+=3)
868 d[0] = (color ) & 0xFF;
869 d[1] = (color>> 8) & 0xFF;
870 d[2] = (color>>16) & 0xFF;
874 case 4: COLORFILL_ROW(DWORD)
876 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
877 return WINED3DERR_NOTAVAILABLE;
882 /* Now copy first row */
884 for (y = 1; y < height; y++)
887 memcpy(buf, first, width * bpp);
892 /*****************************************************************************
893 * IWineD3DSurface::Blt, SW emulation version
895 * Performs blits to a surface, eigher from a source of source-less blts
896 * This is the main functionality of DirectDraw
899 * DestRect: Destination rectangle to write to
900 * SrcSurface: Source surface, can be NULL
901 * SrcRect: Source rectangle
902 *****************************************************************************/
903 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
904 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
906 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
907 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
909 HRESULT ret = WINED3D_OK;
910 WINED3DLOCKED_RECT dlock, slock;
911 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
912 const struct GlPixelFormatDesc *sEntry, *dEntry;
916 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
918 if (TRACE_ON(d3d_surface))
920 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
921 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
922 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
923 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
926 DDRAW_dump_DDBLT(Flags);
927 if (Flags & WINEDDBLT_DDFX)
930 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
935 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
937 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
938 return WINEDDERR_SURFACEBUSY;
941 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
942 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
943 FIXME("Filters not supported in software blit\n");
946 /* First check for the validity of source / destination rectangles. This was
947 * verified using a test application + by MSDN.
949 if ((Src != NULL) && (SrcRect != NULL) &&
950 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
951 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
952 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
953 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
954 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
956 WARN("Application gave us bad source rectangle for Blt.\n");
957 return WINEDDERR_INVALIDRECT;
959 /* For the Destination rect, it can be out of bounds on the condition that a clipper
960 * is set for the given surface.
962 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
963 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
964 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
965 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
966 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
967 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
969 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
970 return WINEDDERR_INVALIDRECT;
973 /* Now handle negative values in the rectangles. Warning: only supported for now
974 in the 'simple' cases (ie not in any stretching / rotation cases).
976 First, the case where nothing is to be done.
978 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
979 (DestRect->top >= (int) This->currentDesc.Height) ||
980 (DestRect->left >= (int) This->currentDesc.Width))) ||
981 ((Src != NULL) && (SrcRect != NULL) &&
982 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
983 (SrcRect->top >= (int) Src->currentDesc.Height) ||
984 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
986 TRACE("Nothing to be done !\n");
997 xdst.bottom = This->currentDesc.Height;
999 xdst.right = This->currentDesc.Width;
1011 xsrc.bottom = Src->currentDesc.Height;
1013 xsrc.right = Src->currentDesc.Width;
1017 memset(&xsrc,0,sizeof(xsrc));
1021 /* The easy case : the source-less blits.... */
1022 if (Src == NULL && DestRect)
1025 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1029 full_rect.right = This->currentDesc.Width;
1030 full_rect.bottom = This->currentDesc.Height;
1031 IntersectRect(&temp_rect, &full_rect, DestRect);
1036 /* Only handle clipping on the destination rectangle */
1037 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1038 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1039 if (clip_vert || clip_horiz)
1041 /* Now check if this is a special case or not... */
1042 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1043 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1044 (Flags & WINEDDBLT_DDFX))
1046 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1052 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1053 if (DestRect->right > This->currentDesc.Width)
1055 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1056 xdst.right = (int) This->currentDesc.Width;
1061 if (DestRect->top < 0)
1063 xsrc.top -= DestRect->top;
1066 if (DestRect->bottom > This->currentDesc.Height)
1068 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1069 xdst.bottom = (int) This->currentDesc.Height;
1072 /* And check if after clipping something is still to be done... */
1073 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1074 (xdst.top >= (int) This->currentDesc.Height) ||
1075 (xdst.left >= (int) This->currentDesc.Width) ||
1076 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1077 (xsrc.top >= (int) Src->currentDesc.Height) ||
1078 (xsrc.left >= (int) Src->currentDesc.Width))
1080 TRACE("Nothing to be done after clipping !\n");
1088 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1090 sEntry = This->resource.format_desc;
1095 dEntry = This->resource.format_desc;
1098 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1100 Src = surface_convert_format(Src, dEntry->format);
1102 /* The conv function writes a FIXME */
1103 WARN("Cannot convert source surface format to dest format\n");
1107 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1108 sEntry = Src->resource.format_desc;
1115 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1117 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1120 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1122 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1124 if (!DestRect || Src == This)
1126 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1131 bpp = This->resource.format_desc->byte_count;
1132 srcheight = xsrc.bottom - xsrc.top;
1133 srcwidth = xsrc.right - xsrc.left;
1134 dstheight = xdst.bottom - xdst.top;
1135 dstwidth = xdst.right - xdst.left;
1136 width = (xdst.right - xdst.left) * bpp;
1138 if (DestRect && Src != This)
1141 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1143 if (Flags & WINEDDBLT_WAIT)
1145 Flags &= ~WINEDDBLT_WAIT;
1147 if (Flags & WINEDDBLT_ASYNC)
1149 static BOOL displayed = FALSE;
1151 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1153 Flags &= ~WINEDDBLT_ASYNC;
1155 if (Flags & WINEDDBLT_DONOTWAIT)
1157 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1158 static BOOL displayed = FALSE;
1160 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1162 Flags &= ~WINEDDBLT_DONOTWAIT;
1165 /* First, all the 'source-less' blits */
1166 if (Flags & WINEDDBLT_COLORFILL)
1168 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1169 dlock.Pitch, DDBltFx->u5.dwFillColor);
1170 Flags &= ~WINEDDBLT_COLORFILL;
1173 if (Flags & WINEDDBLT_DEPTHFILL)
1175 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1177 if (Flags & WINEDDBLT_ROP)
1179 /* Catch some degenerate cases here */
1180 switch(DDBltFx->dwROP)
1183 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1185 case 0xAA0029: /* No-op */
1188 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1190 case SRCCOPY: /* well, we do that below ? */
1193 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1196 Flags &= ~WINEDDBLT_ROP;
1198 if (Flags & WINEDDBLT_DDROPS)
1200 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1202 /* Now the 'with source' blits */
1206 int sx, xinc, sy, yinc;
1208 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1210 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1211 xinc = (srcwidth << 16) / dstwidth;
1212 yinc = (srcheight << 16) / dstheight;
1216 /* No effects, we can cheat here */
1217 if (dstwidth == srcwidth)
1219 if (dstheight == srcheight)
1221 /* No stretching in either direction. This needs to be as
1222 * fast as possible */
1225 /* check for overlapping surfaces */
1226 if (Src != This || xdst.top < xsrc.top ||
1227 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1229 /* no overlap, or dst above src, so copy from top downwards */
1230 for (y = 0; y < dstheight; y++)
1232 memcpy(dbuf, sbuf, width);
1233 sbuf += slock.Pitch;
1234 dbuf += dlock.Pitch;
1237 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1239 sbuf += (slock.Pitch*dstheight);
1240 dbuf += (dlock.Pitch*dstheight);
1241 for (y = 0; y < dstheight; y++)
1243 sbuf -= slock.Pitch;
1244 dbuf -= dlock.Pitch;
1245 memcpy(dbuf, sbuf, width);
1248 else /* src and dst overlapping on the same line, use memmove */
1250 for (y = 0; y < dstheight; y++)
1252 memmove(dbuf, sbuf, width);
1253 sbuf += slock.Pitch;
1254 dbuf += dlock.Pitch;
1258 /* Stretching in Y direction only */
1259 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1260 sbuf = sbase + (sy >> 16) * slock.Pitch;
1261 memcpy(dbuf, sbuf, width);
1262 dbuf += dlock.Pitch;
1268 /* Stretching in X direction */
1270 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1272 sbuf = sbase + (sy >> 16) * slock.Pitch;
1274 if ((sy >> 16) == (last_sy >> 16))
1276 /* this sourcerow is the same as last sourcerow -
1277 * copy already stretched row
1279 memcpy(dbuf, dbuf - dlock.Pitch, width);
1283 #define STRETCH_ROW(type) { \
1284 const type *s = (const type *)sbuf; \
1285 type *d = (type *)dbuf; \
1286 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1287 d[x] = s[sx >> 16]; \
1292 case 1: STRETCH_ROW(BYTE)
1293 case 2: STRETCH_ROW(WORD)
1294 case 4: STRETCH_ROW(DWORD)
1299 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1303 s = sbuf+3*(sx>>16);
1304 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1305 d[0] = (pixel )&0xff;
1306 d[1] = (pixel>> 8)&0xff;
1307 d[2] = (pixel>>16)&0xff;
1313 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1314 ret = WINED3DERR_NOTAVAILABLE;
1319 dbuf += dlock.Pitch;
1326 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1327 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1328 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1329 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1331 /* The color keying flags are checked for correctness in ddraw */
1332 if (Flags & WINEDDBLT_KEYSRC)
1334 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1335 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1337 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1339 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1340 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1343 if (Flags & WINEDDBLT_KEYDEST)
1345 /* Destination color keys are taken from the source surface ! */
1346 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1347 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1349 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1351 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1352 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1361 keymask = sEntry->red_mask
1362 | sEntry->green_mask
1363 | sEntry->blue_mask;
1365 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1368 if (Flags & WINEDDBLT_DDFX)
1370 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1373 dTopRight = dbuf+((dstwidth-1)*bpp);
1374 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1375 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1377 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1379 /* I don't think we need to do anything about this flag */
1380 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1382 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1385 dTopRight = dTopLeft;
1388 dBottomRight = dBottomLeft;
1390 dstxinc = dstxinc *-1;
1392 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1395 dTopLeft = dBottomLeft;
1398 dTopRight = dBottomRight;
1400 dstyinc = dstyinc *-1;
1402 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1404 /* I don't think we need to do anything about this flag */
1405 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1407 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1410 dBottomRight = dTopLeft;
1413 dBottomLeft = dTopRight;
1415 dstxinc = dstxinc * -1;
1416 dstyinc = dstyinc * -1;
1418 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1421 dTopLeft = dBottomLeft;
1422 dBottomLeft = dBottomRight;
1423 dBottomRight = dTopRight;
1428 dstxinc = dstxinc * -1;
1430 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1433 dTopLeft = dTopRight;
1434 dTopRight = dBottomRight;
1435 dBottomRight = dBottomLeft;
1440 dstyinc = dstyinc * -1;
1442 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1444 /* I don't think we need to do anything about this flag */
1445 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1448 Flags &= ~(WINEDDBLT_DDFX);
1451 #define COPY_COLORKEY_FX(type) { \
1453 type *d = (type *)dbuf, *dx, tmp; \
1454 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1455 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1457 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1458 tmp = s[sx >> 16]; \
1459 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1460 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1463 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1465 d = (type*)(((LPBYTE)d)+dstyinc); \
1470 case 1: COPY_COLORKEY_FX(BYTE)
1471 case 2: COPY_COLORKEY_FX(WORD)
1472 case 4: COPY_COLORKEY_FX(DWORD)
1476 BYTE *d = dbuf, *dx;
1477 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1479 sbuf = sbase + (sy >> 16) * slock.Pitch;
1481 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1483 DWORD pixel, dpixel = 0;
1484 s = sbuf+3*(sx>>16);
1485 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1486 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1487 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1488 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1490 dx[0] = (pixel )&0xff;
1491 dx[1] = (pixel>> 8)&0xff;
1492 dx[2] = (pixel>>16)&0xff;
1501 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1502 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1503 ret = WINED3DERR_NOTAVAILABLE;
1505 #undef COPY_COLORKEY_FX
1511 if (Flags && FIXME_ON(d3d_surface))
1513 FIXME("\tUnsupported flags: %08x\n", Flags);
1517 IWineD3DSurface_UnlockRect(iface);
1518 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1519 /* Release the converted surface if any */
1520 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1524 /*****************************************************************************
1525 * IWineD3DSurface::BltFast, SW emulation version
1527 * This is the software implementation of BltFast, as used by GDI surfaces
1528 * and as a fallback for OpenGL surfaces. This code is taken from the old
1529 * DirectDraw code, and was originally written by TransGaming.
1534 * Source: Source surface to copy from
1535 * rsrc: Source rectangle
1539 * WINED3D_OK on success
1541 *****************************************************************************/
1542 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1543 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1545 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1546 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1548 int bpp, w, h, x, y;
1549 WINED3DLOCKED_RECT dlock,slock;
1550 HRESULT ret = WINED3D_OK;
1552 RECT lock_src, lock_dst, lock_union;
1555 const struct GlPixelFormatDesc *sEntry, *dEntry;
1557 if (TRACE_ON(d3d_surface))
1559 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1563 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1564 rsrc->right,rsrc->bottom);
1568 TRACE(" srcrect: NULL\n");
1572 if ((This->Flags & SFLAG_LOCKED) ||
1573 (Src->Flags & SFLAG_LOCKED))
1575 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1576 return WINEDDERR_SURFACEBUSY;
1581 WARN("rsrc is NULL!\n");
1584 rsrc2.right = Src->currentDesc.Width;
1585 rsrc2.bottom = Src->currentDesc.Height;
1589 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1590 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1591 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1592 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1593 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1594 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1596 WARN("Application gave us bad source rectangle for BltFast.\n");
1597 return WINEDDERR_INVALIDRECT;
1600 h = rsrc->bottom - rsrc->top;
1601 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1602 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1603 if (h <= 0) return WINEDDERR_INVALIDRECT;
1605 w = rsrc->right - rsrc->left;
1606 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1607 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1608 if (w <= 0) return WINEDDERR_INVALIDRECT;
1610 /* Now compute the locking rectangle... */
1611 lock_src.left = rsrc->left;
1612 lock_src.top = rsrc->top;
1613 lock_src.right = lock_src.left + w;
1614 lock_src.bottom = lock_src.top + h;
1616 lock_dst.left = dstx;
1617 lock_dst.top = dsty;
1618 lock_dst.right = dstx + w;
1619 lock_dst.bottom = dsty + h;
1621 bpp = This->resource.format_desc->byte_count;
1623 /* We need to lock the surfaces, or we won't get refreshes when done. */
1628 UnionRect(&lock_union, &lock_src, &lock_dst);
1630 /* Lock the union of the two rectangles */
1631 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1632 if(ret != WINED3D_OK) goto error;
1634 pitch = dlock.Pitch;
1635 slock.Pitch = dlock.Pitch;
1637 /* Since slock was originally copied from this surface's description, we can just reuse it */
1638 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1639 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1640 sEntry = Src->resource.format_desc;
1645 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1646 if(ret != WINED3D_OK) goto error;
1647 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1648 if(ret != WINED3D_OK) goto error;
1652 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1654 sEntry = Src->resource.format_desc;
1655 dEntry = This->resource.format_desc;
1658 /* Handle compressed surfaces first... */
1659 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1661 UINT row_block_count;
1663 TRACE("compressed -> compressed copy\n");
1665 FIXME("trans arg not supported when a compressed surface is involved\n");
1667 FIXME("offset for destination surface is not supported\n");
1668 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1670 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1671 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1675 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1676 for (y = 0; y < h; y += dEntry->block_height)
1678 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1679 dbuf += dlock.Pitch;
1680 sbuf += slock.Pitch;
1685 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1687 /* TODO: Use the libtxc_dxtn.so shared library to do
1688 * software decompression
1690 ERR("Software decompression not supported.\n");
1694 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1696 DWORD keylow, keyhigh;
1697 TRACE("Color keyed copy\n");
1698 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1700 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1701 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1705 /* I'm not sure if this is correct */
1706 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1707 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1708 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1711 #define COPYBOX_COLORKEY(type) { \
1712 const type *s = (const type *)sbuf; \
1713 type *d = (type *)dbuf; \
1715 for (y = 0; y < h; y++) { \
1716 for (x = 0; x < w; x++) { \
1718 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1720 s = (const type *)((const BYTE *)s + slock.Pitch); \
1721 d = (type *)((BYTE *)d + dlock.Pitch); \
1727 case 1: COPYBOX_COLORKEY(BYTE)
1728 case 2: COPYBOX_COLORKEY(WORD)
1729 case 4: COPYBOX_COLORKEY(DWORD)
1737 for (y = 0; y < h; y++)
1739 for (x = 0; x < w * 3; x += 3)
1741 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1742 if (tmp < keylow || tmp > keyhigh)
1744 d[x + 0] = s[x + 0];
1745 d[x + 1] = s[x + 1];
1746 d[x + 2] = s[x + 2];
1755 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1756 ret = WINED3DERR_NOTAVAILABLE;
1759 #undef COPYBOX_COLORKEY
1760 TRACE("Copy Done\n");
1764 int width = w * bpp;
1765 INT sbufpitch, dbufpitch;
1767 TRACE("NO color key copy\n");
1768 /* Handle overlapping surfaces */
1771 sbuf += (h - 1) * slock.Pitch;
1772 dbuf += (h - 1) * dlock.Pitch;
1773 sbufpitch = -slock.Pitch;
1774 dbufpitch = -dlock.Pitch;
1778 sbufpitch = slock.Pitch;
1779 dbufpitch = dlock.Pitch;
1781 for (y = 0; y < h; y++)
1783 /* This is pretty easy, a line for line memcpy */
1784 memmove(dbuf, sbuf, width);
1788 TRACE("Copy done\n");
1794 IWineD3DSurface_UnlockRect(iface);
1798 IWineD3DSurface_UnlockRect(iface);
1799 IWineD3DSurface_UnlockRect(Source);
1805 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1807 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1809 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1810 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1812 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1816 pLockedRect->pBits = This->resource.allocatedMemory;
1817 This->lockedRect.left = 0;
1818 This->lockedRect.top = 0;
1819 This->lockedRect.right = This->currentDesc.Width;
1820 This->lockedRect.bottom = This->currentDesc.Height;
1822 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1823 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1824 This->lockedRect.right, This->lockedRect.bottom);
1828 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1830 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1831 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1833 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1835 /* Compressed textures are block based, so calculate the offset of
1836 * the block that contains the top-left pixel of the locked rectangle. */
1837 pLockedRect->pBits = This->resource.allocatedMemory
1838 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1839 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1843 pLockedRect->pBits = This->resource.allocatedMemory +
1844 (pLockedRect->Pitch * pRect->top) +
1845 (pRect->left * format_desc->byte_count);
1847 This->lockedRect.left = pRect->left;
1848 This->lockedRect.top = pRect->top;
1849 This->lockedRect.right = pRect->right;
1850 This->lockedRect.bottom = pRect->bottom;
1853 /* No dirtifying is needed for this surface implementation */
1854 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1859 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1860 ERR("Should not be called on base texture\n");
1864 /* TODO: think about moving this down to resource? */
1865 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1867 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1869 /* This should only be called for sysmem textures, it may be a good idea
1870 * to extend this to all pools at some point in the future */
1871 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1873 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1875 return This->resource.allocatedMemory;