2 * IWineD3DSurface Implementation of management(non-rendering) functions
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in)
40 float tmp = fabs(*in);
41 unsigned int mantissa;
44 /* Deal with special numbers */
45 if (*in == 0.0f) return 0x0000;
46 if(isnan(*in)) return 0x7C01;
47 if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
49 if(tmp < powf(2, 10)) {
54 }while(tmp < powf(2, 10));
55 } else if(tmp >= powf(2, 11)) {
60 }while(tmp >= powf(2, 11));
63 mantissa = (unsigned int) tmp;
64 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
66 exp += 10; /* Normalize the mantissa */
67 exp += 15; /* Exponent is encoded with excess 15 */
69 if(exp > 30) { /* too big */
70 ret = 0x7c00; /* INF */
72 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
74 mantissa = mantissa >> 1;
77 ret = mantissa & 0x3ff;
79 ret = (exp << 10) | (mantissa & 0x3ff);
82 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
86 /* *******************************************
87 IWineD3DSurface IUnknown parts follow
88 ******************************************* */
89 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
91 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
92 /* Warn ,but be nice about things */
93 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
95 if (IsEqualGUID(riid, &IID_IUnknown)
96 || IsEqualGUID(riid, &IID_IWineD3DBase)
97 || IsEqualGUID(riid, &IID_IWineD3DResource)
98 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
99 IUnknown_AddRef((IUnknown*)iface);
104 return E_NOINTERFACE;
107 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
109 ULONG ref = InterlockedIncrement(&This->resource.ref);
110 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
114 /* ****************************************************
115 IWineD3DSurface IWineD3DResource parts follow
116 **************************************************** */
117 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
118 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
122 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
126 return resource_free_private_data((IWineD3DResource *)iface, refguid);
129 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
130 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
133 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
134 return resource_get_priority((IWineD3DResource *)iface);
137 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
138 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
139 return resource_get_type((IWineD3DResource *)iface);
142 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
143 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
144 return resource_get_parent((IWineD3DResource *)iface, pParent);
147 /* ******************************************************
148 IWineD3DSurface IWineD3DSurface parts follow
149 ****************************************************** */
151 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
152 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
153 IWineD3DBase *container = 0;
155 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
158 ERR("Called without a valid ppContainer.\n");
161 /* Standalone surfaces return the device as container. */
162 if (This->container.u.base) container = This->container.u.base;
163 else container = (IWineD3DBase *)This->resource.device;
165 TRACE("Relaying to QueryInterface\n");
166 return IUnknown_QueryInterface(container, riid, ppContainer);
169 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
170 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
172 TRACE("(%p) : copying into %p\n", This, pDesc);
174 pDesc->format = This->resource.format_desc->format;
175 pDesc->resource_type = This->resource.resourceType;
176 pDesc->usage = This->resource.usage;
177 pDesc->pool = This->resource.pool;
178 pDesc->size = This->resource.size; /* dx8 only */
179 pDesc->multisample_type = This->currentDesc.MultiSampleType;
180 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
181 pDesc->width = This->currentDesc.Width;
182 pDesc->height = This->currentDesc.Height;
187 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
189 TRACE("iface %p, flags %#x.\n", iface, Flags);
193 case WINEDDGBS_CANBLT:
194 case WINEDDGBS_ISBLTDONE:
198 return WINED3DERR_INVALIDCALL;
202 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
203 /* XXX: DDERR_INVALIDSURFACETYPE */
205 TRACE("(%p)->(%08x)\n",iface,Flags);
207 case WINEDDGFS_CANFLIP:
208 case WINEDDGFS_ISFLIPDONE:
212 return WINED3DERR_INVALIDCALL;
216 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
217 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
218 TRACE("(%p)\n", This);
220 /* D3D8 and 9 loose full devices, ddraw only surfaces */
221 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
224 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
225 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
226 TRACE("(%p)\n", This);
228 /* So far we don't lose anything :) */
229 This->Flags &= ~SFLAG_LOST;
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
234 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
236 TRACE("(%p)->(%p)\n", This, Pal);
238 if(This->palette == PalImpl) {
239 TRACE("Nop palette change\n");
243 if(This->palette != NULL)
244 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
245 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
247 This->palette = PalImpl;
249 if(PalImpl != NULL) {
250 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
251 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
254 return IWineD3DSurface_RealizePalette(iface);
256 else return WINED3D_OK;
259 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
261 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
262 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
264 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
265 FIXME(" colorkey value not supported (%08x) !\n", Flags);
266 return WINED3DERR_INVALIDCALL;
269 /* Dirtify the surface, but only if a key was changed */
271 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
272 case WINEDDCKEY_DESTBLT:
273 This->DestBltCKey = *CKey;
274 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
277 case WINEDDCKEY_DESTOVERLAY:
278 This->DestOverlayCKey = *CKey;
279 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
282 case WINEDDCKEY_SRCOVERLAY:
283 This->SrcOverlayCKey = *CKey;
284 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
287 case WINEDDCKEY_SRCBLT:
288 This->SrcBltCKey = *CKey;
289 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
294 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
295 case WINEDDCKEY_DESTBLT:
296 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
299 case WINEDDCKEY_DESTOVERLAY:
300 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
303 case WINEDDCKEY_SRCOVERLAY:
304 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
307 case WINEDDCKEY_SRCBLT:
308 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
316 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
317 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
318 TRACE("(%p)->(%p)\n", This, Pal);
320 *Pal = (IWineD3DPalette *) This->palette;
324 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
325 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
326 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
328 TRACE("(%p)\n", This);
330 if ((format_desc->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH))
331 == WINED3DFMT_FLAG_COMPRESSED)
333 /* Since compressed formats are block based, pitch means the amount of
334 * bytes to the next row of block rather than the next row of pixels. */
335 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
336 ret = row_block_count * format_desc->block_byte_count;
340 unsigned char alignment = This->resource.device->surface_alignment;
341 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
342 ret = (ret + alignment - 1) & ~(alignment - 1);
344 TRACE("(%p) Returning %d\n", This, ret);
348 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
349 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
352 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
354 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
356 TRACE("(%p): Not an overlay surface\n", This);
357 return WINEDDERR_NOTAOVERLAYSURFACE;
360 w = This->overlay_destrect.right - This->overlay_destrect.left;
361 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
362 This->overlay_destrect.left = X;
363 This->overlay_destrect.top = Y;
364 This->overlay_destrect.right = X + w;
365 This->overlay_destrect.bottom = Y + h;
367 IWineD3DSurface_DrawOverlay(iface);
372 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
373 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
376 TRACE("(%p)->(%p,%p)\n", This, X, Y);
378 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
380 TRACE("(%p): Not an overlay surface\n", This);
381 return WINEDDERR_NOTAOVERLAYSURFACE;
383 if(This->overlay_dest == NULL) {
385 hr = WINEDDERR_OVERLAYNOTVISIBLE;
387 *X = This->overlay_destrect.left;
388 *Y = This->overlay_destrect.top;
392 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
396 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
397 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
399 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
401 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
403 TRACE("(%p): Not an overlay surface\n", This);
404 return WINEDDERR_NOTAOVERLAYSURFACE;
410 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
411 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
413 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
414 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
415 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
417 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
419 WARN("(%p): Not an overlay surface\n", This);
420 return WINEDDERR_NOTAOVERLAYSURFACE;
421 } else if(!DstSurface) {
422 WARN("(%p): Dest surface is NULL\n", This);
423 return WINED3DERR_INVALIDCALL;
427 This->overlay_srcrect = *SrcRect;
429 This->overlay_srcrect.left = 0;
430 This->overlay_srcrect.top = 0;
431 This->overlay_srcrect.right = This->currentDesc.Width;
432 This->overlay_srcrect.bottom = This->currentDesc.Height;
436 This->overlay_destrect = *DstRect;
438 This->overlay_destrect.left = 0;
439 This->overlay_destrect.top = 0;
440 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
441 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
444 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
445 list_remove(&This->overlay_entry);
448 if(Flags & WINEDDOVER_SHOW) {
449 if(This->overlay_dest != Dst) {
450 This->overlay_dest = Dst;
451 list_add_tail(&Dst->overlays, &This->overlay_entry);
453 } else if(Flags & WINEDDOVER_HIDE) {
454 /* tests show that the rectangles are erased on hide */
455 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
456 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
457 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
458 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
459 This->overlay_dest = NULL;
462 IWineD3DSurface_DrawOverlay(iface);
467 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
469 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
470 TRACE("(%p)->(%p)\n", This, clipper);
472 This->clipper = clipper;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 *clipper = This->clipper;
483 IWineD3DClipper_AddRef(*clipper);
488 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
489 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
490 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format,
491 &This->resource.device->adapter->gl_info);
493 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
495 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
496 return WINED3DERR_INVALIDCALL;
499 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
501 This->resource.size = wined3d_format_calculate_size(format_desc, This->resource.device->surface_alignment,
502 This->pow2Width, This->pow2Height);
504 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
506 This->resource.format_desc = format_desc;
508 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
513 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
514 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
515 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
523 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
525 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
526 return WINED3DERR_INVALIDCALL;
529 switch (format_desc->byte_count)
533 /* Allocate extra space to store the RGB bit masks. */
534 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
538 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
542 /* Allocate extra space for a palette. */
543 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
544 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
549 return E_OUTOFMEMORY;
551 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
552 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
553 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
554 * add an extra line to the dib section
556 GetSystemInfo(&sysInfo);
557 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
559 TRACE("Adding an extra line to the dib section\n");
562 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
563 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
564 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
565 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
566 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
567 b_info->bmiHeader.biPlanes = 1;
568 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
570 b_info->bmiHeader.biXPelsPerMeter = 0;
571 b_info->bmiHeader.biYPelsPerMeter = 0;
572 b_info->bmiHeader.biClrUsed = 0;
573 b_info->bmiHeader.biClrImportant = 0;
575 /* Get the bit masks */
576 masks = (DWORD *)b_info->bmiColors;
577 switch (This->resource.format_desc->format)
579 case WINED3DFMT_B8G8R8_UNORM:
580 usage = DIB_RGB_COLORS;
581 b_info->bmiHeader.biCompression = BI_RGB;
584 case WINED3DFMT_B5G5R5X1_UNORM:
585 case WINED3DFMT_B5G5R5A1_UNORM:
586 case WINED3DFMT_B4G4R4A4_UNORM:
587 case WINED3DFMT_B4G4R4X4_UNORM:
588 case WINED3DFMT_B2G3R3_UNORM:
589 case WINED3DFMT_B2G3R3A8_UNORM:
590 case WINED3DFMT_R10G10B10A2_UNORM:
591 case WINED3DFMT_R8G8B8A8_UNORM:
592 case WINED3DFMT_R8G8B8X8_UNORM:
593 case WINED3DFMT_B10G10R10A2_UNORM:
594 case WINED3DFMT_B5G6R5_UNORM:
595 case WINED3DFMT_R16G16B16A16_UNORM:
597 b_info->bmiHeader.biCompression = BI_BITFIELDS;
598 masks[0] = format_desc->red_mask;
599 masks[1] = format_desc->green_mask;
600 masks[2] = format_desc->blue_mask;
604 /* Don't know palette */
605 b_info->bmiHeader.biCompression = BI_RGB;
612 HeapFree(GetProcessHeap(), 0, b_info);
613 return HRESULT_FROM_WIN32(GetLastError());
616 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);
617 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
620 if (!This->dib.DIBsection) {
621 ERR("CreateDIBSection failed!\n");
622 HeapFree(GetProcessHeap(), 0, b_info);
623 return HRESULT_FROM_WIN32(GetLastError());
626 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
627 /* copy the existing surface to the dib section */
628 if(This->resource.allocatedMemory) {
629 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
631 /* This is to make LockRect read the gl Texture although memory is allocated */
632 This->Flags &= ~SFLAG_INSYSMEM;
634 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
636 HeapFree(GetProcessHeap(), 0, b_info);
638 /* Now allocate a HDC */
639 This->hDC = CreateCompatibleDC(0);
640 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
641 TRACE("using wined3d palette %p\n", This->palette);
642 SelectPalette(This->hDC,
643 This->palette ? This->palette->hpal : 0,
646 This->Flags |= SFLAG_DIBSECTION;
648 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
649 This->resource.heapMemory = NULL;
654 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
655 unsigned int w, unsigned int h)
659 unsigned short *dst_s;
661 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
662 for(y = 0; y < h; y++) {
663 src_f = (const float *)(src + y * pitch_in);
664 dst_s = (unsigned short *) (dst + y * pitch_out);
665 for(x = 0; x < w; x++) {
666 dst_s[x] = float_32_to_16(src_f + x);
671 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
672 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
674 static const unsigned char convert_5to8[] =
676 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
677 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
678 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
679 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
681 static const unsigned char convert_6to8[] =
683 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
684 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
685 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
686 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
687 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
688 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
689 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
690 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
694 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
696 for (y = 0; y < h; ++y)
698 const WORD *src_line = (const WORD *)(src + y * pitch_in);
699 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
700 for (x = 0; x < w; ++x)
702 WORD pixel = src_line[x];
703 dst_line[x] = 0xff000000
704 | convert_5to8[(pixel & 0xf800) >> 11] << 16
705 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
706 | convert_5to8[(pixel & 0x001f)];
711 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
712 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
716 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
718 for (y = 0; y < h; ++y)
720 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
721 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
723 for (x = 0; x < w; ++x)
725 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
730 static inline BYTE cliptobyte(int x)
732 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
735 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
736 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
739 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
741 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
743 for (y = 0; y < h; ++y)
745 const BYTE *src_line = src + y * pitch_in;
746 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
747 for (x = 0; x < w; ++x)
749 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
750 * C = Y - 16; D = U - 128; E = V - 128;
751 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
752 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
753 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
754 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
755 * U and V are shared between the pixels.
757 if (!(x & 1)) /* for every even pixel, read new U and V */
759 d = (int) src_line[1] - 128;
760 e = (int) src_line[3] - 128;
762 g2 = - 100 * d - 208 * e + 128;
765 c2 = 298 * ((int) src_line[0] - 16);
766 dst_line[x] = 0xff000000
767 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
768 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
769 | cliptobyte((c2 + b2) >> 8); /* blue */
770 /* Scale RGB values to 0..255 range,
771 * then clip them if still not in range (may be negative),
772 * then shift them within DWORD if necessary.
779 struct d3dfmt_convertor_desc {
780 WINED3DFORMAT from, to;
781 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
784 static const struct d3dfmt_convertor_desc convertors[] =
786 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
787 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
788 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
789 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
792 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
795 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
796 if(convertors[i].from == from && convertors[i].to == to) {
797 return &convertors[i];
803 /*****************************************************************************
804 * surface_convert_format
806 * Creates a duplicate of a surface in a different format. Is used by Blt to
807 * blit between surfaces with different formats
810 * source: Source surface
811 * fmt: Requested destination format
813 *****************************************************************************/
814 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
815 IWineD3DSurface *ret = NULL;
816 const struct d3dfmt_convertor_desc *conv;
817 WINED3DLOCKED_RECT lock_src, lock_dst;
820 conv = find_convertor(source->resource.format_desc->format, to_fmt);
822 FIXME("Cannot find a conversion function from format %s to %s\n",
823 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
827 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
828 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
829 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
830 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
831 NULL /* parent */, &wined3d_null_parent_ops);
833 ERR("Failed to create a destination surface for conversion\n");
837 memset(&lock_src, 0, sizeof(lock_src));
838 memset(&lock_dst, 0, sizeof(lock_dst));
840 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
842 ERR("Failed to lock the source surface\n");
843 IWineD3DSurface_Release(ret);
846 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
848 ERR("Failed to lock the dest surface\n");
849 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
850 IWineD3DSurface_Release(ret);
854 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
855 source->currentDesc.Width, source->currentDesc.Height);
857 IWineD3DSurface_UnlockRect(ret);
858 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
860 return (IWineD3DSurfaceImpl *) ret;
863 /*****************************************************************************
866 * Helper function that fills a memory area with a specific color
869 * buf: memory address to start filling at
870 * width, height: Dimensions of the area to fill
871 * bpp: Bit depth of the surface
872 * lPitch: pitch of the surface
873 * color: Color to fill with
875 *****************************************************************************/
877 _Blt_ColorFill(BYTE *buf,
878 int width, int height,
879 int bpp, LONG lPitch,
887 #define COLORFILL_ROW(type) \
889 type *d = (type *) buf; \
890 for (x = 0; x < width; x++) \
891 d[x] = (type) color; \
896 case 1: COLORFILL_ROW(BYTE)
897 case 2: COLORFILL_ROW(WORD)
901 for (x = 0; x < width; x++,d+=3)
903 d[0] = (color ) & 0xFF;
904 d[1] = (color>> 8) & 0xFF;
905 d[2] = (color>>16) & 0xFF;
909 case 4: COLORFILL_ROW(DWORD)
911 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
912 return WINED3DERR_NOTAVAILABLE;
917 /* Now copy first row */
919 for (y = 1; y < height; y++)
922 memcpy(buf, first, width * bpp);
927 /*****************************************************************************
928 * IWineD3DSurface::Blt, SW emulation version
930 * Performs a blit to a surface, with or without a source surface.
931 * This is the main functionality of DirectDraw
934 * DestRect: Destination rectangle to write to
935 * src_surface: Source surface, can be NULL
936 * SrcRect: Source rectangle
937 *****************************************************************************/
938 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
939 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
941 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
942 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
944 HRESULT ret = WINED3D_OK;
945 WINED3DLOCKED_RECT dlock, slock;
946 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
947 const struct wined3d_format_desc *sEntry, *dEntry;
952 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
953 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
954 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
956 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
958 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
959 return WINEDDERR_SURFACEBUSY;
962 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
963 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
964 FIXME("Filters not supported in software blit\n");
967 /* First check for the validity of source / destination rectangles.
968 * This was verified using a test application + by MSDN. */
974 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
975 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
976 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
977 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
978 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
980 WARN("Application gave us bad source rectangle for Blt.\n");
981 return WINEDDERR_INVALIDRECT;
984 if (!SrcRect->right || !SrcRect->bottom
985 || SrcRect->left == (int)src->currentDesc.Width
986 || SrcRect->top == (int)src->currentDesc.Height)
988 TRACE("Nothing to be done.\n");
999 xsrc.right = src->currentDesc.Width;
1000 xsrc.bottom = src->currentDesc.Height;
1004 memset(&xsrc, 0, sizeof(xsrc));
1009 /* For the Destination rect, it can be out of bounds on the condition
1010 * that a clipper is set for the given surface. */
1011 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1012 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1013 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1014 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1015 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1017 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1018 return WINEDDERR_INVALIDRECT;
1021 if (DestRect->right <= 0 || DestRect->bottom <= 0
1022 || DestRect->left >= (int)This->currentDesc.Width
1023 || DestRect->top >= (int)This->currentDesc.Height)
1025 TRACE("Nothing to be done.\n");
1035 full_rect.right = This->currentDesc.Width;
1036 full_rect.bottom = This->currentDesc.Height;
1037 IntersectRect(&xdst, &full_rect, DestRect);
1041 BOOL clip_horiz, clip_vert;
1044 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1045 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1047 if (clip_vert || clip_horiz)
1049 /* Now check if this is a special case or not... */
1050 if ((Flags & WINEDDBLT_DDFX)
1051 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1052 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1054 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1062 xsrc.left -= xdst.left;
1065 if (xdst.right > This->currentDesc.Width)
1067 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1068 xdst.right = (int)This->currentDesc.Width;
1076 xsrc.top -= xdst.top;
1079 if (xdst.bottom > This->currentDesc.Height)
1081 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1082 xdst.bottom = (int)This->currentDesc.Height;
1086 /* And check if after clipping something is still to be done... */
1087 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1088 || (xdst.left >= (int)This->currentDesc.Width)
1089 || (xdst.top >= (int)This->currentDesc.Height)
1090 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1091 || (xsrc.left >= (int)src->currentDesc.Width)
1092 || (xsrc.top >= (int)src->currentDesc.Height))
1094 TRACE("Nothing to be done after clipping.\n");
1104 xdst.right = This->currentDesc.Width;
1105 xdst.bottom = This->currentDesc.Height;
1110 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1112 sEntry = This->resource.format_desc;
1117 dEntry = This->resource.format_desc;
1120 if (This->resource.format_desc->format != src->resource.format_desc->format)
1122 src = surface_convert_format(src, dEntry->format);
1125 /* The conv function writes a FIXME */
1126 WARN("Cannot convert source surface format to dest format\n");
1130 IWineD3DSurface_LockRect((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1131 sEntry = src->resource.format_desc;
1138 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1140 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1143 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1145 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1147 if (!DestRect || src == This)
1149 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1154 bpp = This->resource.format_desc->byte_count;
1155 srcheight = xsrc.bottom - xsrc.top;
1156 srcwidth = xsrc.right - xsrc.left;
1157 dstheight = xdst.bottom - xdst.top;
1158 dstwidth = xdst.right - xdst.left;
1159 width = (xdst.right - xdst.left) * bpp;
1161 if (DestRect && src != This)
1164 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1166 if (Flags & WINEDDBLT_WAIT)
1168 Flags &= ~WINEDDBLT_WAIT;
1170 if (Flags & WINEDDBLT_ASYNC)
1172 static BOOL displayed = FALSE;
1174 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1176 Flags &= ~WINEDDBLT_ASYNC;
1178 if (Flags & WINEDDBLT_DONOTWAIT)
1180 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1181 static BOOL displayed = FALSE;
1183 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1185 Flags &= ~WINEDDBLT_DONOTWAIT;
1188 /* First, all the 'source-less' blits */
1189 if (Flags & WINEDDBLT_COLORFILL)
1191 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1192 dlock.Pitch, DDBltFx->u5.dwFillColor);
1193 Flags &= ~WINEDDBLT_COLORFILL;
1196 if (Flags & WINEDDBLT_DEPTHFILL)
1198 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1200 if (Flags & WINEDDBLT_ROP)
1202 /* Catch some degenerate cases here */
1203 switch(DDBltFx->dwROP)
1206 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1208 case 0xAA0029: /* No-op */
1211 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1213 case SRCCOPY: /* well, we do that below ? */
1216 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1219 Flags &= ~WINEDDBLT_ROP;
1221 if (Flags & WINEDDBLT_DDROPS)
1223 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1225 /* Now the 'with source' blits */
1229 int sx, xinc, sy, yinc;
1231 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1233 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1234 xinc = (srcwidth << 16) / dstwidth;
1235 yinc = (srcheight << 16) / dstheight;
1239 /* No effects, we can cheat here */
1240 if (dstwidth == srcwidth)
1242 if (dstheight == srcheight)
1244 /* No stretching in either direction. This needs to be as
1245 * fast as possible */
1248 /* check for overlapping surfaces */
1249 if (src != This || xdst.top < xsrc.top ||
1250 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1252 /* no overlap, or dst above src, so copy from top downwards */
1253 for (y = 0; y < dstheight; y++)
1255 memcpy(dbuf, sbuf, width);
1256 sbuf += slock.Pitch;
1257 dbuf += dlock.Pitch;
1260 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1262 sbuf += (slock.Pitch*dstheight);
1263 dbuf += (dlock.Pitch*dstheight);
1264 for (y = 0; y < dstheight; y++)
1266 sbuf -= slock.Pitch;
1267 dbuf -= dlock.Pitch;
1268 memcpy(dbuf, sbuf, width);
1271 else /* src and dst overlapping on the same line, use memmove */
1273 for (y = 0; y < dstheight; y++)
1275 memmove(dbuf, sbuf, width);
1276 sbuf += slock.Pitch;
1277 dbuf += dlock.Pitch;
1281 /* Stretching in Y direction only */
1282 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1283 sbuf = sbase + (sy >> 16) * slock.Pitch;
1284 memcpy(dbuf, sbuf, width);
1285 dbuf += dlock.Pitch;
1291 /* Stretching in X direction */
1293 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1295 sbuf = sbase + (sy >> 16) * slock.Pitch;
1297 if ((sy >> 16) == (last_sy >> 16))
1299 /* this sourcerow is the same as last sourcerow -
1300 * copy already stretched row
1302 memcpy(dbuf, dbuf - dlock.Pitch, width);
1306 #define STRETCH_ROW(type) { \
1307 const type *s = (const type *)sbuf; \
1308 type *d = (type *)dbuf; \
1309 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1310 d[x] = s[sx >> 16]; \
1315 case 1: STRETCH_ROW(BYTE)
1316 case 2: STRETCH_ROW(WORD)
1317 case 4: STRETCH_ROW(DWORD)
1322 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1326 s = sbuf+3*(sx>>16);
1327 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1328 d[0] = (pixel )&0xff;
1329 d[1] = (pixel>> 8)&0xff;
1330 d[2] = (pixel>>16)&0xff;
1336 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1337 ret = WINED3DERR_NOTAVAILABLE;
1342 dbuf += dlock.Pitch;
1349 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1350 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1351 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1352 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1354 /* The color keying flags are checked for correctness in ddraw */
1355 if (Flags & WINEDDBLT_KEYSRC)
1357 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1358 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1360 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1362 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1363 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1366 if (Flags & WINEDDBLT_KEYDEST)
1368 /* Destination color keys are taken from the source surface ! */
1369 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1370 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1372 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1374 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1375 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1384 keymask = sEntry->red_mask
1385 | sEntry->green_mask
1386 | sEntry->blue_mask;
1388 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1391 if (Flags & WINEDDBLT_DDFX)
1393 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1396 dTopRight = dbuf+((dstwidth-1)*bpp);
1397 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1398 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1400 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1402 /* I don't think we need to do anything about this flag */
1403 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1405 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1408 dTopRight = dTopLeft;
1411 dBottomRight = dBottomLeft;
1413 dstxinc = dstxinc *-1;
1415 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1418 dTopLeft = dBottomLeft;
1421 dTopRight = dBottomRight;
1423 dstyinc = dstyinc *-1;
1425 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1427 /* I don't think we need to do anything about this flag */
1428 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1430 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1433 dBottomRight = dTopLeft;
1436 dBottomLeft = dTopRight;
1438 dstxinc = dstxinc * -1;
1439 dstyinc = dstyinc * -1;
1441 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1444 dTopLeft = dBottomLeft;
1445 dBottomLeft = dBottomRight;
1446 dBottomRight = dTopRight;
1451 dstxinc = dstxinc * -1;
1453 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1456 dTopLeft = dTopRight;
1457 dTopRight = dBottomRight;
1458 dBottomRight = dBottomLeft;
1463 dstyinc = dstyinc * -1;
1465 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1467 /* I don't think we need to do anything about this flag */
1468 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1471 Flags &= ~(WINEDDBLT_DDFX);
1474 #define COPY_COLORKEY_FX(type) { \
1476 type *d = (type *)dbuf, *dx, tmp; \
1477 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1478 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1480 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1481 tmp = s[sx >> 16]; \
1482 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1483 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1486 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1488 d = (type*)(((LPBYTE)d)+dstyinc); \
1493 case 1: COPY_COLORKEY_FX(BYTE)
1494 case 2: COPY_COLORKEY_FX(WORD)
1495 case 4: COPY_COLORKEY_FX(DWORD)
1499 BYTE *d = dbuf, *dx;
1500 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1502 sbuf = sbase + (sy >> 16) * slock.Pitch;
1504 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1506 DWORD pixel, dpixel = 0;
1507 s = sbuf+3*(sx>>16);
1508 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1509 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1510 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1511 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1513 dx[0] = (pixel )&0xff;
1514 dx[1] = (pixel>> 8)&0xff;
1515 dx[2] = (pixel>>16)&0xff;
1524 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1525 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1526 ret = WINED3DERR_NOTAVAILABLE;
1528 #undef COPY_COLORKEY_FX
1534 if (Flags && FIXME_ON(d3d_surface))
1536 FIXME("\tUnsupported flags: %08x\n", Flags);
1540 IWineD3DSurface_UnlockRect(iface);
1541 if (src && src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *)src);
1542 /* Release the converted surface if any */
1543 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1547 /*****************************************************************************
1548 * IWineD3DSurface::BltFast, SW emulation version
1550 * This is the software implementation of BltFast, as used by GDI surfaces
1551 * and as a fallback for OpenGL surfaces. This code is taken from the old
1552 * DirectDraw code, and was originally written by TransGaming.
1557 * src_surface: Source surface to copy from
1558 * rsrc: Source rectangle
1562 * WINED3D_OK on success
1564 *****************************************************************************/
1565 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1566 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1568 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1569 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1571 int bpp, w, h, x, y;
1572 WINED3DLOCKED_RECT dlock,slock;
1573 HRESULT ret = WINED3D_OK;
1575 RECT lock_src, lock_dst, lock_union;
1578 const struct wined3d_format_desc *sEntry, *dEntry;
1580 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1581 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1583 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1585 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1586 return WINEDDERR_SURFACEBUSY;
1591 WARN("rsrc is NULL!\n");
1594 rsrc2.right = src->currentDesc.Width;
1595 rsrc2.bottom = src->currentDesc.Height;
1599 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1600 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1601 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1602 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1603 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1604 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1606 WARN("Application gave us bad source rectangle for BltFast.\n");
1607 return WINEDDERR_INVALIDRECT;
1610 h = rsrc->bottom - rsrc->top;
1611 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1612 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1613 if (h <= 0) return WINEDDERR_INVALIDRECT;
1615 w = rsrc->right - rsrc->left;
1616 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1617 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1618 if (w <= 0) return WINEDDERR_INVALIDRECT;
1620 /* Now compute the locking rectangle... */
1621 lock_src.left = rsrc->left;
1622 lock_src.top = rsrc->top;
1623 lock_src.right = lock_src.left + w;
1624 lock_src.bottom = lock_src.top + h;
1626 lock_dst.left = dstx;
1627 lock_dst.top = dsty;
1628 lock_dst.right = dstx + w;
1629 lock_dst.bottom = dsty + h;
1631 bpp = This->resource.format_desc->byte_count;
1633 /* We need to lock the surfaces, or we won't get refreshes when done. */
1638 UnionRect(&lock_union, &lock_src, &lock_dst);
1640 /* Lock the union of the two rectangles */
1641 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1642 if(ret != WINED3D_OK) goto error;
1644 pitch = dlock.Pitch;
1645 slock.Pitch = dlock.Pitch;
1647 /* Since slock was originally copied from this surface's description, we can just reuse it */
1648 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1649 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1650 sEntry = src->resource.format_desc;
1655 ret = IWineD3DSurface_LockRect(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1656 if(ret != WINED3D_OK) goto error;
1657 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1658 if(ret != WINED3D_OK) goto error;
1662 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1664 sEntry = src->resource.format_desc;
1665 dEntry = This->resource.format_desc;
1668 /* Handle compressed surfaces first... */
1669 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1671 UINT row_block_count;
1673 TRACE("compressed -> compressed copy\n");
1675 FIXME("trans arg not supported when a compressed surface is involved\n");
1677 FIXME("offset for destination surface is not supported\n");
1678 if (src->resource.format_desc->format != This->resource.format_desc->format)
1680 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1681 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1685 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1686 for (y = 0; y < h; y += dEntry->block_height)
1688 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1689 dbuf += dlock.Pitch;
1690 sbuf += slock.Pitch;
1695 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1697 /* TODO: Use the libtxc_dxtn.so shared library to do
1698 * software decompression
1700 ERR("Software decompression not supported.\n");
1704 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1706 DWORD keylow, keyhigh;
1707 DWORD mask = src->resource.format_desc->red_mask
1708 | src->resource.format_desc->green_mask
1709 | src->resource.format_desc->blue_mask;
1711 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1715 TRACE("Color keyed copy\n");
1716 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1718 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1719 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1723 /* I'm not sure if this is correct */
1724 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1725 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1726 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1729 #define COPYBOX_COLORKEY(type) { \
1730 const type *s = (const type *)sbuf; \
1731 type *d = (type *)dbuf; \
1733 for (y = 0; y < h; y++) { \
1734 for (x = 0; x < w; x++) { \
1736 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1738 s = (const type *)((const BYTE *)s + slock.Pitch); \
1739 d = (type *)((BYTE *)d + dlock.Pitch); \
1745 case 1: COPYBOX_COLORKEY(BYTE)
1746 case 2: COPYBOX_COLORKEY(WORD)
1747 case 4: COPYBOX_COLORKEY(DWORD)
1755 for (y = 0; y < h; y++)
1757 for (x = 0; x < w * 3; x += 3)
1759 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1760 if (tmp < keylow || tmp > keyhigh)
1762 d[x + 0] = s[x + 0];
1763 d[x + 1] = s[x + 1];
1764 d[x + 2] = s[x + 2];
1773 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1774 ret = WINED3DERR_NOTAVAILABLE;
1777 #undef COPYBOX_COLORKEY
1778 TRACE("Copy Done\n");
1782 int width = w * bpp;
1783 INT sbufpitch, dbufpitch;
1785 TRACE("NO color key copy\n");
1786 /* Handle overlapping surfaces */
1789 sbuf += (h - 1) * slock.Pitch;
1790 dbuf += (h - 1) * dlock.Pitch;
1791 sbufpitch = -slock.Pitch;
1792 dbufpitch = -dlock.Pitch;
1796 sbufpitch = slock.Pitch;
1797 dbufpitch = dlock.Pitch;
1799 for (y = 0; y < h; y++)
1801 /* This is pretty easy, a line for line memcpy */
1802 memmove(dbuf, sbuf, width);
1806 TRACE("Copy done\n");
1812 IWineD3DSurface_UnlockRect(iface);
1816 IWineD3DSurface_UnlockRect(iface);
1817 IWineD3DSurface_UnlockRect(src_surface);
1823 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1825 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1827 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1828 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1830 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1834 pLockedRect->pBits = This->resource.allocatedMemory;
1835 This->lockedRect.left = 0;
1836 This->lockedRect.top = 0;
1837 This->lockedRect.right = This->currentDesc.Width;
1838 This->lockedRect.bottom = This->currentDesc.Height;
1840 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1841 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1842 This->lockedRect.right, This->lockedRect.bottom);
1846 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1848 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1849 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1851 if ((format_desc->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH))
1852 == WINED3DFMT_FLAG_COMPRESSED)
1854 /* Compressed textures are block based, so calculate the offset of
1855 * the block that contains the top-left pixel of the locked rectangle. */
1856 pLockedRect->pBits = This->resource.allocatedMemory
1857 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1858 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1862 pLockedRect->pBits = This->resource.allocatedMemory +
1863 (pLockedRect->Pitch * pRect->top) +
1864 (pRect->left * format_desc->byte_count);
1866 This->lockedRect.left = pRect->left;
1867 This->lockedRect.top = pRect->top;
1868 This->lockedRect.right = pRect->right;
1869 This->lockedRect.bottom = pRect->bottom;
1872 /* No dirtifying is needed for this surface implementation */
1873 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1878 /* TODO: think about moving this down to resource? */
1879 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1881 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1883 /* This should only be called for sysmem textures, it may be a good idea
1884 * to extend this to all pools at some point in the future */
1885 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1887 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1889 return This->resource.allocatedMemory;