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-2007 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 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
39 /* *******************************************
40 IWineD3DSurface IUnknown parts follow
41 ******************************************* */
42 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface
*iface
, REFIID riid
, LPVOID
*ppobj
)
44 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
45 /* Warn ,but be nice about things */
46 TRACE("(%p)->(%s,%p)\n", This
,debugstr_guid(riid
),ppobj
);
48 if (IsEqualGUID(riid
, &IID_IUnknown
)
49 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
50 || IsEqualGUID(riid
, &IID_IWineD3DResource
)
51 || IsEqualGUID(riid
, &IID_IWineD3DSurface
)) {
52 IUnknown_AddRef((IUnknown
*)iface
);
60 ULONG WINAPI
IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface
*iface
) {
61 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
62 ULONG ref
= InterlockedIncrement(&This
->resource
.ref
);
63 TRACE("(%p) : AddRef increasing from %d\n", This
,ref
- 1);
67 /* ****************************************************
68 IWineD3DSurface IWineD3DResource parts follow
69 **************************************************** */
70 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface
*iface
, IWineD3DDevice
** ppDevice
) {
71 return IWineD3DResourceImpl_GetDevice((IWineD3DResource
*)iface
, ppDevice
);
74 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, CONST
void* pData
, DWORD SizeOfData
, DWORD Flags
) {
75 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, SizeOfData
, Flags
);
78 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, void* pData
, DWORD
* pSizeOfData
) {
79 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, pSizeOfData
);
82 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface
*iface
, REFGUID refguid
) {
83 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource
*)iface
, refguid
);
86 DWORD WINAPI
IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface
*iface
, DWORD PriorityNew
) {
87 return IWineD3DResourceImpl_SetPriority((IWineD3DResource
*)iface
, PriorityNew
);
90 DWORD WINAPI
IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface
*iface
) {
91 return IWineD3DResourceImpl_GetPriority((IWineD3DResource
*)iface
);
94 WINED3DRESOURCETYPE WINAPI
IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface
*iface
) {
95 TRACE("(%p) : calling resourceimpl_GetType\n", iface
);
96 return IWineD3DResourceImpl_GetType((IWineD3DResource
*)iface
);
99 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface
*iface
, IUnknown
**pParent
) {
100 TRACE("(%p) : calling resourceimpl_GetParent\n", iface
);
101 return IWineD3DResourceImpl_GetParent((IWineD3DResource
*)iface
, pParent
);
104 /* ******************************************************
105 IWineD3DSurface IWineD3DSurface parts follow
106 ****************************************************** */
108 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface
* iface
, REFIID riid
, void** ppContainer
) {
109 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
110 IWineD3DBase
*container
= 0;
112 TRACE("(This %p, riid %s, ppContainer %p)\n", This
, debugstr_guid(riid
), ppContainer
);
115 ERR("Called without a valid ppContainer.\n");
119 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
120 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
121 * GetContainer will return the Direct3D device used to create the surface.
123 if (This
->container
) {
124 container
= This
->container
;
126 container
= (IWineD3DBase
*)This
->resource
.wineD3DDevice
;
129 TRACE("Relaying to QueryInterface\n");
130 return IUnknown_QueryInterface(container
, riid
, ppContainer
);
133 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface
*iface
, WINED3DSURFACE_DESC
*pDesc
) {
134 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
136 TRACE("(%p) : copying into %p\n", This
, pDesc
);
137 if(pDesc
->Format
!= NULL
) *(pDesc
->Format
) = This
->resource
.format
;
138 if(pDesc
->Type
!= NULL
) *(pDesc
->Type
) = This
->resource
.resourceType
;
139 if(pDesc
->Usage
!= NULL
) *(pDesc
->Usage
) = This
->resource
.usage
;
140 if(pDesc
->Pool
!= NULL
) *(pDesc
->Pool
) = This
->resource
.pool
;
141 if(pDesc
->Size
!= NULL
) *(pDesc
->Size
) = This
->resource
.size
; /* dx8 only */
142 if(pDesc
->MultiSampleType
!= NULL
) *(pDesc
->MultiSampleType
) = This
->currentDesc
.MultiSampleType
;
143 if(pDesc
->MultiSampleQuality
!= NULL
) *(pDesc
->MultiSampleQuality
) = This
->currentDesc
.MultiSampleQuality
;
144 if(pDesc
->Width
!= NULL
) *(pDesc
->Width
) = This
->currentDesc
.Width
;
145 if(pDesc
->Height
!= NULL
) *(pDesc
->Height
) = This
->currentDesc
.Height
;
149 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
150 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
151 TRACE("(%p)->(%x)\n", This
, Flags
);
155 case WINEDDGBS_CANBLT
:
156 case WINEDDGBS_ISBLTDONE
:
160 return WINED3DERR_INVALIDCALL
;
164 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
165 /* XXX: DDERR_INVALIDSURFACETYPE */
167 TRACE("(%p)->(%08x)\n",iface
,Flags
);
169 case WINEDDGFS_CANFLIP
:
170 case WINEDDGFS_ISFLIPDONE
:
174 return WINED3DERR_INVALIDCALL
;
178 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface
*iface
) {
179 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
180 TRACE("(%p)\n", This
);
182 /* D3D8 and 9 loose full devices, ddraw only surfaces */
183 return This
->Flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
186 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface
*iface
) {
187 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
188 TRACE("(%p)\n", This
);
190 /* So far we don't lose anything :) */
191 This
->Flags
&= ~SFLAG_LOST
;
195 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
*Pal
) {
196 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
197 IWineD3DPaletteImpl
*PalImpl
= (IWineD3DPaletteImpl
*) Pal
;
198 TRACE("(%p)->(%p)\n", This
, Pal
);
200 if(This
->palette
!= NULL
)
201 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
202 This
->palette
->Flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
204 if(PalImpl
!= NULL
) {
205 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
206 /* Set the device's main palette if the palette
207 * wasn't a primary palette before
209 if(!(PalImpl
->Flags
& WINEDDPCAPS_PRIMARYSURFACE
)) {
210 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
213 for(i
=0; i
< 256; i
++) {
214 device
->palettes
[device
->currentPalette
][i
] = PalImpl
->palents
[i
];
218 (PalImpl
)->Flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
221 This
->palette
= PalImpl
;
223 return IWineD3DSurface_RealizePalette(iface
);
226 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface
*iface
, DWORD Flags
, WINEDDCOLORKEY
*CKey
) {
227 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
228 TRACE("(%p)->(%08x,%p)\n", This
, Flags
, CKey
);
230 if ((Flags
& WINEDDCKEY_COLORSPACE
) != 0) {
231 FIXME(" colorkey value not supported (%08x) !\n", Flags
);
232 return WINED3DERR_INVALIDCALL
;
235 /* Dirtify the surface, but only if a key was changed */
237 switch (Flags
& ~WINEDDCKEY_COLORSPACE
) {
238 case WINEDDCKEY_DESTBLT
:
239 This
->DestBltCKey
= *CKey
;
240 This
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
243 case WINEDDCKEY_DESTOVERLAY
:
244 This
->DestOverlayCKey
= *CKey
;
245 This
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
248 case WINEDDCKEY_SRCOVERLAY
:
249 This
->SrcOverlayCKey
= *CKey
;
250 This
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
253 case WINEDDCKEY_SRCBLT
:
254 This
->SrcBltCKey
= *CKey
;
255 This
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
260 switch (Flags
& ~WINEDDCKEY_COLORSPACE
) {
261 case WINEDDCKEY_DESTBLT
:
262 This
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
265 case WINEDDCKEY_DESTOVERLAY
:
266 This
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
269 case WINEDDCKEY_SRCOVERLAY
:
270 This
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
273 case WINEDDCKEY_SRCBLT
:
274 This
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
282 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
**Pal
) {
283 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
284 TRACE("(%p)->(%p)\n", This
, Pal
);
286 *Pal
= (IWineD3DPalette
*) This
->palette
;
290 DWORD WINAPI
IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface
*iface
) {
291 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
293 TRACE("(%p)\n", This
);
295 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
296 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
297 ie pitch = (width/4) * bytes per block */
298 if (This
->resource
.format
== WINED3DFMT_DXT1
) /* DXT1 is 8 bytes per block */
299 ret
= ((This
->currentDesc
.Width
+ 3) >> 2) << 3;
300 else if (This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
301 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) /* DXT2/3/4/5 is 16 bytes per block */
302 ret
= ((This
->currentDesc
.Width
+ 3) >> 2) << 4;
304 unsigned char alignment
= This
->resource
.wineD3DDevice
->surface_alignment
;
305 ret
= This
->bytesPerPixel
* This
->currentDesc
.Width
; /* Bytes / row */
306 ret
= (ret
+ alignment
- 1) & ~(alignment
- 1);
308 TRACE("(%p) Returning %d\n", This
, ret
);
312 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface
*iface
, LONG X
, LONG Y
) {
313 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
315 FIXME("(%p)->(%d,%d) Stub!\n", This
, X
, Y
);
317 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
319 TRACE("(%p): Not an overlay surface\n", This
);
320 return WINEDDERR_NOTAOVERLAYSURFACE
;
326 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface
*iface
, LONG
*X
, LONG
*Y
) {
327 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
329 FIXME("(%p)->(%p,%p) Stub!\n", This
, X
, Y
);
331 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
333 TRACE("(%p): Not an overlay surface\n", This
);
334 return WINEDDERR_NOTAOVERLAYSURFACE
;
340 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface
*iface
, DWORD Flags
, IWineD3DSurface
*Ref
) {
341 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
342 IWineD3DSurfaceImpl
*RefImpl
= (IWineD3DSurfaceImpl
*) Ref
;
344 FIXME("(%p)->(%08x,%p) Stub!\n", This
, Flags
, RefImpl
);
346 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
348 TRACE("(%p): Not an overlay surface\n", This
);
349 return WINEDDERR_NOTAOVERLAYSURFACE
;
355 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface
*iface
, RECT
*SrcRect
, IWineD3DSurface
*DstSurface
, RECT
*DstRect
, DWORD Flags
, WINEDDOVERLAYFX
*FX
) {
356 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
357 IWineD3DSurfaceImpl
*Dst
= (IWineD3DSurfaceImpl
*) DstSurface
;
358 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This
, SrcRect
, Dst
, DstRect
, Flags
, FX
);
360 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
362 TRACE("(%p): Not an overlay surface\n", This
);
363 return WINEDDERR_NOTAOVERLAYSURFACE
;
369 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface
*iface
, IWineD3DClipper
*clipper
)
371 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
372 TRACE("(%p)->(%p)\n", This
, clipper
);
374 This
->clipper
= clipper
;
378 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface
*iface
, IWineD3DClipper
**clipper
)
380 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
381 TRACE("(%p)->(%p)\n", This
, clipper
);
383 *clipper
= This
->clipper
;
385 IWineD3DClipper_AddRef(*clipper
);
390 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface
*iface
, IWineD3DBase
*container
) {
391 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
393 TRACE("This %p, container %p\n", This
, container
);
395 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
397 TRACE("Setting container to %p from %p\n", container
, This
->container
);
398 This
->container
= container
;
403 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface
*iface
, WINED3DFORMAT format
) {
404 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
405 const StaticPixelFormatDesc
*formatEntry
= getFormatDescEntry(format
, NULL
, NULL
);
407 if (This
->resource
.format
!= WINED3DFMT_UNKNOWN
) {
408 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This
);
409 return WINED3DERR_INVALIDCALL
;
412 TRACE("(%p) : Setting texture format to (%d,%s)\n", This
, format
, debug_d3dformat(format
));
413 if (format
== WINED3DFMT_UNKNOWN
) {
414 This
->resource
.size
= 0;
415 } else if (format
== WINED3DFMT_DXT1
) {
416 /* DXT1 is half byte per pixel */
417 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4)) >> 1;
419 } else if (format
== WINED3DFMT_DXT2
|| format
== WINED3DFMT_DXT3
||
420 format
== WINED3DFMT_DXT4
|| format
== WINED3DFMT_DXT5
) {
421 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4));
423 unsigned char alignment
= This
->resource
.wineD3DDevice
->surface_alignment
;
424 This
->resource
.size
= ((This
->pow2Width
* formatEntry
->bpp
) + alignment
- 1) & ~(alignment
- 1);
425 This
->resource
.size
*= This
->pow2Height
;
428 if (format
!= WINED3DFMT_UNKNOWN
) {
429 This
->bytesPerPixel
= formatEntry
->bpp
;
431 This
->bytesPerPixel
= 0;
434 This
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== format
) ? SFLAG_LOCKABLE
: 0;
436 This
->resource
.format
= format
;
438 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This
, This
->resource
.size
, This
->bytesPerPixel
);
443 HRESULT
IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface
*iface
) {
444 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
450 const StaticPixelFormatDesc
*formatEntry
= getFormatDescEntry(This
->resource
.format
, NULL
, NULL
);
453 switch (This
->bytesPerPixel
) {
456 /* Allocate extra space to store the RGB bit masks. */
457 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
461 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
465 /* Allocate extra space for a palette. */
466 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
467 sizeof(BITMAPINFOHEADER
)
469 * (1 << (This
->bytesPerPixel
* 8)));
474 return E_OUTOFMEMORY
;
476 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
477 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
478 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
479 * add an extra line to the dib section
481 GetSystemInfo(&sysInfo
);
482 if( ((This
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4) {
484 TRACE("Adding an extra line to the dib section\n");
487 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
488 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
489 b_info
->bmiHeader
.biWidth
= IWineD3DSurface_GetPitch(iface
) / This
->bytesPerPixel
;
490 b_info
->bmiHeader
.biHeight
= -This
->currentDesc
.Height
-extraline
;
491 b_info
->bmiHeader
.biSizeImage
= ( This
->currentDesc
.Height
+ extraline
) * IWineD3DSurface_GetPitch(iface
);
492 b_info
->bmiHeader
.biPlanes
= 1;
493 b_info
->bmiHeader
.biBitCount
= This
->bytesPerPixel
* 8;
495 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
496 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
497 b_info
->bmiHeader
.biClrUsed
= 0;
498 b_info
->bmiHeader
.biClrImportant
= 0;
500 /* Get the bit masks */
501 masks
= (DWORD
*) &(b_info
->bmiColors
);
502 switch (This
->resource
.format
) {
503 case WINED3DFMT_R8G8B8
:
504 usage
= DIB_RGB_COLORS
;
505 b_info
->bmiHeader
.biCompression
= BI_RGB
;
508 case WINED3DFMT_X1R5G5B5
:
509 case WINED3DFMT_A1R5G5B5
:
510 case WINED3DFMT_A4R4G4B4
:
511 case WINED3DFMT_X4R4G4B4
:
512 case WINED3DFMT_R3G3B2
:
513 case WINED3DFMT_A8R3G3B2
:
514 case WINED3DFMT_A2B10G10R10
:
515 case WINED3DFMT_A8B8G8R8
:
516 case WINED3DFMT_X8B8G8R8
:
517 case WINED3DFMT_A2R10G10B10
:
518 case WINED3DFMT_R5G6B5
:
519 case WINED3DFMT_A16B16G16R16
:
521 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
522 masks
[0] = formatEntry
->redMask
;
523 masks
[1] = formatEntry
->greenMask
;
524 masks
[2] = formatEntry
->blueMask
;
528 /* Don't know palette */
529 b_info
->bmiHeader
.biCompression
= BI_RGB
;
536 HeapFree(GetProcessHeap(), 0, b_info
);
537 return HRESULT_FROM_WIN32(GetLastError());
540 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
);
541 This
->dib
.DIBsection
= CreateDIBSection(ddc
, b_info
, usage
, &This
->dib
.bitmap_data
, 0 /* Handle */, 0 /* Offset */);
544 if (!This
->dib
.DIBsection
) {
545 ERR("CreateDIBSection failed!\n");
546 HeapFree(GetProcessHeap(), 0, b_info
);
547 return HRESULT_FROM_WIN32(GetLastError());
550 TRACE("DIBSection at : %p\n", This
->dib
.bitmap_data
);
551 /* copy the existing surface to the dib section */
552 if(This
->resource
.allocatedMemory
) {
553 memcpy(This
->dib
.bitmap_data
, This
->resource
.allocatedMemory
, b_info
->bmiHeader
.biSizeImage
);
555 /* This is to make LockRect read the gl Texture although memory is allocated */
556 This
->Flags
&= ~SFLAG_INSYSMEM
;
558 This
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
560 HeapFree(GetProcessHeap(), 0, b_info
);
562 /* Now allocate a HDC */
563 This
->hDC
= CreateCompatibleDC(0);
564 This
->dib
.holdbitmap
= SelectObject(This
->hDC
, This
->dib
.DIBsection
);
565 TRACE("using wined3d palette %p\n", This
->palette
);
566 SelectPalette(This
->hDC
,
567 This
->palette
? This
->palette
->hpal
: 0,
570 This
->Flags
|= SFLAG_DIBSECTION
;
572 HeapFree(GetProcessHeap(), 0, This
->resource
.heapMemory
);
573 This
->resource
.heapMemory
= NULL
;
578 /*****************************************************************************
581 * Helper function that fills a memory area with a specific color
584 * buf: memory address to start filling at
585 * width, height: Dimensions of the area to fill
586 * bpp: Bit depth of the surface
587 * lPitch: pitch of the surface
588 * color: Color to fill with
590 *****************************************************************************/
592 _Blt_ColorFill(BYTE
*buf
,
593 int width
, int height
,
594 int bpp
, LONG lPitch
,
602 #define COLORFILL_ROW(type) \
604 type *d = (type *) buf; \
605 for (x = 0; x < width; x++) \
606 d[x] = (type) color; \
611 case 1: COLORFILL_ROW(BYTE
)
612 case 2: COLORFILL_ROW(WORD
)
616 for (x
= 0; x
< width
; x
++,d
+=3)
618 d
[0] = (color
) & 0xFF;
619 d
[1] = (color
>> 8) & 0xFF;
620 d
[2] = (color
>>16) & 0xFF;
624 case 4: COLORFILL_ROW(DWORD
)
626 FIXME("Color fill not implemented for bpp %d!\n", bpp
*8);
627 return WINED3DERR_NOTAVAILABLE
;
632 /* Now copy first row */
634 for (y
= 1; y
< height
; y
++)
637 memcpy(buf
, first
, width
* bpp
);
642 /*****************************************************************************
643 * IWineD3DSurface::Blt, SW emulation version
645 * Performs blits to a surface, eigher from a source of source-less blts
646 * This is the main functionality of DirectDraw
649 * DestRect: Destination rectangle to write to
650 * SrcSurface: Source surface, can be NULL
651 * SrcRect: Source rectangle
652 *****************************************************************************/
654 IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface
*iface
,
656 IWineD3DSurface
*SrcSurface
,
659 WINEDDBLTFX
*DDBltFx
,
660 WINED3DTEXTUREFILTERTYPE Filter
)
662 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
663 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
665 HRESULT ret
= WINED3D_OK
;
666 WINED3DLOCKED_RECT dlock
, slock
;
667 WINED3DFORMAT dfmt
= WINED3DFMT_UNKNOWN
, sfmt
= WINED3DFMT_UNKNOWN
;
668 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
670 const StaticPixelFormatDesc
*sEntry
, *dEntry
;
672 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This
, DestRect
, Src
, SrcRect
, Flags
, DDBltFx
);
674 if (TRACE_ON(d3d_surface
))
676 if (DestRect
) TRACE("\tdestrect :%dx%d-%dx%d\n",
677 DestRect
->left
, DestRect
->top
, DestRect
->right
, DestRect
->bottom
);
678 if (SrcRect
) TRACE("\tsrcrect :%dx%d-%dx%d\n",
679 SrcRect
->left
, SrcRect
->top
, SrcRect
->right
, SrcRect
->bottom
);
682 DDRAW_dump_DDBLT(Flags
);
683 if (Flags
& WINEDDBLT_DDFX
)
686 DDRAW_dump_DDBLTFX(DDBltFx
->dwDDFX
);
691 if ( (This
->Flags
& SFLAG_LOCKED
) || ((Src
!= NULL
) && (Src
->Flags
& SFLAG_LOCKED
)))
693 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
694 return WINEDDERR_SURFACEBUSY
;
697 if(Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
) {
698 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
699 FIXME("Filters not supported in software blit\n");
704 IWineD3DSurface_LockRect(iface
, &dlock
, NULL
, 0);
705 dfmt
= This
->resource
.format
;
708 sEntry
= getFormatDescEntry(sfmt
, NULL
, NULL
);
715 IWineD3DSurface_LockRect(SrcSurface
, &slock
, NULL
, WINED3DLOCK_READONLY
);
716 sfmt
= Src
->resource
.format
;
718 sEntry
= getFormatDescEntry(sfmt
, NULL
, NULL
);
719 dfmt
= This
->resource
.format
;
720 dEntry
= getFormatDescEntry(dfmt
, NULL
, NULL
);
721 IWineD3DSurface_LockRect(iface
, &dlock
,NULL
,0);
724 if (!DDBltFx
|| !(DDBltFx
->dwDDFX
)) Flags
&= ~WINEDDBLT_DDFX
;
726 if (sEntry
->isFourcc
&& dEntry
->isFourcc
)
730 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
731 ret
= WINED3DERR_WRONGTEXTUREFORMAT
;
734 memcpy(dlock
.pBits
, slock
.pBits
, This
->resource
.size
);
738 if (sEntry
->isFourcc
&& !dEntry
->isFourcc
)
740 FIXME("DXTC decompression not supported right now\n");
746 memcpy(&xdst
,DestRect
,sizeof(xdst
));
751 xdst
.bottom
= This
->currentDesc
.Height
;
753 xdst
.right
= This
->currentDesc
.Width
;
758 memcpy(&xsrc
,SrcRect
,sizeof(xsrc
));
765 xsrc
.bottom
= Src
->currentDesc
.Height
;
767 xsrc
.right
= Src
->currentDesc
.Width
;
771 memset(&xsrc
,0,sizeof(xsrc
));
775 /* First check for the validity of source / destination rectangles. This was
776 * verified using a test application + by MSDN.
779 ((xsrc
.bottom
> Src
->currentDesc
.Height
) || (xsrc
.bottom
< 0) ||
780 (xsrc
.top
> Src
->currentDesc
.Height
) || (xsrc
.top
< 0) ||
781 (xsrc
.left
> Src
->currentDesc
.Width
) || (xsrc
.left
< 0) ||
782 (xsrc
.right
> Src
->currentDesc
.Width
) || (xsrc
.right
< 0) ||
783 (xsrc
.right
< xsrc
.left
) || (xsrc
.bottom
< xsrc
.top
)))
785 WARN("Application gave us bad source rectangle for Blt.\n");
786 ret
= WINEDDERR_INVALIDRECT
;
789 /* For the Destination rect, it can be out of bounds on the condition that a clipper
790 * is set for the given surface.
792 if ((/*This->clipper == NULL*/ TRUE
) &&
793 ((xdst
.bottom
> This
->currentDesc
.Height
) || (xdst
.bottom
< 0) ||
794 (xdst
.top
> This
->currentDesc
.Height
) || (xdst
.top
< 0) ||
795 (xdst
.left
> This
->currentDesc
.Width
) || (xdst
.left
< 0) ||
796 (xdst
.right
> This
->currentDesc
.Width
) || (xdst
.right
< 0) ||
797 (xdst
.right
< xdst
.left
) || (xdst
.bottom
< xdst
.top
)))
799 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
800 ret
= WINEDDERR_INVALIDRECT
;
804 /* Now handle negative values in the rectangles. Warning: only supported for now
805 in the 'simple' cases (ie not in any stretching / rotation cases).
807 First, the case where nothing is to be done.
809 if (((xdst
.bottom
<= 0) || (xdst
.right
<= 0) ||
810 (xdst
.top
>= (int) This
->currentDesc
.Height
) ||
811 (xdst
.left
>= (int) This
->currentDesc
.Width
)) ||
813 ((xsrc
.bottom
<= 0) || (xsrc
.right
<= 0) ||
814 (xsrc
.top
>= (int) Src
->currentDesc
.Height
) ||
815 (xsrc
.left
>= (int) Src
->currentDesc
.Width
)) ))
817 TRACE("Nothing to be done !\n");
821 /* The easy case : the source-less blits.... */
825 RECT temp_rect
; /* No idea if intersect rect can be the same as one of the source rect */
829 full_rect
.right
= This
->currentDesc
.Width
;
830 full_rect
.bottom
= This
->currentDesc
.Height
;
831 IntersectRect(&temp_rect
, &full_rect
, &xdst
);
836 /* Only handle clipping on the destination rectangle */
837 int clip_horiz
= (xdst
.left
< 0) || (xdst
.right
> (int) This
->currentDesc
.Width
);
838 int clip_vert
= (xdst
.top
< 0) || (xdst
.bottom
> (int) This
->currentDesc
.Height
);
839 if (clip_vert
|| clip_horiz
)
841 /* Now check if this is a special case or not... */
842 if ((((xdst
.bottom
- xdst
.top
) != (xsrc
.bottom
- xsrc
.top
)) && clip_vert
) ||
843 (((xdst
.right
- xdst
.left
) != (xsrc
.right
- xsrc
.left
)) && clip_horiz
) ||
844 (Flags
& WINEDDBLT_DDFX
))
846 WARN("Out of screen rectangle in special case. Not handled right now.\n");
852 if (xdst
.left
< 0) { xsrc
.left
-= xdst
.left
; xdst
.left
= 0; }
853 if (xdst
.right
> This
->currentDesc
.Width
)
855 xsrc
.right
-= (xdst
.right
- (int) This
->currentDesc
.Width
);
856 xdst
.right
= (int) This
->currentDesc
.Width
;
863 xsrc
.top
-= xdst
.top
;
866 if (xdst
.bottom
> This
->currentDesc
.Height
)
868 xsrc
.bottom
-= (xdst
.bottom
- (int) This
->currentDesc
.Height
);
869 xdst
.bottom
= (int) This
->currentDesc
.Height
;
872 /* And check if after clipping something is still to be done... */
873 if ((xdst
.bottom
<= 0) || (xdst
.right
<= 0) ||
874 (xdst
.top
>= (int) This
->currentDesc
.Height
) ||
875 (xdst
.left
>= (int) This
->currentDesc
.Width
) ||
876 (xsrc
.bottom
<= 0) || (xsrc
.right
<= 0) ||
877 (xsrc
.top
>= (int) Src
->currentDesc
.Height
) ||
878 (xsrc
.left
>= (int) Src
->currentDesc
.Width
))
880 TRACE("Nothing to be done after clipping !\n");
886 bpp
= This
->bytesPerPixel
;
887 srcheight
= xsrc
.bottom
- xsrc
.top
;
888 srcwidth
= xsrc
.right
- xsrc
.left
;
889 dstheight
= xdst
.bottom
- xdst
.top
;
890 dstwidth
= xdst
.right
- xdst
.left
;
891 width
= (xdst
.right
- xdst
.left
) * bpp
;
893 assert(width
<= dlock
.Pitch
);
895 dbuf
= (BYTE
*)dlock
.pBits
+(xdst
.top
*dlock
.Pitch
)+(xdst
.left
*bpp
);
897 if (Flags
& WINEDDBLT_WAIT
)
899 Flags
&= ~WINEDDBLT_WAIT
;
901 if (Flags
& WINEDDBLT_ASYNC
)
903 static BOOL displayed
= FALSE
;
905 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
907 Flags
&= ~WINEDDBLT_ASYNC
;
909 if (Flags
& WINEDDBLT_DONOTWAIT
)
911 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
912 static BOOL displayed
= FALSE
;
914 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
916 Flags
&= ~WINEDDBLT_DONOTWAIT
;
919 /* First, all the 'source-less' blits */
920 if (Flags
& WINEDDBLT_COLORFILL
)
922 ret
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
,
923 dlock
.Pitch
, DDBltFx
->u5
.dwFillColor
);
924 Flags
&= ~WINEDDBLT_COLORFILL
;
927 if (Flags
& WINEDDBLT_DEPTHFILL
)
929 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
931 if (Flags
& WINEDDBLT_ROP
)
933 /* Catch some degenerate cases here */
934 switch(DDBltFx
->dwROP
)
937 ret
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,0);
939 case 0xAA0029: /* No-op */
942 ret
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,~0);
944 case SRCCOPY
: /* well, we do that below ? */
947 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx
->dwROP
, DDBltFx
->u5
.lpDDSPattern
);
950 Flags
&= ~WINEDDBLT_ROP
;
952 if (Flags
& WINEDDBLT_DDROPS
)
954 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx
->dwDDROP
, DDBltFx
->u5
.lpDDSPattern
);
956 /* Now the 'with source' blits */
960 int sx
, xinc
, sy
, yinc
;
962 if (!dstwidth
|| !dstheight
) /* hmm... stupid program ? */
964 sbase
= (BYTE
*)slock
.pBits
+(xsrc
.top
*slock
.Pitch
)+xsrc
.left
*bpp
;
965 xinc
= (srcwidth
<< 16) / dstwidth
;
966 yinc
= (srcheight
<< 16) / dstheight
;
970 /* No effects, we can cheat here */
971 if (dstwidth
== srcwidth
)
973 if (dstheight
== srcheight
)
975 /* No stretching in either direction. This needs to be as
976 * fast as possible */
979 /* check for overlapping surfaces */
980 if (SrcSurface
!= iface
|| xdst
.top
< xsrc
.top
||
981 xdst
.right
<= xsrc
.left
|| xsrc
.right
<= xdst
.left
)
983 /* no overlap, or dst above src, so copy from top downwards */
984 for (y
= 0; y
< dstheight
; y
++)
986 memcpy(dbuf
, sbuf
, width
);
991 else if (xdst
.top
> xsrc
.top
) /* copy from bottom upwards */
993 sbuf
+= (slock
.Pitch
*dstheight
);
994 dbuf
+= (dlock
.Pitch
*dstheight
);
995 for (y
= 0; y
< dstheight
; y
++)
999 memcpy(dbuf
, sbuf
, width
);
1002 else /* src and dst overlapping on the same line, use memmove */
1004 for (y
= 0; y
< dstheight
; y
++)
1006 memmove(dbuf
, sbuf
, width
);
1007 sbuf
+= slock
.Pitch
;
1008 dbuf
+= dlock
.Pitch
;
1012 /* Stretching in Y direction only */
1013 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
) {
1014 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1015 memcpy(dbuf
, sbuf
, width
);
1016 dbuf
+= dlock
.Pitch
;
1022 /* Stretching in X direction */
1024 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
)
1026 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1028 if ((sy
>> 16) == (last_sy
>> 16))
1030 /* this sourcerow is the same as last sourcerow -
1031 * copy already stretched row
1033 memcpy(dbuf
, dbuf
- dlock
.Pitch
, width
);
1037 #define STRETCH_ROW(type) { \
1038 type *s = (type *) sbuf, *d = (type *) dbuf; \
1039 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1040 d[x] = s[sx >> 16]; \
1045 case 1: STRETCH_ROW(BYTE
)
1046 case 2: STRETCH_ROW(WORD
)
1047 case 4: STRETCH_ROW(DWORD
)
1051 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
1055 s
= sbuf
+3*(sx
>>16);
1056 pixel
= s
[0]|(s
[1]<<8)|(s
[2]<<16);
1057 d
[0] = (pixel
)&0xff;
1058 d
[1] = (pixel
>> 8)&0xff;
1059 d
[2] = (pixel
>>16)&0xff;
1065 FIXME("Stretched blit not implemented for bpp %d!\n", bpp
*8);
1066 ret
= WINED3DERR_NOTAVAILABLE
;
1071 dbuf
+= dlock
.Pitch
;
1078 LONG dstyinc
= dlock
.Pitch
, dstxinc
= bpp
;
1079 DWORD keylow
= 0xFFFFFFFF, keyhigh
= 0, keymask
= 0xFFFFFFFF;
1080 DWORD destkeylow
= 0x0, destkeyhigh
= 0xFFFFFFFF, destkeymask
= 0xFFFFFFFF;
1081 if (Flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
1083 /* The color keying flags are checked for correctness in ddraw */
1084 if (Flags
& WINEDDBLT_KEYSRC
)
1086 keylow
= Src
->SrcBltCKey
.dwColorSpaceLowValue
;
1087 keyhigh
= Src
->SrcBltCKey
.dwColorSpaceHighValue
;
1089 else if (Flags
& WINEDDBLT_KEYSRCOVERRIDE
)
1091 keylow
= DDBltFx
->ddckSrcColorkey
.dwColorSpaceLowValue
;
1092 keyhigh
= DDBltFx
->ddckSrcColorkey
.dwColorSpaceHighValue
;
1095 if (Flags
& WINEDDBLT_KEYDEST
)
1097 /* Destination color keys are taken from the source surface ! */
1098 destkeylow
= Src
->DestBltCKey
.dwColorSpaceLowValue
;
1099 destkeyhigh
= Src
->DestBltCKey
.dwColorSpaceHighValue
;
1101 else if (Flags
& WINEDDBLT_KEYDESTOVERRIDE
)
1103 destkeylow
= DDBltFx
->ddckDestColorkey
.dwColorSpaceLowValue
;
1104 destkeyhigh
= DDBltFx
->ddckDestColorkey
.dwColorSpaceHighValue
;
1113 keymask
= sEntry
->redMask
|
1117 Flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
1120 if (Flags
& WINEDDBLT_DDFX
)
1122 LPBYTE dTopLeft
, dTopRight
, dBottomLeft
, dBottomRight
, tmp
;
1125 dTopRight
= dbuf
+((dstwidth
-1)*bpp
);
1126 dBottomLeft
= dTopLeft
+((dstheight
-1)*dlock
.Pitch
);
1127 dBottomRight
= dBottomLeft
+((dstwidth
-1)*bpp
);
1129 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
1131 /* I don't think we need to do anything about this flag */
1132 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1134 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
1137 dTopRight
= dTopLeft
;
1140 dBottomRight
= dBottomLeft
;
1142 dstxinc
= dstxinc
*-1;
1144 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
1147 dTopLeft
= dBottomLeft
;
1150 dTopRight
= dBottomRight
;
1152 dstyinc
= dstyinc
*-1;
1154 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
1156 /* I don't think we need to do anything about this flag */
1157 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1159 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
1162 dBottomRight
= dTopLeft
;
1165 dBottomLeft
= dTopRight
;
1167 dstxinc
= dstxinc
* -1;
1168 dstyinc
= dstyinc
* -1;
1170 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
1173 dTopLeft
= dBottomLeft
;
1174 dBottomLeft
= dBottomRight
;
1175 dBottomRight
= dTopRight
;
1180 dstxinc
= dstxinc
* -1;
1182 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
1185 dTopLeft
= dTopRight
;
1186 dTopRight
= dBottomRight
;
1187 dBottomRight
= dBottomLeft
;
1192 dstyinc
= dstyinc
* -1;
1194 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
1196 /* I don't think we need to do anything about this flag */
1197 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1200 Flags
&= ~(WINEDDBLT_DDFX
);
1203 #define COPY_COLORKEY_FX(type) { \
1204 type *s, *d = (type *) dbuf, *dx, tmp; \
1205 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1206 s = (type*)(sbase + (sy >> 16) * slock.Pitch); \
1208 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1209 tmp = s[sx >> 16]; \
1210 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1211 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1214 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1216 d = (type*)(((LPBYTE)d)+dstyinc); \
1221 case 1: COPY_COLORKEY_FX(BYTE
)
1222 case 2: COPY_COLORKEY_FX(WORD
)
1223 case 4: COPY_COLORKEY_FX(DWORD
)
1226 LPBYTE s
,d
= dbuf
, dx
;
1227 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
)
1229 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1231 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
1233 DWORD pixel
, dpixel
= 0;
1234 s
= sbuf
+3*(sx
>>16);
1235 pixel
= s
[0]|(s
[1]<<8)|(s
[2]<<16);
1236 dpixel
= dx
[0]|(dx
[1]<<8)|(dx
[2]<<16);
1237 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
) &&
1238 ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
1240 dx
[0] = (pixel
)&0xff;
1241 dx
[1] = (pixel
>> 8)&0xff;
1242 dx
[2] = (pixel
>>16)&0xff;
1251 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1252 (Flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
*8);
1253 ret
= WINED3DERR_NOTAVAILABLE
;
1255 #undef COPY_COLORKEY_FX
1261 if (Flags
&& FIXME_ON(d3d_surface
))
1263 FIXME("\tUnsupported flags: %08x\n", Flags
);
1267 IWineD3DSurface_UnlockRect(iface
);
1268 if (SrcSurface
&& SrcSurface
!= iface
) IWineD3DSurface_UnlockRect(SrcSurface
);
1272 /*****************************************************************************
1273 * IWineD3DSurface::BltFast, SW emulation version
1275 * This is the software implementation of BltFast, as used by GDI surfaces
1276 * and as a fallback for OpenGL surfaces. This code is taken from the old
1277 * DirectDraw code, and was originally written by TransGaming.
1282 * Source: Source surface to copy from
1283 * rsrc: Source rectangle
1287 * WINED3D_OK on success
1289 *****************************************************************************/
1291 IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface
*iface
,
1294 IWineD3DSurface
*Source
,
1298 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
1299 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) Source
;
1301 int bpp
, w
, h
, x
, y
;
1302 WINED3DLOCKED_RECT dlock
,slock
;
1303 HRESULT ret
= WINED3D_OK
;
1305 RECT lock_src
, lock_dst
, lock_union
;
1307 const StaticPixelFormatDesc
*sEntry
, *dEntry
;
1309 if (TRACE_ON(d3d_surface
))
1311 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This
,dstx
,dsty
,Src
,rsrc
,trans
);
1315 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc
->left
,rsrc
->top
,
1316 rsrc
->right
,rsrc
->bottom
);
1320 TRACE(" srcrect: NULL\n");
1324 if ((This
->Flags
& SFLAG_LOCKED
) ||
1325 ((Src
!= NULL
) && (Src
->Flags
& SFLAG_LOCKED
)))
1327 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1328 return WINEDDERR_SURFACEBUSY
;
1333 WARN("rsrc is NULL!\n");
1337 rsrc
->right
= Src
->currentDesc
.Width
;
1338 rsrc
->bottom
= Src
->currentDesc
.Height
;
1341 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1342 if ((rsrc
->bottom
> Src
->currentDesc
.Height
) || (rsrc
->bottom
< 0) ||
1343 (rsrc
->top
> Src
->currentDesc
.Height
) || (rsrc
->top
< 0) ||
1344 (rsrc
->left
> Src
->currentDesc
.Width
) || (rsrc
->left
< 0) ||
1345 (rsrc
->right
> Src
->currentDesc
.Width
) || (rsrc
->right
< 0) ||
1346 (rsrc
->right
< rsrc
->left
) || (rsrc
->bottom
< rsrc
->top
))
1348 WARN("Application gave us bad source rectangle for BltFast.\n");
1349 return WINEDDERR_INVALIDRECT
;
1352 h
= rsrc
->bottom
- rsrc
->top
;
1353 if (h
> This
->currentDesc
.Height
-dsty
) h
= This
->currentDesc
.Height
-dsty
;
1354 if (h
> Src
->currentDesc
.Height
-rsrc
->top
) h
=Src
->currentDesc
.Height
-rsrc
->top
;
1355 if (h
<= 0) return WINEDDERR_INVALIDRECT
;
1357 w
= rsrc
->right
- rsrc
->left
;
1358 if (w
> This
->currentDesc
.Width
-dstx
) w
= This
->currentDesc
.Width
-dstx
;
1359 if (w
> Src
->currentDesc
.Width
-rsrc
->left
) w
= Src
->currentDesc
.Width
-rsrc
->left
;
1360 if (w
<= 0) return WINEDDERR_INVALIDRECT
;
1362 /* Now compute the locking rectangle... */
1363 lock_src
.left
= rsrc
->left
;
1364 lock_src
.top
= rsrc
->top
;
1365 lock_src
.right
= lock_src
.left
+ w
;
1366 lock_src
.bottom
= lock_src
.top
+ h
;
1368 lock_dst
.left
= dstx
;
1369 lock_dst
.top
= dsty
;
1370 lock_dst
.right
= dstx
+ w
;
1371 lock_dst
.bottom
= dsty
+ h
;
1373 bpp
= This
->bytesPerPixel
;
1375 /* We need to lock the surfaces, or we won't get refreshes when done. */
1380 UnionRect(&lock_union
, &lock_src
, &lock_dst
);
1382 /* Lock the union of the two rectangles */
1383 ret
= IWineD3DSurface_LockRect(iface
, &dlock
, &lock_union
, 0);
1384 if(ret
!= WINED3D_OK
) goto error
;
1386 pitch
= dlock
.Pitch
;
1387 slock
.Pitch
= dlock
.Pitch
;
1389 /* Since slock was originally copied from this surface's description, we can just reuse it */
1390 assert(This
->resource
.allocatedMemory
!= NULL
);
1391 sbuf
= This
->resource
.allocatedMemory
+ lock_src
.top
* pitch
+ lock_src
.left
* bpp
;
1392 dbuf
= This
->resource
.allocatedMemory
+ lock_dst
.top
* pitch
+ lock_dst
.left
* bpp
;
1393 sEntry
= getFormatDescEntry(Src
->resource
.format
, NULL
, NULL
);
1398 ret
= IWineD3DSurface_LockRect(Source
, &slock
, &lock_src
, WINED3DLOCK_READONLY
);
1399 if(ret
!= WINED3D_OK
) goto error
;
1400 ret
= IWineD3DSurface_LockRect(iface
, &dlock
, &lock_dst
, 0);
1401 if(ret
!= WINED3D_OK
) goto error
;
1405 TRACE("Dst is at %p, Src is at %p\n", dbuf
, sbuf
);
1407 sEntry
= getFormatDescEntry(Src
->resource
.format
, NULL
, NULL
);
1408 dEntry
= getFormatDescEntry(This
->resource
.format
, NULL
, NULL
);
1411 /* Handle first the FOURCC surfaces... */
1412 if (sEntry
->isFourcc
&& dEntry
->isFourcc
)
1414 TRACE("Fourcc -> Fourcc copy\n");
1416 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1418 FIXME("offset for destination surface is not supported\n");
1419 if (Src
->resource
.format
!= This
->resource
.format
)
1421 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1422 ret
= WINED3DERR_WRONGTEXTUREFORMAT
;
1425 /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1426 memcpy(dbuf
, sbuf
, This
->resource
.size
);
1429 if (sEntry
->isFourcc
&& !dEntry
->isFourcc
)
1431 /* TODO: Use the libtxc_dxtn.so shared library to do
1432 * software decompression
1434 ERR("DXTC decompression not supported by now\n");
1438 if (trans
& (WINEDDBLTFAST_SRCCOLORKEY
| WINEDDBLTFAST_DESTCOLORKEY
))
1440 DWORD keylow
, keyhigh
;
1441 TRACE("Color keyed copy\n");
1442 if (trans
& WINEDDBLTFAST_SRCCOLORKEY
)
1444 keylow
= Src
->SrcBltCKey
.dwColorSpaceLowValue
;
1445 keyhigh
= Src
->SrcBltCKey
.dwColorSpaceHighValue
;
1449 /* I'm not sure if this is correct */
1450 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1451 keylow
= This
->DestBltCKey
.dwColorSpaceLowValue
;
1452 keyhigh
= This
->DestBltCKey
.dwColorSpaceHighValue
;
1455 #define COPYBOX_COLORKEY(type) { \
1457 s = (type *) sbuf; \
1458 d = (type *) dbuf; \
1459 for (y = 0; y < h; y++) { \
1460 for (x = 0; x < w; x++) { \
1462 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1464 s = (type *)((BYTE *)s + slock.Pitch); \
1465 d = (type *)((BYTE *)d + dlock.Pitch); \
1471 case 1: COPYBOX_COLORKEY(BYTE
)
1472 case 2: COPYBOX_COLORKEY(WORD
)
1473 case 4: COPYBOX_COLORKEY(DWORD
)
1480 for (y
= 0; y
< h
; y
++)
1482 for (x
= 0; x
< w
* 3; x
+= 3)
1484 tmp
= (DWORD
)s
[x
] + ((DWORD
)s
[x
+ 1] << 8) + ((DWORD
)s
[x
+ 2] << 16);
1485 if (tmp
< keylow
|| tmp
> keyhigh
)
1487 d
[x
+ 0] = s
[x
+ 0];
1488 d
[x
+ 1] = s
[x
+ 1];
1489 d
[x
+ 2] = s
[x
+ 2];
1498 FIXME("Source color key blitting not supported for bpp %d\n",bpp
*8);
1499 ret
= WINED3DERR_NOTAVAILABLE
;
1502 #undef COPYBOX_COLORKEY
1503 TRACE("Copy Done\n");
1507 int width
= w
* bpp
;
1508 TRACE("NO color key copy\n");
1509 for (y
= 0; y
< h
; y
++)
1511 /* This is pretty easy, a line for line memcpy */
1512 memcpy(dbuf
, sbuf
, width
);
1513 sbuf
+= slock
.Pitch
;
1514 dbuf
+= dlock
.Pitch
;
1516 TRACE("Copy done\n");
1522 IWineD3DSurface_UnlockRect(iface
);
1526 IWineD3DSurface_UnlockRect(iface
);
1527 IWineD3DSurface_UnlockRect(Source
);
1533 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface
*iface
, WINED3DLOCKED_RECT
* pLockedRect
, CONST RECT
* pRect
, DWORD Flags
)
1535 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1537 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1538 This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
1540 pLockedRect
->Pitch
= IWineD3DSurface_GetPitch(iface
);
1544 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
1545 This
->lockedRect
.left
= 0;
1546 This
->lockedRect
.top
= 0;
1547 This
->lockedRect
.right
= This
->currentDesc
.Width
;
1548 This
->lockedRect
.bottom
= This
->currentDesc
.Height
;
1550 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1551 &This
->lockedRect
, This
->lockedRect
.left
, This
->lockedRect
.top
,
1552 This
->lockedRect
.right
, This
->lockedRect
.bottom
);
1556 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1557 pRect
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
1559 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1560 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1561 * slightly different meaning compared to regular textures. For DXTn
1562 * textures Pitch is the size of a row of blocks, 4 high and "width"
1563 * long. The x offset is calculated differently as well, since moving 4
1564 * pixels to the right actually moves an entire 4x4 block to right, ie
1565 * 16 bytes (8 in case of DXT1). */
1566 if (This
->resource
.format
== WINED3DFMT_DXT1
)
1568 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
/ 4) + (pRect
->left
* 2);
1570 else if (This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
1571 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
)
1573 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
/ 4) + (pRect
->left
* 4);
1577 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+
1578 (pLockedRect
->Pitch
* pRect
->top
) +
1579 (pRect
->left
* This
->bytesPerPixel
);
1581 This
->lockedRect
.left
= pRect
->left
;
1582 This
->lockedRect
.top
= pRect
->top
;
1583 This
->lockedRect
.right
= pRect
->right
;
1584 This
->lockedRect
.bottom
= pRect
->bottom
;
1587 /* No dirtifying is needed for this surface implementation */
1588 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
);
1593 void WINAPI
IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface
*iface
) {
1594 ERR("Should not be called on base texture\n");