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"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37 /* See also float_16_to_32() in wined3d_private.h */
38 static inline unsigned short float_32_to_16(const float *in)
41 float tmp = fabs(*in);
42 unsigned int mantissa;
45 /* Deal with special numbers */
46 if(*in == 0.0) return 0x0000;
47 if(isnan(*in)) return 0x7C01;
48 if(isinf(*in)) return (*in < 0.0 ? 0xFC00 : 0x7c00);
50 if(tmp < pow(2, 10)) {
55 }while(tmp < pow(2, 10));
56 } else if(tmp >= pow(2, 11)) {
61 }while(tmp >= pow(2, 11));
64 mantissa = (unsigned int) tmp;
65 if(tmp - mantissa >= 0.5) mantissa++; /* round to nearest, away from zero */
67 exp += 10; /* Normalize the mantissa */
68 exp += 15; /* Exponent is encoded with excess 15 */
70 if(exp > 30) { /* too big */
71 ret = 0x7c00; /* INF */
73 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
75 mantissa = mantissa >> 1;
78 ret = mantissa & 0x3ff;
80 ret = (exp << 10) | (mantissa & 0x3ff);
83 ret |= ((*in < 0.0 ? 1 : 0) << 15); /* Add the sign */
88 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
90 /* *******************************************
91 IWineD3DSurface IUnknown parts follow
92 ******************************************* */
93 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
95 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
96 /* Warn ,but be nice about things */
97 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
99 if (IsEqualGUID(riid, &IID_IUnknown)
100 || IsEqualGUID(riid, &IID_IWineD3DBase)
101 || IsEqualGUID(riid, &IID_IWineD3DResource)
102 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
103 IUnknown_AddRef((IUnknown*)iface);
108 return E_NOINTERFACE;
111 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
112 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
113 ULONG ref = InterlockedIncrement(&This->resource.ref);
114 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
118 /* ****************************************************
119 IWineD3DSurface IWineD3DResource parts follow
120 **************************************************** */
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
122 return resource_get_device((IWineD3DResource *)iface, ppDevice);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
126 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
129 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
130 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
133 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
134 return resource_free_private_data((IWineD3DResource *)iface, refguid);
137 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
138 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
141 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
142 return resource_get_priority((IWineD3DResource *)iface);
145 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
146 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
147 return resource_get_type((IWineD3DResource *)iface);
150 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
151 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
152 return resource_get_parent((IWineD3DResource *)iface, pParent);
155 /* ******************************************************
156 IWineD3DSurface IWineD3DSurface parts follow
157 ****************************************************** */
159 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
160 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
161 IWineD3DBase *container = 0;
163 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
166 ERR("Called without a valid ppContainer.\n");
169 /* Standalone surfaces return the device as container. */
170 if (This->container) {
171 container = This->container;
173 container = (IWineD3DBase *)This->resource.wineD3DDevice;
176 TRACE("Relaying to QueryInterface\n");
177 return IUnknown_QueryInterface(container, riid, ppContainer);
180 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
181 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
183 TRACE("(%p) : copying into %p\n", This, pDesc);
184 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format_desc->format;
185 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
186 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
187 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
188 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
189 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
190 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
191 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
192 if(pDesc->Height != NULL) *(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 WINED3DFORMAT format = This->resource.format_desc->format;
337 TRACE("(%p)\n", This);
339 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
340 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
341 ie pitch = (width/4) * bytes per block */
342 if (format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
343 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
344 else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
345 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
346 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
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));
522 if (format == WINED3DFMT_UNKNOWN) {
523 This->resource.size = 0;
525 else if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
527 UINT row_block_count = (This->pow2Width + format_desc->block_width - 1) / format_desc->block_width;
528 UINT row_count = (This->pow2Height + format_desc->block_height - 1) / format_desc->block_height;
529 This->resource.size = row_count * row_block_count * format_desc->block_byte_count;
533 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
534 This->resource.size = ((This->pow2Width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1);
535 This->resource.size *= This->pow2Height;
538 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
540 This->resource.format_desc = format_desc;
542 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
547 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
548 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
549 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
557 switch (format_desc->byte_count)
561 /* Allocate extra space to store the RGB bit masks. */
562 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
566 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
570 /* Allocate extra space for a palette. */
571 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
572 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
577 return E_OUTOFMEMORY;
579 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
580 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
581 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
582 * add an extra line to the dib section
584 GetSystemInfo(&sysInfo);
585 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
587 TRACE("Adding an extra line to the dib section\n");
590 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
591 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
592 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
593 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
594 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
595 b_info->bmiHeader.biPlanes = 1;
596 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
598 b_info->bmiHeader.biXPelsPerMeter = 0;
599 b_info->bmiHeader.biYPelsPerMeter = 0;
600 b_info->bmiHeader.biClrUsed = 0;
601 b_info->bmiHeader.biClrImportant = 0;
603 /* Get the bit masks */
604 masks = (DWORD *)b_info->bmiColors;
605 switch (This->resource.format_desc->format)
607 case WINED3DFMT_R8G8B8:
608 usage = DIB_RGB_COLORS;
609 b_info->bmiHeader.biCompression = BI_RGB;
612 case WINED3DFMT_X1R5G5B5:
613 case WINED3DFMT_A1R5G5B5:
614 case WINED3DFMT_A4R4G4B4:
615 case WINED3DFMT_X4R4G4B4:
616 case WINED3DFMT_R3G3B2:
617 case WINED3DFMT_A8R3G3B2:
618 case WINED3DFMT_R10G10B10A2_UNORM:
619 case WINED3DFMT_R8G8B8A8_UNORM:
620 case WINED3DFMT_X8B8G8R8:
621 case WINED3DFMT_A2R10G10B10:
622 case WINED3DFMT_R5G6B5:
623 case WINED3DFMT_R16G16B16A16_UNORM:
625 b_info->bmiHeader.biCompression = BI_BITFIELDS;
626 masks[0] = format_desc->red_mask;
627 masks[1] = format_desc->green_mask;
628 masks[2] = format_desc->blue_mask;
632 /* Don't know palette */
633 b_info->bmiHeader.biCompression = BI_RGB;
640 HeapFree(GetProcessHeap(), 0, b_info);
641 return HRESULT_FROM_WIN32(GetLastError());
644 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);
645 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
648 if (!This->dib.DIBsection) {
649 ERR("CreateDIBSection failed!\n");
650 HeapFree(GetProcessHeap(), 0, b_info);
651 return HRESULT_FROM_WIN32(GetLastError());
654 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
655 /* copy the existing surface to the dib section */
656 if(This->resource.allocatedMemory) {
657 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
659 /* This is to make LockRect read the gl Texture although memory is allocated */
660 This->Flags &= ~SFLAG_INSYSMEM;
662 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
664 HeapFree(GetProcessHeap(), 0, b_info);
666 /* Now allocate a HDC */
667 This->hDC = CreateCompatibleDC(0);
668 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
669 TRACE("using wined3d palette %p\n", This->palette);
670 SelectPalette(This->hDC,
671 This->palette ? This->palette->hpal : 0,
674 This->Flags |= SFLAG_DIBSECTION;
676 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
677 This->resource.heapMemory = NULL;
682 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
683 unsigned int w, unsigned int h)
687 unsigned short *dst_s;
689 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
690 for(y = 0; y < h; y++) {
691 src_f = (const float *)(src + y * pitch_in);
692 dst_s = (unsigned short *) (dst + y * pitch_out);
693 for(x = 0; x < w; x++) {
694 dst_s[x] = float_32_to_16(src_f + x);
699 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
700 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
702 static const unsigned char convert_5to8[] =
704 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
705 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
706 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
707 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
709 static const unsigned char convert_6to8[] =
711 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
712 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
713 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
714 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
715 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
716 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
717 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
718 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
722 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
724 for (y = 0; y < h; ++y)
726 const WORD *src_line = (const WORD *)(src + y * pitch_in);
727 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
728 for (x = 0; x < w; ++x)
730 WORD pixel = src_line[x];
731 dst_line[x] = 0xff000000
732 | convert_5to8[(pixel & 0xf800) >> 11] << 16
733 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
734 | convert_5to8[(pixel & 0x001f)];
739 struct d3dfmt_convertor_desc {
740 WINED3DFORMAT from, to;
741 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
744 static const struct d3dfmt_convertor_desc convertors[] =
746 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
747 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
750 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
753 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
754 if(convertors[i].from == from && convertors[i].to == to) {
755 return &convertors[i];
761 /*****************************************************************************
762 * surface_convert_format
764 * Creates a duplicate of a surface in a different format. Is used by Blt to
765 * blit between surfaces with different formats
768 * source: Source surface
769 * fmt: Requested destination format
771 *****************************************************************************/
772 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
773 IWineD3DSurface *ret = NULL;
774 const struct d3dfmt_convertor_desc *conv;
775 WINED3DLOCKED_RECT lock_src, lock_dst;
778 conv = find_convertor(source->resource.format_desc->format, to_fmt);
780 FIXME("Cannot find a conversion function from format %s to %s\n",
781 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
785 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice,
786 source->currentDesc.Width, source->currentDesc.Height, to_fmt, TRUE /* lockable */,
787 TRUE /* discard */, 0 /* level */, &ret, WINED3DRTYPE_SURFACE, 0 /* usage */,
788 WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
789 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
791 ERR("Failed to create a destination surface for conversion\n");
795 memset(&lock_src, 0, sizeof(lock_src));
796 memset(&lock_dst, 0, sizeof(lock_dst));
798 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
800 ERR("Failed to lock the source surface\n");
801 IWineD3DSurface_Release(ret);
804 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
806 ERR("Failed to lock the dest surface\n");
807 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
808 IWineD3DSurface_Release(ret);
812 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
813 source->currentDesc.Width, source->currentDesc.Height);
815 IWineD3DSurface_UnlockRect(ret);
816 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
818 return (IWineD3DSurfaceImpl *) ret;
821 /*****************************************************************************
824 * Helper function that fills a memory area with a specific color
827 * buf: memory address to start filling at
828 * width, height: Dimensions of the area to fill
829 * bpp: Bit depth of the surface
830 * lPitch: pitch of the surface
831 * color: Color to fill with
833 *****************************************************************************/
835 _Blt_ColorFill(BYTE *buf,
836 int width, int height,
837 int bpp, LONG lPitch,
845 #define COLORFILL_ROW(type) \
847 type *d = (type *) buf; \
848 for (x = 0; x < width; x++) \
849 d[x] = (type) color; \
854 case 1: COLORFILL_ROW(BYTE)
855 case 2: COLORFILL_ROW(WORD)
859 for (x = 0; x < width; x++,d+=3)
861 d[0] = (color ) & 0xFF;
862 d[1] = (color>> 8) & 0xFF;
863 d[2] = (color>>16) & 0xFF;
867 case 4: COLORFILL_ROW(DWORD)
869 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
870 return WINED3DERR_NOTAVAILABLE;
875 /* Now copy first row */
877 for (y = 1; y < height; y++)
880 memcpy(buf, first, width * bpp);
885 /*****************************************************************************
886 * IWineD3DSurface::Blt, SW emulation version
888 * Performs blits to a surface, eigher from a source of source-less blts
889 * This is the main functionality of DirectDraw
892 * DestRect: Destination rectangle to write to
893 * SrcSurface: Source surface, can be NULL
894 * SrcRect: Source rectangle
895 *****************************************************************************/
896 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
897 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
899 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
900 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
902 HRESULT ret = WINED3D_OK;
903 WINED3DLOCKED_RECT dlock, slock;
904 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
905 const struct GlPixelFormatDesc *sEntry, *dEntry;
909 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
911 if (TRACE_ON(d3d_surface))
913 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
914 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
915 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
916 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
919 DDRAW_dump_DDBLT(Flags);
920 if (Flags & WINEDDBLT_DDFX)
923 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
928 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
930 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
931 return WINEDDERR_SURFACEBUSY;
934 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
935 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
936 FIXME("Filters not supported in software blit\n");
939 /* First check for the validity of source / destination rectangles. This was
940 * verified using a test application + by MSDN.
942 if ((Src != NULL) && (SrcRect != NULL) &&
943 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
944 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
945 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
946 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
947 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
949 WARN("Application gave us bad source rectangle for Blt.\n");
950 return WINEDDERR_INVALIDRECT;
952 /* For the Destination rect, it can be out of bounds on the condition that a clipper
953 * is set for the given surface.
955 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
956 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
957 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
958 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
959 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
960 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
962 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
963 return WINEDDERR_INVALIDRECT;
966 /* Now handle negative values in the rectangles. Warning: only supported for now
967 in the 'simple' cases (ie not in any stretching / rotation cases).
969 First, the case where nothing is to be done.
971 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
972 (DestRect->top >= (int) This->currentDesc.Height) ||
973 (DestRect->left >= (int) This->currentDesc.Width))) ||
974 ((Src != NULL) && (SrcRect != NULL) &&
975 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
976 (SrcRect->top >= (int) Src->currentDesc.Height) ||
977 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
979 TRACE("Nothing to be done !\n");
990 xdst.bottom = This->currentDesc.Height;
992 xdst.right = This->currentDesc.Width;
1004 xsrc.bottom = Src->currentDesc.Height;
1006 xsrc.right = Src->currentDesc.Width;
1010 memset(&xsrc,0,sizeof(xsrc));
1014 /* The easy case : the source-less blits.... */
1015 if (Src == NULL && DestRect)
1018 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1022 full_rect.right = This->currentDesc.Width;
1023 full_rect.bottom = This->currentDesc.Height;
1024 IntersectRect(&temp_rect, &full_rect, DestRect);
1029 /* Only handle clipping on the destination rectangle */
1030 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1031 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1032 if (clip_vert || clip_horiz)
1034 /* Now check if this is a special case or not... */
1035 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1036 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1037 (Flags & WINEDDBLT_DDFX))
1039 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1045 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1046 if (DestRect->right > This->currentDesc.Width)
1048 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1049 xdst.right = (int) This->currentDesc.Width;
1054 if (DestRect->top < 0)
1056 xsrc.top -= DestRect->top;
1059 if (DestRect->bottom > This->currentDesc.Height)
1061 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1062 xdst.bottom = (int) This->currentDesc.Height;
1065 /* And check if after clipping something is still to be done... */
1066 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1067 (xdst.top >= (int) This->currentDesc.Height) ||
1068 (xdst.left >= (int) This->currentDesc.Width) ||
1069 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1070 (xsrc.top >= (int) Src->currentDesc.Height) ||
1071 (xsrc.left >= (int) Src->currentDesc.Width))
1073 TRACE("Nothing to be done after clipping !\n");
1081 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1083 sEntry = This->resource.format_desc;
1088 dEntry = This->resource.format_desc;
1091 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1093 Src = surface_convert_format(Src, dEntry->format);
1095 /* The conv function writes a FIXME */
1096 WARN("Cannot convert source surface format to dest format\n");
1100 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1101 sEntry = Src->resource.format_desc;
1108 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1110 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1113 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1115 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1117 if (!DestRect || Src == This)
1119 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1124 bpp = This->resource.format_desc->byte_count;
1125 srcheight = xsrc.bottom - xsrc.top;
1126 srcwidth = xsrc.right - xsrc.left;
1127 dstheight = xdst.bottom - xdst.top;
1128 dstwidth = xdst.right - xdst.left;
1129 width = (xdst.right - xdst.left) * bpp;
1131 assert(width <= dlock.Pitch);
1133 if (DestRect && Src != This)
1136 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1138 if (Flags & WINEDDBLT_WAIT)
1140 Flags &= ~WINEDDBLT_WAIT;
1142 if (Flags & WINEDDBLT_ASYNC)
1144 static BOOL displayed = FALSE;
1146 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1148 Flags &= ~WINEDDBLT_ASYNC;
1150 if (Flags & WINEDDBLT_DONOTWAIT)
1152 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1153 static BOOL displayed = FALSE;
1155 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1157 Flags &= ~WINEDDBLT_DONOTWAIT;
1160 /* First, all the 'source-less' blits */
1161 if (Flags & WINEDDBLT_COLORFILL)
1163 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1164 dlock.Pitch, DDBltFx->u5.dwFillColor);
1165 Flags &= ~WINEDDBLT_COLORFILL;
1168 if (Flags & WINEDDBLT_DEPTHFILL)
1170 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1172 if (Flags & WINEDDBLT_ROP)
1174 /* Catch some degenerate cases here */
1175 switch(DDBltFx->dwROP)
1178 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1180 case 0xAA0029: /* No-op */
1183 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1185 case SRCCOPY: /* well, we do that below ? */
1188 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1191 Flags &= ~WINEDDBLT_ROP;
1193 if (Flags & WINEDDBLT_DDROPS)
1195 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1197 /* Now the 'with source' blits */
1201 int sx, xinc, sy, yinc;
1203 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1205 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1206 xinc = (srcwidth << 16) / dstwidth;
1207 yinc = (srcheight << 16) / dstheight;
1211 /* No effects, we can cheat here */
1212 if (dstwidth == srcwidth)
1214 if (dstheight == srcheight)
1216 /* No stretching in either direction. This needs to be as
1217 * fast as possible */
1220 /* check for overlapping surfaces */
1221 if (Src != This || xdst.top < xsrc.top ||
1222 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1224 /* no overlap, or dst above src, so copy from top downwards */
1225 for (y = 0; y < dstheight; y++)
1227 memcpy(dbuf, sbuf, width);
1228 sbuf += slock.Pitch;
1229 dbuf += dlock.Pitch;
1232 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1234 sbuf += (slock.Pitch*dstheight);
1235 dbuf += (dlock.Pitch*dstheight);
1236 for (y = 0; y < dstheight; y++)
1238 sbuf -= slock.Pitch;
1239 dbuf -= dlock.Pitch;
1240 memcpy(dbuf, sbuf, width);
1243 else /* src and dst overlapping on the same line, use memmove */
1245 for (y = 0; y < dstheight; y++)
1247 memmove(dbuf, sbuf, width);
1248 sbuf += slock.Pitch;
1249 dbuf += dlock.Pitch;
1253 /* Stretching in Y direction only */
1254 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1255 sbuf = sbase + (sy >> 16) * slock.Pitch;
1256 memcpy(dbuf, sbuf, width);
1257 dbuf += dlock.Pitch;
1263 /* Stretching in X direction */
1265 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1267 sbuf = sbase + (sy >> 16) * slock.Pitch;
1269 if ((sy >> 16) == (last_sy >> 16))
1271 /* this sourcerow is the same as last sourcerow -
1272 * copy already stretched row
1274 memcpy(dbuf, dbuf - dlock.Pitch, width);
1278 #define STRETCH_ROW(type) { \
1279 const type *s = (const type *)sbuf; \
1280 type *d = (type *)dbuf; \
1281 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1282 d[x] = s[sx >> 16]; \
1287 case 1: STRETCH_ROW(BYTE)
1288 case 2: STRETCH_ROW(WORD)
1289 case 4: STRETCH_ROW(DWORD)
1294 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1298 s = sbuf+3*(sx>>16);
1299 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1300 d[0] = (pixel )&0xff;
1301 d[1] = (pixel>> 8)&0xff;
1302 d[2] = (pixel>>16)&0xff;
1308 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1309 ret = WINED3DERR_NOTAVAILABLE;
1314 dbuf += dlock.Pitch;
1321 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1322 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1323 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1324 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1326 /* The color keying flags are checked for correctness in ddraw */
1327 if (Flags & WINEDDBLT_KEYSRC)
1329 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1330 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1332 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1334 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1335 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1338 if (Flags & WINEDDBLT_KEYDEST)
1340 /* Destination color keys are taken from the source surface ! */
1341 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1342 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1344 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1346 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1347 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1356 keymask = sEntry->red_mask
1357 | sEntry->green_mask
1358 | sEntry->blue_mask;
1360 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1363 if (Flags & WINEDDBLT_DDFX)
1365 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1368 dTopRight = dbuf+((dstwidth-1)*bpp);
1369 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1370 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1372 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1374 /* I don't think we need to do anything about this flag */
1375 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1377 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1380 dTopRight = dTopLeft;
1383 dBottomRight = dBottomLeft;
1385 dstxinc = dstxinc *-1;
1387 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1390 dTopLeft = dBottomLeft;
1393 dTopRight = dBottomRight;
1395 dstyinc = dstyinc *-1;
1397 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1399 /* I don't think we need to do anything about this flag */
1400 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1402 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1405 dBottomRight = dTopLeft;
1408 dBottomLeft = dTopRight;
1410 dstxinc = dstxinc * -1;
1411 dstyinc = dstyinc * -1;
1413 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1416 dTopLeft = dBottomLeft;
1417 dBottomLeft = dBottomRight;
1418 dBottomRight = dTopRight;
1423 dstxinc = dstxinc * -1;
1425 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1428 dTopLeft = dTopRight;
1429 dTopRight = dBottomRight;
1430 dBottomRight = dBottomLeft;
1435 dstyinc = dstyinc * -1;
1437 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1439 /* I don't think we need to do anything about this flag */
1440 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1443 Flags &= ~(WINEDDBLT_DDFX);
1446 #define COPY_COLORKEY_FX(type) { \
1448 type *d = (type *)dbuf, *dx, tmp; \
1449 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1450 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1452 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1453 tmp = s[sx >> 16]; \
1454 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1455 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1458 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1460 d = (type*)(((LPBYTE)d)+dstyinc); \
1465 case 1: COPY_COLORKEY_FX(BYTE)
1466 case 2: COPY_COLORKEY_FX(WORD)
1467 case 4: COPY_COLORKEY_FX(DWORD)
1471 BYTE *d = dbuf, *dx;
1472 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1474 sbuf = sbase + (sy >> 16) * slock.Pitch;
1476 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1478 DWORD pixel, dpixel = 0;
1479 s = sbuf+3*(sx>>16);
1480 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1481 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1482 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1483 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1485 dx[0] = (pixel )&0xff;
1486 dx[1] = (pixel>> 8)&0xff;
1487 dx[2] = (pixel>>16)&0xff;
1496 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1497 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1498 ret = WINED3DERR_NOTAVAILABLE;
1500 #undef COPY_COLORKEY_FX
1506 if (Flags && FIXME_ON(d3d_surface))
1508 FIXME("\tUnsupported flags: %08x\n", Flags);
1512 IWineD3DSurface_UnlockRect(iface);
1513 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1514 /* Release the converted surface if any */
1515 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1519 /*****************************************************************************
1520 * IWineD3DSurface::BltFast, SW emulation version
1522 * This is the software implementation of BltFast, as used by GDI surfaces
1523 * and as a fallback for OpenGL surfaces. This code is taken from the old
1524 * DirectDraw code, and was originally written by TransGaming.
1529 * Source: Source surface to copy from
1530 * rsrc: Source rectangle
1534 * WINED3D_OK on success
1536 *****************************************************************************/
1537 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1538 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1540 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1541 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1543 int bpp, w, h, x, y;
1544 WINED3DLOCKED_RECT dlock,slock;
1545 HRESULT ret = WINED3D_OK;
1547 RECT lock_src, lock_dst, lock_union;
1550 const struct GlPixelFormatDesc *sEntry, *dEntry;
1552 if (TRACE_ON(d3d_surface))
1554 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1558 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1559 rsrc->right,rsrc->bottom);
1563 TRACE(" srcrect: NULL\n");
1567 if ((This->Flags & SFLAG_LOCKED) ||
1568 (Src->Flags & SFLAG_LOCKED))
1570 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1571 return WINEDDERR_SURFACEBUSY;
1576 WARN("rsrc is NULL!\n");
1579 rsrc2.right = Src->currentDesc.Width;
1580 rsrc2.bottom = Src->currentDesc.Height;
1584 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1585 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1586 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1587 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1588 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1589 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1591 WARN("Application gave us bad source rectangle for BltFast.\n");
1592 return WINEDDERR_INVALIDRECT;
1595 h = rsrc->bottom - rsrc->top;
1596 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1597 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1598 if (h <= 0) return WINEDDERR_INVALIDRECT;
1600 w = rsrc->right - rsrc->left;
1601 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1602 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1603 if (w <= 0) return WINEDDERR_INVALIDRECT;
1605 /* Now compute the locking rectangle... */
1606 lock_src.left = rsrc->left;
1607 lock_src.top = rsrc->top;
1608 lock_src.right = lock_src.left + w;
1609 lock_src.bottom = lock_src.top + h;
1611 lock_dst.left = dstx;
1612 lock_dst.top = dsty;
1613 lock_dst.right = dstx + w;
1614 lock_dst.bottom = dsty + h;
1616 bpp = This->resource.format_desc->byte_count;
1618 /* We need to lock the surfaces, or we won't get refreshes when done. */
1623 UnionRect(&lock_union, &lock_src, &lock_dst);
1625 /* Lock the union of the two rectangles */
1626 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1627 if(ret != WINED3D_OK) goto error;
1629 pitch = dlock.Pitch;
1630 slock.Pitch = dlock.Pitch;
1632 /* Since slock was originally copied from this surface's description, we can just reuse it */
1633 assert(This->resource.allocatedMemory != NULL);
1634 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1635 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1636 sEntry = Src->resource.format_desc;
1641 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1642 if(ret != WINED3D_OK) goto error;
1643 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1644 if(ret != WINED3D_OK) goto error;
1648 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1650 sEntry = Src->resource.format_desc;
1651 dEntry = This->resource.format_desc;
1654 /* Handle compressed surfaces first... */
1655 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1657 UINT row_block_count;
1659 TRACE("compressed -> compressed copy\n");
1661 FIXME("trans arg not supported when a compressed surface is involved\n");
1663 FIXME("offset for destination surface is not supported\n");
1664 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1666 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1667 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1671 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1672 for (y = 0; y < h; y += dEntry->block_height)
1674 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1675 dbuf += dlock.Pitch;
1676 sbuf += slock.Pitch;
1681 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1683 /* TODO: Use the libtxc_dxtn.so shared library to do
1684 * software decompression
1686 ERR("Software decompression not supported.\n");
1690 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1692 DWORD keylow, keyhigh;
1693 TRACE("Color keyed copy\n");
1694 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1696 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1697 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1701 /* I'm not sure if this is correct */
1702 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1703 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1704 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1707 #define COPYBOX_COLORKEY(type) { \
1708 const type *s = (const type *)sbuf; \
1709 type *d = (type *)dbuf; \
1711 for (y = 0; y < h; y++) { \
1712 for (x = 0; x < w; x++) { \
1714 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1716 s = (const type *)((const BYTE *)s + slock.Pitch); \
1717 d = (type *)((BYTE *)d + dlock.Pitch); \
1723 case 1: COPYBOX_COLORKEY(BYTE)
1724 case 2: COPYBOX_COLORKEY(WORD)
1725 case 4: COPYBOX_COLORKEY(DWORD)
1733 for (y = 0; y < h; y++)
1735 for (x = 0; x < w * 3; x += 3)
1737 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1738 if (tmp < keylow || tmp > keyhigh)
1740 d[x + 0] = s[x + 0];
1741 d[x + 1] = s[x + 1];
1742 d[x + 2] = s[x + 2];
1751 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1752 ret = WINED3DERR_NOTAVAILABLE;
1755 #undef COPYBOX_COLORKEY
1756 TRACE("Copy Done\n");
1760 int width = w * bpp;
1761 INT sbufpitch, dbufpitch;
1763 TRACE("NO color key copy\n");
1764 /* Handle overlapping surfaces */
1767 sbuf += (h - 1) * slock.Pitch;
1768 dbuf += (h - 1) * dlock.Pitch;
1769 sbufpitch = -slock.Pitch;
1770 dbufpitch = -dlock.Pitch;
1774 sbufpitch = slock.Pitch;
1775 dbufpitch = dlock.Pitch;
1777 for (y = 0; y < h; y++)
1779 /* This is pretty easy, a line for line memcpy */
1780 memmove(dbuf, sbuf, width);
1784 TRACE("Copy done\n");
1790 IWineD3DSurface_UnlockRect(iface);
1794 IWineD3DSurface_UnlockRect(iface);
1795 IWineD3DSurface_UnlockRect(Source);
1801 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1803 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1805 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1806 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1808 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1812 pLockedRect->pBits = This->resource.allocatedMemory;
1813 This->lockedRect.left = 0;
1814 This->lockedRect.top = 0;
1815 This->lockedRect.right = This->currentDesc.Width;
1816 This->lockedRect.bottom = This->currentDesc.Height;
1818 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1819 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1820 This->lockedRect.right, This->lockedRect.bottom);
1824 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1825 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1827 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1828 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1829 * slightly different meaning compared to regular textures. For DXTn
1830 * textures Pitch is the size of a row of blocks, 4 high and "width"
1831 * long. The x offset is calculated differently as well, since moving 4
1832 * pixels to the right actually moves an entire 4x4 block to right, ie
1833 * 16 bytes (8 in case of DXT1). */
1834 if (This->resource.format_desc->format == WINED3DFMT_DXT1)
1836 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1838 else if (This->resource.format_desc->format == WINED3DFMT_DXT2
1839 || This->resource.format_desc->format == WINED3DFMT_DXT3
1840 || This->resource.format_desc->format == WINED3DFMT_DXT4
1841 || This->resource.format_desc->format == WINED3DFMT_DXT5)
1843 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1847 pLockedRect->pBits = This->resource.allocatedMemory +
1848 (pLockedRect->Pitch * pRect->top) +
1849 (pRect->left * This->resource.format_desc->byte_count);
1851 This->lockedRect.left = pRect->left;
1852 This->lockedRect.top = pRect->top;
1853 This->lockedRect.right = pRect->right;
1854 This->lockedRect.bottom = pRect->bottom;
1857 /* No dirtifying is needed for this surface implementation */
1858 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1863 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1864 ERR("Should not be called on base texture\n");
1868 /* TODO: think about moving this down to resource? */
1869 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1871 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1873 /* This should only be called for sysmem textures, it may be a good idea
1874 * to extend this to all pools at some point in the future */
1875 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1877 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1879 return This->resource.allocatedMemory;