2 * IWineD3DSurface Implementation of management(non-rendering) functions
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009-2010 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in
)
40 float tmp
= fabs(*in
);
41 unsigned int mantissa
;
44 /* Deal with special numbers */
45 if (*in
== 0.0f
) return 0x0000;
46 if(isnan(*in
)) return 0x7C01;
47 if (isinf(*in
)) return (*in
< 0.0f
? 0xFC00 : 0x7c00);
49 if(tmp
< powf(2, 10)) {
54 }while(tmp
< powf(2, 10));
55 } else if(tmp
>= powf(2, 11)) {
60 }while(tmp
>= powf(2, 11));
63 mantissa
= (unsigned int) tmp
;
64 if(tmp
- mantissa
>= 0.5f
) mantissa
++; /* round to nearest, away from zero */
66 exp
+= 10; /* Normalize the mantissa */
67 exp
+= 15; /* Exponent is encoded with excess 15 */
69 if(exp
> 30) { /* too big */
70 ret
= 0x7c00; /* INF */
72 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
74 mantissa
= mantissa
>> 1;
77 ret
= mantissa
& 0x3ff;
79 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
82 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
86 /* *******************************************
87 IWineD3DSurface IUnknown parts follow
88 ******************************************* */
89 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface
*iface
, REFIID riid
, LPVOID
*ppobj
)
91 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
92 /* Warn ,but be nice about things */
93 TRACE("(%p)->(%s,%p)\n", This
,debugstr_guid(riid
),ppobj
);
95 if (IsEqualGUID(riid
, &IID_IUnknown
)
96 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
97 || IsEqualGUID(riid
, &IID_IWineD3DResource
)
98 || IsEqualGUID(riid
, &IID_IWineD3DSurface
)) {
99 IUnknown_AddRef((IUnknown
*)iface
);
104 return E_NOINTERFACE
;
107 ULONG WINAPI
IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface
*iface
) {
108 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
109 ULONG ref
= InterlockedIncrement(&This
->resource
.ref
);
110 TRACE("(%p) : AddRef increasing from %d\n", This
,ref
- 1);
114 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface
*iface
,
115 REFGUID riid
, const void *data
, DWORD data_size
, DWORD flags
)
117 return resource_set_private_data((IWineD3DResourceImpl
*)iface
, riid
, data
, data_size
, flags
);
120 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface
*iface
,
121 REFGUID guid
, void *data
, DWORD
*data_size
)
123 return resource_get_private_data((IWineD3DResourceImpl
*)iface
, guid
, data
, data_size
);
126 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface
*iface
, REFGUID refguid
)
128 return resource_free_private_data((IWineD3DResourceImpl
*)iface
, refguid
);
131 DWORD WINAPI
IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface
*iface
, DWORD priority
)
133 return resource_set_priority((IWineD3DResourceImpl
*)iface
, priority
);
136 DWORD WINAPI
IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface
*iface
)
138 return resource_get_priority((IWineD3DResourceImpl
*)iface
);
141 WINED3DRESOURCETYPE WINAPI
IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface
*iface
)
143 return resource_get_type((IWineD3DResourceImpl
*)iface
);
146 void * WINAPI
IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface
*iface
)
148 TRACE("iface %p.\n", iface
);
150 return ((IWineD3DSurfaceImpl
*)iface
)->resource
.parent
;
153 void WINAPI
IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface
*iface
, WINED3DSURFACE_DESC
*desc
)
155 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)iface
;
157 TRACE("iface %p, desc %p.\n", iface
, desc
);
159 desc
->format
= surface
->resource
.format
->id
;
160 desc
->resource_type
= surface
->resource
.resourceType
;
161 desc
->usage
= surface
->resource
.usage
;
162 desc
->pool
= surface
->resource
.pool
;
163 desc
->size
= surface
->resource
.size
; /* dx8 only */
164 desc
->multisample_type
= surface
->currentDesc
.MultiSampleType
;
165 desc
->multisample_quality
= surface
->currentDesc
.MultiSampleQuality
;
166 desc
->width
= surface
->currentDesc
.Width
;
167 desc
->height
= surface
->currentDesc
.Height
;
170 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface
*iface
, DWORD flags
)
172 TRACE("iface %p, flags %#x.\n", iface
, flags
);
176 case WINEDDGBS_CANBLT
:
177 case WINEDDGBS_ISBLTDONE
:
181 return WINED3DERR_INVALIDCALL
;
185 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface
*iface
, DWORD flags
)
187 /* XXX: DDERR_INVALIDSURFACETYPE */
189 TRACE("iface %p, flags %#x.\n", iface
, flags
);
193 case WINEDDGFS_CANFLIP
:
194 case WINEDDGFS_ISFLIPDONE
:
198 return WINED3DERR_INVALIDCALL
;
202 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface
*iface
) {
203 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
204 TRACE("(%p)\n", This
);
206 /* D3D8 and 9 loose full devices, ddraw only surfaces */
207 return This
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
210 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface
*iface
) {
211 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
212 TRACE("(%p)\n", This
);
214 /* So far we don't lose anything :) */
215 This
->flags
&= ~SFLAG_LOST
;
219 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
*Pal
) {
220 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
221 IWineD3DPaletteImpl
*PalImpl
= (IWineD3DPaletteImpl
*) Pal
;
222 TRACE("(%p)->(%p)\n", This
, Pal
);
224 if(This
->palette
== PalImpl
) {
225 TRACE("Nop palette change\n");
230 if (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
231 This
->palette
->flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
233 This
->palette
= PalImpl
;
237 if (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
238 PalImpl
->flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
240 return IWineD3DSurface_RealizePalette(iface
);
242 else return WINED3D_OK
;
245 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface
*iface
, DWORD flags
, const WINEDDCOLORKEY
*CKey
)
247 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
249 TRACE("iface %p, flags %#x, color_key %p.\n", iface
, flags
, CKey
);
251 if (flags
& WINEDDCKEY_COLORSPACE
)
253 FIXME(" colorkey value not supported (%08x) !\n", flags
);
254 return WINED3DERR_INVALIDCALL
;
257 /* Dirtify the surface, but only if a key was changed */
260 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
262 case WINEDDCKEY_DESTBLT
:
263 This
->DestBltCKey
= *CKey
;
264 This
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
267 case WINEDDCKEY_DESTOVERLAY
:
268 This
->DestOverlayCKey
= *CKey
;
269 This
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
272 case WINEDDCKEY_SRCOVERLAY
:
273 This
->SrcOverlayCKey
= *CKey
;
274 This
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
277 case WINEDDCKEY_SRCBLT
:
278 This
->SrcBltCKey
= *CKey
;
279 This
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
285 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
287 case WINEDDCKEY_DESTBLT
:
288 This
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
291 case WINEDDCKEY_DESTOVERLAY
:
292 This
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
295 case WINEDDCKEY_SRCOVERLAY
:
296 This
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
299 case WINEDDCKEY_SRCBLT
:
300 This
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
308 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
**Pal
) {
309 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
310 TRACE("(%p)->(%p)\n", This
, Pal
);
312 *Pal
= (IWineD3DPalette
*) This
->palette
;
316 DWORD WINAPI
IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface
*iface
)
318 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
319 const struct wined3d_format
*format
= This
->resource
.format
;
321 TRACE("(%p)\n", This
);
323 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
325 /* Since compressed formats are block based, pitch means the amount of
326 * bytes to the next row of block rather than the next row of pixels. */
327 UINT row_block_count
= (This
->currentDesc
.Width
+ format
->block_width
- 1) / format
->block_width
;
328 ret
= row_block_count
* format
->block_byte_count
;
332 unsigned char alignment
= This
->resource
.device
->surface_alignment
;
333 ret
= This
->resource
.format
->byte_count
* This
->currentDesc
.Width
; /* Bytes / row */
334 ret
= (ret
+ alignment
- 1) & ~(alignment
- 1);
336 TRACE("(%p) Returning %d\n", This
, ret
);
340 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface
*iface
, LONG X
, LONG Y
) {
341 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
344 TRACE("(%p)->(%d,%d) Stub!\n", This
, X
, Y
);
346 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
348 TRACE("(%p): Not an overlay surface\n", This
);
349 return WINEDDERR_NOTAOVERLAYSURFACE
;
352 w
= This
->overlay_destrect
.right
- This
->overlay_destrect
.left
;
353 h
= This
->overlay_destrect
.bottom
- This
->overlay_destrect
.top
;
354 This
->overlay_destrect
.left
= X
;
355 This
->overlay_destrect
.top
= Y
;
356 This
->overlay_destrect
.right
= X
+ w
;
357 This
->overlay_destrect
.bottom
= Y
+ h
;
359 IWineD3DSurface_DrawOverlay(iface
);
364 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface
*iface
, LONG
*X
, LONG
*Y
) {
365 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
368 TRACE("(%p)->(%p,%p)\n", This
, X
, Y
);
370 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
372 TRACE("(%p): Not an overlay surface\n", This
);
373 return WINEDDERR_NOTAOVERLAYSURFACE
;
376 if (!This
->overlay_dest
)
379 hr
= WINEDDERR_OVERLAYNOTVISIBLE
;
381 *X
= This
->overlay_destrect
.left
;
382 *Y
= This
->overlay_destrect
.top
;
386 TRACE("Returning 0x%08x, position %d, %d\n", hr
, *X
, *Y
);
390 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface
*iface
, DWORD flags
, IWineD3DSurface
*Ref
)
392 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
394 FIXME("iface %p, flags %#x, ref %p stub!\n", iface
, flags
, Ref
);
396 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
398 TRACE("(%p): Not an overlay surface\n", This
);
399 return WINEDDERR_NOTAOVERLAYSURFACE
;
405 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface
*iface
, const RECT
*SrcRect
,
406 IWineD3DSurface
*DstSurface
, const RECT
*DstRect
, DWORD flags
, const WINEDDOVERLAYFX
*FX
)
408 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
409 IWineD3DSurfaceImpl
*Dst
= (IWineD3DSurfaceImpl
*) DstSurface
;
411 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
412 iface
, wine_dbgstr_rect(SrcRect
), DstSurface
, wine_dbgstr_rect(DstRect
), flags
, FX
);
414 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
416 WARN("(%p): Not an overlay surface\n", This
);
417 return WINEDDERR_NOTAOVERLAYSURFACE
;
418 } else if(!DstSurface
) {
419 WARN("(%p): Dest surface is NULL\n", This
);
420 return WINED3DERR_INVALIDCALL
;
424 This
->overlay_srcrect
= *SrcRect
;
426 This
->overlay_srcrect
.left
= 0;
427 This
->overlay_srcrect
.top
= 0;
428 This
->overlay_srcrect
.right
= This
->currentDesc
.Width
;
429 This
->overlay_srcrect
.bottom
= This
->currentDesc
.Height
;
433 This
->overlay_destrect
= *DstRect
;
435 This
->overlay_destrect
.left
= 0;
436 This
->overlay_destrect
.top
= 0;
437 This
->overlay_destrect
.right
= Dst
? Dst
->currentDesc
.Width
: 0;
438 This
->overlay_destrect
.bottom
= Dst
? Dst
->currentDesc
.Height
: 0;
441 if (This
->overlay_dest
&& (This
->overlay_dest
!= Dst
|| flags
& WINEDDOVER_HIDE
))
443 list_remove(&This
->overlay_entry
);
446 if (flags
& WINEDDOVER_SHOW
)
448 if (This
->overlay_dest
!= Dst
)
450 This
->overlay_dest
= Dst
;
451 list_add_tail(&Dst
->overlays
, &This
->overlay_entry
);
454 else if (flags
& WINEDDOVER_HIDE
)
456 /* tests show that the rectangles are erased on hide */
457 This
->overlay_srcrect
.left
= 0; This
->overlay_srcrect
.top
= 0;
458 This
->overlay_srcrect
.right
= 0; This
->overlay_srcrect
.bottom
= 0;
459 This
->overlay_destrect
.left
= 0; This
->overlay_destrect
.top
= 0;
460 This
->overlay_destrect
.right
= 0; This
->overlay_destrect
.bottom
= 0;
461 This
->overlay_dest
= NULL
;
464 IWineD3DSurface_DrawOverlay(iface
);
469 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface
*iface
, IWineD3DClipper
*clipper
)
471 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
472 TRACE("(%p)->(%p)\n", This
, clipper
);
474 This
->clipper
= (IWineD3DClipperImpl
*)clipper
;
478 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface
*iface
, IWineD3DClipper
**clipper
)
480 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
481 TRACE("(%p)->(%p)\n", This
, clipper
);
483 *clipper
= (IWineD3DClipper
*)This
->clipper
;
485 IWineD3DClipper_AddRef(*clipper
);
490 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface
*iface
, enum wined3d_format_id format_id
)
492 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
493 const struct wined3d_format
*format
= wined3d_get_format(&This
->resource
.device
->adapter
->gl_info
, format_id
);
495 if (This
->resource
.format
->id
!= WINED3DFMT_UNKNOWN
)
497 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This
);
498 return WINED3DERR_INVALIDCALL
;
501 TRACE("(%p) : Setting texture format to %s (%#x).\n", This
, debug_d3dformat(format_id
), format_id
);
503 This
->resource
.size
= wined3d_format_calculate_size(format
, This
->resource
.device
->surface_alignment
,
504 This
->pow2Width
, This
->pow2Height
);
506 This
->flags
|= (WINED3DFMT_D16_LOCKABLE
== format_id
) ? SFLAG_LOCKABLE
: 0;
508 This
->resource
.format
= format
;
510 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This
, This
->resource
.size
, format
->byte_count
);
515 HRESULT
IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface
*iface
)
517 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
518 const struct wined3d_format
*format
= This
->resource
.format
;
526 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
528 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format
->id
));
529 return WINED3DERR_INVALIDCALL
;
532 switch (format
->byte_count
)
536 /* Allocate extra space to store the RGB bit masks. */
537 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
541 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
545 /* Allocate extra space for a palette. */
546 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
547 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
552 return E_OUTOFMEMORY
;
554 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
555 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
556 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
557 * add an extra line to the dib section
559 GetSystemInfo(&sysInfo
);
560 if( ((This
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4) {
562 TRACE("Adding an extra line to the dib section\n");
565 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
566 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
567 b_info
->bmiHeader
.biWidth
= IWineD3DSurface_GetPitch(iface
) / format
->byte_count
;
568 b_info
->bmiHeader
.biHeight
= -This
->currentDesc
.Height
-extraline
;
569 b_info
->bmiHeader
.biSizeImage
= ( This
->currentDesc
.Height
+ extraline
) * IWineD3DSurface_GetPitch(iface
);
570 b_info
->bmiHeader
.biPlanes
= 1;
571 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
573 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
574 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
575 b_info
->bmiHeader
.biClrUsed
= 0;
576 b_info
->bmiHeader
.biClrImportant
= 0;
578 /* Get the bit masks */
579 masks
= (DWORD
*)b_info
->bmiColors
;
580 switch (This
->resource
.format
->id
)
582 case WINED3DFMT_B8G8R8_UNORM
:
583 usage
= DIB_RGB_COLORS
;
584 b_info
->bmiHeader
.biCompression
= BI_RGB
;
587 case WINED3DFMT_B5G5R5X1_UNORM
:
588 case WINED3DFMT_B5G5R5A1_UNORM
:
589 case WINED3DFMT_B4G4R4A4_UNORM
:
590 case WINED3DFMT_B4G4R4X4_UNORM
:
591 case WINED3DFMT_B2G3R3_UNORM
:
592 case WINED3DFMT_B2G3R3A8_UNORM
:
593 case WINED3DFMT_R10G10B10A2_UNORM
:
594 case WINED3DFMT_R8G8B8A8_UNORM
:
595 case WINED3DFMT_R8G8B8X8_UNORM
:
596 case WINED3DFMT_B10G10R10A2_UNORM
:
597 case WINED3DFMT_B5G6R5_UNORM
:
598 case WINED3DFMT_R16G16B16A16_UNORM
:
600 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
601 masks
[0] = format
->red_mask
;
602 masks
[1] = format
->green_mask
;
603 masks
[2] = format
->blue_mask
;
607 /* Don't know palette */
608 b_info
->bmiHeader
.biCompression
= BI_RGB
;
613 if (!(ddc
= GetDC(0)))
615 HeapFree(GetProcessHeap(), 0, b_info
);
616 return HRESULT_FROM_WIN32(GetLastError());
619 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
);
620 This
->dib
.DIBsection
= CreateDIBSection(ddc
, b_info
, usage
, &This
->dib
.bitmap_data
, 0 /* Handle */, 0 /* Offset */);
623 if (!This
->dib
.DIBsection
) {
624 ERR("CreateDIBSection failed!\n");
625 HeapFree(GetProcessHeap(), 0, b_info
);
626 return HRESULT_FROM_WIN32(GetLastError());
629 TRACE("DIBSection at : %p\n", This
->dib
.bitmap_data
);
630 /* copy the existing surface to the dib section */
631 if(This
->resource
.allocatedMemory
) {
632 memcpy(This
->dib
.bitmap_data
, This
->resource
.allocatedMemory
, This
->currentDesc
.Height
* IWineD3DSurface_GetPitch(iface
));
634 /* This is to make LockRect read the gl Texture although memory is allocated */
635 This
->flags
&= ~SFLAG_INSYSMEM
;
637 This
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
639 HeapFree(GetProcessHeap(), 0, b_info
);
641 /* Now allocate a HDC */
642 This
->hDC
= CreateCompatibleDC(0);
643 This
->dib
.holdbitmap
= SelectObject(This
->hDC
, This
->dib
.DIBsection
);
644 TRACE("using wined3d palette %p\n", This
->palette
);
645 SelectPalette(This
->hDC
,
646 This
->palette
? This
->palette
->hpal
: 0,
649 This
->flags
|= SFLAG_DIBSECTION
;
651 HeapFree(GetProcessHeap(), 0, This
->resource
.heapMemory
);
652 This
->resource
.heapMemory
= NULL
;
657 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
658 unsigned int w
, unsigned int h
)
662 unsigned short *dst_s
;
664 TRACE("Converting %dx%d pixels, pitches %d %d\n", w
, h
, pitch_in
, pitch_out
);
665 for(y
= 0; y
< h
; y
++) {
666 src_f
= (const float *)(src
+ y
* pitch_in
);
667 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
668 for(x
= 0; x
< w
; x
++) {
669 dst_s
[x
] = float_32_to_16(src_f
+ x
);
674 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
675 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
677 static const unsigned char convert_5to8
[] =
679 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
680 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
681 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
682 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
684 static const unsigned char convert_6to8
[] =
686 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
687 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
688 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
689 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
690 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
691 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
692 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
693 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
697 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
699 for (y
= 0; y
< h
; ++y
)
701 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
702 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
703 for (x
= 0; x
< w
; ++x
)
705 WORD pixel
= src_line
[x
];
706 dst_line
[x
] = 0xff000000
707 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
708 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
709 | convert_5to8
[(pixel
& 0x001f)];
714 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
715 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
719 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
721 for (y
= 0; y
< h
; ++y
)
723 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
724 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
726 for (x
= 0; x
< w
; ++x
)
728 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
733 static inline BYTE
cliptobyte(int x
)
735 return (BYTE
) ((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
738 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
739 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
742 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
744 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
746 for (y
= 0; y
< h
; ++y
)
748 const BYTE
*src_line
= src
+ y
* pitch_in
;
749 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
750 for (x
= 0; x
< w
; ++x
)
752 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
753 * C = Y - 16; D = U - 128; E = V - 128;
754 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
755 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
756 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
757 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
758 * U and V are shared between the pixels.
760 if (!(x
& 1)) /* for every even pixel, read new U and V */
762 d
= (int) src_line
[1] - 128;
763 e
= (int) src_line
[3] - 128;
765 g2
= - 100 * d
- 208 * e
+ 128;
768 c2
= 298 * ((int) src_line
[0] - 16);
769 dst_line
[x
] = 0xff000000
770 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
771 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
772 | cliptobyte((c2
+ b2
) >> 8); /* blue */
773 /* Scale RGB values to 0..255 range,
774 * then clip them if still not in range (may be negative),
775 * then shift them within DWORD if necessary.
782 struct d3dfmt_convertor_desc
784 enum wined3d_format_id from
, to
;
785 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
788 static const struct d3dfmt_convertor_desc convertors
[] =
790 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
791 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
792 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
793 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
796 static inline const struct d3dfmt_convertor_desc
*find_convertor(enum wined3d_format_id from
, enum wined3d_format_id to
)
799 for(i
= 0; i
< (sizeof(convertors
) / sizeof(convertors
[0])); i
++) {
800 if(convertors
[i
].from
== from
&& convertors
[i
].to
== to
) {
801 return &convertors
[i
];
807 /*****************************************************************************
808 * surface_convert_format
810 * Creates a duplicate of a surface in a different format. Is used by Blt to
811 * blit between surfaces with different formats
814 * source: Source surface
815 * fmt: Requested destination format
817 *****************************************************************************/
818 static IWineD3DSurfaceImpl
*surface_convert_format(IWineD3DSurfaceImpl
*source
, enum wined3d_format_id to_fmt
)
820 IWineD3DSurface
*ret
= NULL
;
821 const struct d3dfmt_convertor_desc
*conv
;
822 WINED3DLOCKED_RECT lock_src
, lock_dst
;
825 conv
= find_convertor(source
->resource
.format
->id
, to_fmt
);
828 FIXME("Cannot find a conversion function from format %s to %s.\n",
829 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
833 IWineD3DDevice_CreateSurface((IWineD3DDevice
*)source
->resource
.device
, source
->currentDesc
.Width
,
834 source
->currentDesc
.Height
, to_fmt
, TRUE
/* lockable */, TRUE
/* discard */, 0 /* level */,
835 0 /* usage */, WINED3DPOOL_SCRATCH
, WINED3DMULTISAMPLE_NONE
/* TODO: Multisampled conversion */,
836 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface
*) source
),
837 NULL
/* parent */, &wined3d_null_parent_ops
, &ret
);
839 ERR("Failed to create a destination surface for conversion\n");
843 memset(&lock_src
, 0, sizeof(lock_src
));
844 memset(&lock_dst
, 0, sizeof(lock_dst
));
846 hr
= IWineD3DSurface_Map((IWineD3DSurface
*)source
, &lock_src
, NULL
, WINED3DLOCK_READONLY
);
849 ERR("Failed to lock the source surface.\n");
850 IWineD3DSurface_Release(ret
);
853 hr
= IWineD3DSurface_Map(ret
, &lock_dst
, NULL
, WINED3DLOCK_READONLY
);
856 ERR("Failed to lock the dest surface\n");
857 IWineD3DSurface_Unmap((IWineD3DSurface
*)source
);
858 IWineD3DSurface_Release(ret
);
862 conv
->convert(lock_src
.pBits
, lock_dst
.pBits
, lock_src
.Pitch
, lock_dst
.Pitch
,
863 source
->currentDesc
.Width
, source
->currentDesc
.Height
);
865 IWineD3DSurface_Unmap(ret
);
866 IWineD3DSurface_Unmap((IWineD3DSurface
*)source
);
868 return (IWineD3DSurfaceImpl
*) ret
;
871 /*****************************************************************************
874 * Helper function that fills a memory area with a specific color
877 * buf: memory address to start filling at
878 * width, height: Dimensions of the area to fill
879 * bpp: Bit depth of the surface
880 * lPitch: pitch of the surface
881 * color: Color to fill with
883 *****************************************************************************/
885 _Blt_ColorFill(BYTE
*buf
,
886 int width
, int height
,
887 int bpp
, LONG lPitch
,
895 #define COLORFILL_ROW(type) \
897 type *d = (type *) buf; \
898 for (x = 0; x < width; x++) \
899 d[x] = (type) color; \
904 case 1: COLORFILL_ROW(BYTE
)
905 case 2: COLORFILL_ROW(WORD
)
909 for (x
= 0; x
< width
; x
++,d
+=3)
911 d
[0] = (color
) & 0xFF;
912 d
[1] = (color
>> 8) & 0xFF;
913 d
[2] = (color
>>16) & 0xFF;
917 case 4: COLORFILL_ROW(DWORD
)
919 FIXME("Color fill not implemented for bpp %d!\n", bpp
*8);
920 return WINED3DERR_NOTAVAILABLE
;
925 /* Now copy first row */
927 for (y
= 1; y
< height
; y
++)
930 memcpy(buf
, first
, width
* bpp
);
935 /*****************************************************************************
936 * IWineD3DSurface::Blt, SW emulation version
938 * Performs a blit to a surface, with or without a source surface.
939 * This is the main functionality of DirectDraw
942 * DestRect: Destination rectangle to write to
943 * src_surface: Source surface, can be NULL
944 * SrcRect: Source rectangle
945 *****************************************************************************/
946 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface
*iface
, const RECT
*DestRect
, IWineD3DSurface
*src_surface
,
947 const RECT
*SrcRect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
, WINED3DTEXTUREFILTERTYPE Filter
)
949 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
950 IWineD3DSurfaceImpl
*src
= (IWineD3DSurfaceImpl
*)src_surface
;
952 HRESULT ret
= WINED3D_OK
;
953 WINED3DLOCKED_RECT dlock
, slock
;
954 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
955 const struct wined3d_format
*sEntry
, *dEntry
;
960 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
961 iface
, wine_dbgstr_rect(DestRect
), src_surface
, wine_dbgstr_rect(SrcRect
),
962 flags
, DDBltFx
, debug_d3dtexturefiltertype(Filter
));
964 if ((This
->flags
& SFLAG_LOCKED
) || (src
&& (src
->flags
& SFLAG_LOCKED
)))
966 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
967 return WINEDDERR_SURFACEBUSY
;
970 /* First check for the validity of source / destination rectangles.
971 * This was verified using a test application + by MSDN. */
977 if (SrcRect
->right
< SrcRect
->left
|| SrcRect
->bottom
< SrcRect
->top
978 || SrcRect
->left
> src
->currentDesc
.Width
|| SrcRect
->left
< 0
979 || SrcRect
->top
> src
->currentDesc
.Height
|| SrcRect
->top
< 0
980 || SrcRect
->right
> src
->currentDesc
.Width
|| SrcRect
->right
< 0
981 || SrcRect
->bottom
> src
->currentDesc
.Height
|| SrcRect
->bottom
< 0)
983 WARN("Application gave us bad source rectangle for Blt.\n");
984 return WINEDDERR_INVALIDRECT
;
987 if (!SrcRect
->right
|| !SrcRect
->bottom
988 || SrcRect
->left
== (int)src
->currentDesc
.Width
989 || SrcRect
->top
== (int)src
->currentDesc
.Height
)
991 TRACE("Nothing to be done.\n");
1002 xsrc
.right
= src
->currentDesc
.Width
;
1003 xsrc
.bottom
= src
->currentDesc
.Height
;
1007 memset(&xsrc
, 0, sizeof(xsrc
));
1012 /* For the Destination rect, it can be out of bounds on the condition
1013 * that a clipper is set for the given surface. */
1014 if (!This
->clipper
&& (DestRect
->right
< DestRect
->left
|| DestRect
->bottom
< DestRect
->top
1015 || DestRect
->left
> This
->currentDesc
.Width
|| DestRect
->left
< 0
1016 || DestRect
->top
> This
->currentDesc
.Height
|| DestRect
->top
< 0
1017 || DestRect
->right
> This
->currentDesc
.Width
|| DestRect
->right
< 0
1018 || DestRect
->bottom
> This
->currentDesc
.Height
|| DestRect
->bottom
< 0))
1020 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1021 return WINEDDERR_INVALIDRECT
;
1024 if (DestRect
->right
<= 0 || DestRect
->bottom
<= 0
1025 || DestRect
->left
>= (int)This
->currentDesc
.Width
1026 || DestRect
->top
>= (int)This
->currentDesc
.Height
)
1028 TRACE("Nothing to be done.\n");
1038 full_rect
.right
= This
->currentDesc
.Width
;
1039 full_rect
.bottom
= This
->currentDesc
.Height
;
1040 IntersectRect(&xdst
, &full_rect
, DestRect
);
1044 BOOL clip_horiz
, clip_vert
;
1047 clip_horiz
= xdst
.left
< 0 || xdst
.right
> (int)This
->currentDesc
.Width
;
1048 clip_vert
= xdst
.top
< 0 || xdst
.bottom
> (int)This
->currentDesc
.Height
;
1050 if (clip_vert
|| clip_horiz
)
1052 /* Now check if this is a special case or not... */
1053 if ((flags
& WINEDDBLT_DDFX
)
1054 || (clip_horiz
&& xdst
.right
- xdst
.left
!= xsrc
.right
- xsrc
.left
)
1055 || (clip_vert
&& xdst
.bottom
- xdst
.top
!= xsrc
.bottom
- xsrc
.top
))
1057 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1065 xsrc
.left
-= xdst
.left
;
1068 if (xdst
.right
> This
->currentDesc
.Width
)
1070 xsrc
.right
-= (xdst
.right
- (int)This
->currentDesc
.Width
);
1071 xdst
.right
= (int)This
->currentDesc
.Width
;
1079 xsrc
.top
-= xdst
.top
;
1082 if (xdst
.bottom
> This
->currentDesc
.Height
)
1084 xsrc
.bottom
-= (xdst
.bottom
- (int)This
->currentDesc
.Height
);
1085 xdst
.bottom
= (int)This
->currentDesc
.Height
;
1089 /* And check if after clipping something is still to be done... */
1090 if ((xdst
.right
<= 0) || (xdst
.bottom
<= 0)
1091 || (xdst
.left
>= (int)This
->currentDesc
.Width
)
1092 || (xdst
.top
>= (int)This
->currentDesc
.Height
)
1093 || (xsrc
.right
<= 0) || (xsrc
.bottom
<= 0)
1094 || (xsrc
.left
>= (int)src
->currentDesc
.Width
)
1095 || (xsrc
.top
>= (int)src
->currentDesc
.Height
))
1097 TRACE("Nothing to be done after clipping.\n");
1107 xdst
.right
= This
->currentDesc
.Width
;
1108 xdst
.bottom
= This
->currentDesc
.Height
;
1113 IWineD3DSurface_Map(iface
, &dlock
, NULL
, 0);
1115 sEntry
= This
->resource
.format
;
1120 dEntry
= This
->resource
.format
;
1123 if (This
->resource
.format
->id
!= src
->resource
.format
->id
)
1125 src
= surface_convert_format(src
, dEntry
->id
);
1128 /* The conv function writes a FIXME */
1129 WARN("Cannot convert source surface format to dest format\n");
1133 IWineD3DSurface_Map((IWineD3DSurface
*)src
, &slock
, NULL
, WINED3DLOCK_READONLY
);
1134 sEntry
= src
->resource
.format
;
1141 IWineD3DSurface_Map(iface
, &dlock
, &xdst
, 0);
1143 IWineD3DSurface_Map(iface
, &dlock
, NULL
, 0);
1146 if (!DDBltFx
|| !(DDBltFx
->dwDDFX
)) flags
&= ~WINEDDBLT_DDFX
;
1148 if (sEntry
->flags
& dEntry
->flags
& WINED3DFMT_FLAG_FOURCC
)
1150 if (!DestRect
|| src
== This
)
1152 memcpy(dlock
.pBits
, slock
.pBits
, This
->resource
.size
);
1157 bpp
= This
->resource
.format
->byte_count
;
1158 srcheight
= xsrc
.bottom
- xsrc
.top
;
1159 srcwidth
= xsrc
.right
- xsrc
.left
;
1160 dstheight
= xdst
.bottom
- xdst
.top
;
1161 dstwidth
= xdst
.right
- xdst
.left
;
1162 width
= (xdst
.right
- xdst
.left
) * bpp
;
1164 if (DestRect
&& src
!= This
)
1167 dbuf
= (BYTE
*)dlock
.pBits
+(xdst
.top
*dlock
.Pitch
)+(xdst
.left
*bpp
);
1169 if (flags
& WINEDDBLT_WAIT
)
1171 flags
&= ~WINEDDBLT_WAIT
;
1173 if (flags
& WINEDDBLT_ASYNC
)
1175 static BOOL displayed
= FALSE
;
1177 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1179 flags
&= ~WINEDDBLT_ASYNC
;
1181 if (flags
& WINEDDBLT_DONOTWAIT
)
1183 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1184 static BOOL displayed
= FALSE
;
1186 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1188 flags
&= ~WINEDDBLT_DONOTWAIT
;
1191 /* First, all the 'source-less' blits */
1192 if (flags
& WINEDDBLT_COLORFILL
)
1194 ret
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
,
1195 dlock
.Pitch
, DDBltFx
->u5
.dwFillColor
);
1196 flags
&= ~WINEDDBLT_COLORFILL
;
1199 if (flags
& WINEDDBLT_DEPTHFILL
)
1201 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1203 if (flags
& WINEDDBLT_ROP
)
1205 /* Catch some degenerate cases here */
1206 switch(DDBltFx
->dwROP
)
1209 ret
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,0);
1211 case 0xAA0029: /* No-op */
1214 ret
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,~0);
1216 case SRCCOPY
: /* well, we do that below ? */
1219 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx
->dwROP
, DDBltFx
->u5
.lpDDSPattern
);
1222 flags
&= ~WINEDDBLT_ROP
;
1224 if (flags
& WINEDDBLT_DDROPS
)
1226 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx
->dwDDROP
, DDBltFx
->u5
.lpDDSPattern
);
1228 /* Now the 'with source' blits */
1232 int sx
, xinc
, sy
, yinc
;
1234 if (!dstwidth
|| !dstheight
) /* hmm... stupid program ? */
1237 if (Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
1238 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
1240 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1241 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter
));
1244 sbase
= (BYTE
*)slock
.pBits
+(xsrc
.top
*slock
.Pitch
)+xsrc
.left
*bpp
;
1245 xinc
= (srcwidth
<< 16) / dstwidth
;
1246 yinc
= (srcheight
<< 16) / dstheight
;
1250 /* No effects, we can cheat here */
1251 if (dstwidth
== srcwidth
)
1253 if (dstheight
== srcheight
)
1255 /* No stretching in either direction. This needs to be as
1256 * fast as possible */
1259 /* check for overlapping surfaces */
1260 if (src
!= This
|| xdst
.top
< xsrc
.top
||
1261 xdst
.right
<= xsrc
.left
|| xsrc
.right
<= xdst
.left
)
1263 /* no overlap, or dst above src, so copy from top downwards */
1264 for (y
= 0; y
< dstheight
; y
++)
1266 memcpy(dbuf
, sbuf
, width
);
1267 sbuf
+= slock
.Pitch
;
1268 dbuf
+= dlock
.Pitch
;
1271 else if (xdst
.top
> xsrc
.top
) /* copy from bottom upwards */
1273 sbuf
+= (slock
.Pitch
*dstheight
);
1274 dbuf
+= (dlock
.Pitch
*dstheight
);
1275 for (y
= 0; y
< dstheight
; y
++)
1277 sbuf
-= slock
.Pitch
;
1278 dbuf
-= dlock
.Pitch
;
1279 memcpy(dbuf
, sbuf
, width
);
1282 else /* src and dst overlapping on the same line, use memmove */
1284 for (y
= 0; y
< dstheight
; y
++)
1286 memmove(dbuf
, sbuf
, width
);
1287 sbuf
+= slock
.Pitch
;
1288 dbuf
+= dlock
.Pitch
;
1292 /* Stretching in Y direction only */
1293 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
) {
1294 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1295 memcpy(dbuf
, sbuf
, width
);
1296 dbuf
+= dlock
.Pitch
;
1302 /* Stretching in X direction */
1304 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
)
1306 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1308 if ((sy
>> 16) == (last_sy
>> 16))
1310 /* this sourcerow is the same as last sourcerow -
1311 * copy already stretched row
1313 memcpy(dbuf
, dbuf
- dlock
.Pitch
, width
);
1317 #define STRETCH_ROW(type) { \
1318 const type *s = (const type *)sbuf; \
1319 type *d = (type *)dbuf; \
1320 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1321 d[x] = s[sx >> 16]; \
1326 case 1: STRETCH_ROW(BYTE
)
1327 case 2: STRETCH_ROW(WORD
)
1328 case 4: STRETCH_ROW(DWORD
)
1333 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
1337 s
= sbuf
+3*(sx
>>16);
1338 pixel
= s
[0]|(s
[1]<<8)|(s
[2]<<16);
1339 d
[0] = (pixel
)&0xff;
1340 d
[1] = (pixel
>> 8)&0xff;
1341 d
[2] = (pixel
>>16)&0xff;
1347 FIXME("Stretched blit not implemented for bpp %d!\n", bpp
*8);
1348 ret
= WINED3DERR_NOTAVAILABLE
;
1353 dbuf
+= dlock
.Pitch
;
1360 LONG dstyinc
= dlock
.Pitch
, dstxinc
= bpp
;
1361 DWORD keylow
= 0xFFFFFFFF, keyhigh
= 0, keymask
= 0xFFFFFFFF;
1362 DWORD destkeylow
= 0x0, destkeyhigh
= 0xFFFFFFFF, destkeymask
= 0xFFFFFFFF;
1363 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
1365 /* The color keying flags are checked for correctness in ddraw */
1366 if (flags
& WINEDDBLT_KEYSRC
)
1368 keylow
= src
->SrcBltCKey
.dwColorSpaceLowValue
;
1369 keyhigh
= src
->SrcBltCKey
.dwColorSpaceHighValue
;
1371 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
1373 keylow
= DDBltFx
->ddckSrcColorkey
.dwColorSpaceLowValue
;
1374 keyhigh
= DDBltFx
->ddckSrcColorkey
.dwColorSpaceHighValue
;
1377 if (flags
& WINEDDBLT_KEYDEST
)
1379 /* Destination color keys are taken from the source surface ! */
1380 destkeylow
= src
->DestBltCKey
.dwColorSpaceLowValue
;
1381 destkeyhigh
= src
->DestBltCKey
.dwColorSpaceHighValue
;
1383 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
1385 destkeylow
= DDBltFx
->ddckDestColorkey
.dwColorSpaceLowValue
;
1386 destkeyhigh
= DDBltFx
->ddckDestColorkey
.dwColorSpaceHighValue
;
1395 keymask
= sEntry
->red_mask
1396 | sEntry
->green_mask
1397 | sEntry
->blue_mask
;
1399 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
1402 if (flags
& WINEDDBLT_DDFX
)
1404 LPBYTE dTopLeft
, dTopRight
, dBottomLeft
, dBottomRight
, tmp
;
1407 dTopRight
= dbuf
+((dstwidth
-1)*bpp
);
1408 dBottomLeft
= dTopLeft
+((dstheight
-1)*dlock
.Pitch
);
1409 dBottomRight
= dBottomLeft
+((dstwidth
-1)*bpp
);
1411 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
1413 /* I don't think we need to do anything about this flag */
1414 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1416 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
1419 dTopRight
= dTopLeft
;
1422 dBottomRight
= dBottomLeft
;
1424 dstxinc
= dstxinc
*-1;
1426 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
1429 dTopLeft
= dBottomLeft
;
1432 dTopRight
= dBottomRight
;
1434 dstyinc
= dstyinc
*-1;
1436 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
1438 /* I don't think we need to do anything about this flag */
1439 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1441 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
1444 dBottomRight
= dTopLeft
;
1447 dBottomLeft
= dTopRight
;
1449 dstxinc
= dstxinc
* -1;
1450 dstyinc
= dstyinc
* -1;
1452 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
1455 dTopLeft
= dBottomLeft
;
1456 dBottomLeft
= dBottomRight
;
1457 dBottomRight
= dTopRight
;
1462 dstxinc
= dstxinc
* -1;
1464 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
1467 dTopLeft
= dTopRight
;
1468 dTopRight
= dBottomRight
;
1469 dBottomRight
= dBottomLeft
;
1474 dstyinc
= dstyinc
* -1;
1476 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
1478 /* I don't think we need to do anything about this flag */
1479 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1482 flags
&= ~(WINEDDBLT_DDFX
);
1485 #define COPY_COLORKEY_FX(type) { \
1487 type *d = (type *)dbuf, *dx, tmp; \
1488 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1489 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1491 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1492 tmp = s[sx >> 16]; \
1493 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1494 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1497 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1499 d = (type*)(((LPBYTE)d)+dstyinc); \
1504 case 1: COPY_COLORKEY_FX(BYTE
)
1505 case 2: COPY_COLORKEY_FX(WORD
)
1506 case 4: COPY_COLORKEY_FX(DWORD
)
1510 BYTE
*d
= dbuf
, *dx
;
1511 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
)
1513 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1515 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
1517 DWORD pixel
, dpixel
= 0;
1518 s
= sbuf
+3*(sx
>>16);
1519 pixel
= s
[0]|(s
[1]<<8)|(s
[2]<<16);
1520 dpixel
= dx
[0]|(dx
[1]<<8)|(dx
[2]<<16);
1521 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
) &&
1522 ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
1524 dx
[0] = (pixel
)&0xff;
1525 dx
[1] = (pixel
>> 8)&0xff;
1526 dx
[2] = (pixel
>>16)&0xff;
1535 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1536 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
*8);
1537 ret
= WINED3DERR_NOTAVAILABLE
;
1539 #undef COPY_COLORKEY_FX
1545 if (flags
&& FIXME_ON(d3d_surface
))
1547 FIXME("\tUnsupported flags: %#x.\n", flags
);
1551 IWineD3DSurface_Unmap(iface
);
1552 if (src
&& src
!= This
) IWineD3DSurface_Unmap((IWineD3DSurface
*)src
);
1553 /* Release the converted surface if any */
1554 if (src
&& src_surface
!= (IWineD3DSurface
*)src
) IWineD3DSurface_Release((IWineD3DSurface
*)src
);
1558 /*****************************************************************************
1559 * IWineD3DSurface::BltFast, SW emulation version
1561 * This is the software implementation of BltFast, as used by GDI surfaces
1562 * and as a fallback for OpenGL surfaces. This code is taken from the old
1563 * DirectDraw code, and was originally written by TransGaming.
1568 * src_surface: Source surface to copy from
1569 * rsrc: Source rectangle
1573 * WINED3D_OK on success
1575 *****************************************************************************/
1576 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface
*iface
, DWORD dstx
, DWORD dsty
,
1577 IWineD3DSurface
*src_surface
, const RECT
*rsrc
, DWORD trans
)
1579 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1580 IWineD3DSurfaceImpl
*src
= (IWineD3DSurfaceImpl
*)src_surface
;
1582 int bpp
, w
, h
, x
, y
;
1583 WINED3DLOCKED_RECT dlock
,slock
;
1584 HRESULT ret
= WINED3D_OK
;
1586 RECT lock_src
, lock_dst
, lock_union
;
1589 const struct wined3d_format
*sEntry
, *dEntry
;
1591 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1592 iface
, dstx
, dsty
, src_surface
, wine_dbgstr_rect(rsrc
), trans
);
1594 if ((This
->flags
& SFLAG_LOCKED
) || (src
->flags
& SFLAG_LOCKED
))
1596 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1597 return WINEDDERR_SURFACEBUSY
;
1602 WARN("rsrc is NULL!\n");
1605 rsrc2
.right
= src
->currentDesc
.Width
;
1606 rsrc2
.bottom
= src
->currentDesc
.Height
;
1610 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1611 if ((rsrc
->bottom
> src
->currentDesc
.Height
) || (rsrc
->bottom
< 0)
1612 || (rsrc
->top
> src
->currentDesc
.Height
) || (rsrc
->top
< 0)
1613 || (rsrc
->left
> src
->currentDesc
.Width
) || (rsrc
->left
< 0)
1614 || (rsrc
->right
> src
->currentDesc
.Width
) || (rsrc
->right
< 0)
1615 || (rsrc
->right
< rsrc
->left
) || (rsrc
->bottom
< rsrc
->top
))
1617 WARN("Application gave us bad source rectangle for BltFast.\n");
1618 return WINEDDERR_INVALIDRECT
;
1621 h
= rsrc
->bottom
- rsrc
->top
;
1622 if (h
> This
->currentDesc
.Height
-dsty
) h
= This
->currentDesc
.Height
-dsty
;
1623 if (h
> src
->currentDesc
.Height
-rsrc
->top
) h
= src
->currentDesc
.Height
-rsrc
->top
;
1624 if (h
<= 0) return WINEDDERR_INVALIDRECT
;
1626 w
= rsrc
->right
- rsrc
->left
;
1627 if (w
> This
->currentDesc
.Width
-dstx
) w
= This
->currentDesc
.Width
-dstx
;
1628 if (w
> src
->currentDesc
.Width
-rsrc
->left
) w
= src
->currentDesc
.Width
-rsrc
->left
;
1629 if (w
<= 0) return WINEDDERR_INVALIDRECT
;
1631 /* Now compute the locking rectangle... */
1632 lock_src
.left
= rsrc
->left
;
1633 lock_src
.top
= rsrc
->top
;
1634 lock_src
.right
= lock_src
.left
+ w
;
1635 lock_src
.bottom
= lock_src
.top
+ h
;
1637 lock_dst
.left
= dstx
;
1638 lock_dst
.top
= dsty
;
1639 lock_dst
.right
= dstx
+ w
;
1640 lock_dst
.bottom
= dsty
+ h
;
1642 bpp
= This
->resource
.format
->byte_count
;
1644 /* We need to lock the surfaces, or we won't get refreshes when done. */
1649 UnionRect(&lock_union
, &lock_src
, &lock_dst
);
1651 /* Lock the union of the two rectangles */
1652 ret
= IWineD3DSurface_Map(iface
, &dlock
, &lock_union
, 0);
1653 if (FAILED(ret
)) goto error
;
1655 pitch
= dlock
.Pitch
;
1656 slock
.Pitch
= dlock
.Pitch
;
1658 /* Since slock was originally copied from this surface's description, we can just reuse it */
1659 sbuf
= This
->resource
.allocatedMemory
+ lock_src
.top
* pitch
+ lock_src
.left
* bpp
;
1660 dbuf
= This
->resource
.allocatedMemory
+ lock_dst
.top
* pitch
+ lock_dst
.left
* bpp
;
1661 sEntry
= src
->resource
.format
;
1666 ret
= IWineD3DSurface_Map(src_surface
, &slock
, &lock_src
, WINED3DLOCK_READONLY
);
1667 if (FAILED(ret
)) goto error
;
1668 ret
= IWineD3DSurface_Map(iface
, &dlock
, &lock_dst
, 0);
1669 if (FAILED(ret
)) goto error
;
1673 TRACE("Dst is at %p, Src is at %p\n", dbuf
, sbuf
);
1675 sEntry
= src
->resource
.format
;
1676 dEntry
= This
->resource
.format
;
1679 /* Handle compressed surfaces first... */
1680 if (sEntry
->flags
& dEntry
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1682 UINT row_block_count
;
1684 TRACE("compressed -> compressed copy\n");
1686 FIXME("trans arg not supported when a compressed surface is involved\n");
1688 FIXME("offset for destination surface is not supported\n");
1689 if (src
->resource
.format
->id
!= This
->resource
.format
->id
)
1691 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1692 ret
= WINED3DERR_WRONGTEXTUREFORMAT
;
1696 row_block_count
= (w
+ dEntry
->block_width
- 1) / dEntry
->block_width
;
1697 for (y
= 0; y
< h
; y
+= dEntry
->block_height
)
1699 memcpy(dbuf
, sbuf
, row_block_count
* dEntry
->block_byte_count
);
1700 dbuf
+= dlock
.Pitch
;
1701 sbuf
+= slock
.Pitch
;
1706 if ((sEntry
->flags
& WINED3DFMT_FLAG_COMPRESSED
) && !(dEntry
->flags
& WINED3DFMT_FLAG_COMPRESSED
))
1708 /* TODO: Use the libtxc_dxtn.so shared library to do
1709 * software decompression
1711 ERR("Software decompression not supported.\n");
1715 if (trans
& (WINEDDBLTFAST_SRCCOLORKEY
| WINEDDBLTFAST_DESTCOLORKEY
))
1717 DWORD keylow
, keyhigh
;
1718 DWORD mask
= src
->resource
.format
->red_mask
1719 | src
->resource
.format
->green_mask
1720 | src
->resource
.format
->blue_mask
;
1722 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1726 TRACE("Color keyed copy\n");
1727 if (trans
& WINEDDBLTFAST_SRCCOLORKEY
)
1729 keylow
= src
->SrcBltCKey
.dwColorSpaceLowValue
;
1730 keyhigh
= src
->SrcBltCKey
.dwColorSpaceHighValue
;
1734 /* I'm not sure if this is correct */
1735 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1736 keylow
= This
->DestBltCKey
.dwColorSpaceLowValue
;
1737 keyhigh
= This
->DestBltCKey
.dwColorSpaceHighValue
;
1740 #define COPYBOX_COLORKEY(type) { \
1741 const type *s = (const type *)sbuf; \
1742 type *d = (type *)dbuf; \
1744 for (y = 0; y < h; y++) { \
1745 for (x = 0; x < w; x++) { \
1747 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1749 s = (const type *)((const BYTE *)s + slock.Pitch); \
1750 d = (type *)((BYTE *)d + dlock.Pitch); \
1756 case 1: COPYBOX_COLORKEY(BYTE
)
1757 case 2: COPYBOX_COLORKEY(WORD
)
1758 case 4: COPYBOX_COLORKEY(DWORD
)
1766 for (y
= 0; y
< h
; y
++)
1768 for (x
= 0; x
< w
* 3; x
+= 3)
1770 tmp
= (DWORD
)s
[x
] + ((DWORD
)s
[x
+ 1] << 8) + ((DWORD
)s
[x
+ 2] << 16);
1771 if (tmp
< keylow
|| tmp
> keyhigh
)
1773 d
[x
+ 0] = s
[x
+ 0];
1774 d
[x
+ 1] = s
[x
+ 1];
1775 d
[x
+ 2] = s
[x
+ 2];
1784 FIXME("Source color key blitting not supported for bpp %d\n",bpp
*8);
1785 ret
= WINED3DERR_NOTAVAILABLE
;
1788 #undef COPYBOX_COLORKEY
1789 TRACE("Copy Done\n");
1793 int width
= w
* bpp
;
1794 INT sbufpitch
, dbufpitch
;
1796 TRACE("NO color key copy\n");
1797 /* Handle overlapping surfaces */
1800 sbuf
+= (h
- 1) * slock
.Pitch
;
1801 dbuf
+= (h
- 1) * dlock
.Pitch
;
1802 sbufpitch
= -slock
.Pitch
;
1803 dbufpitch
= -dlock
.Pitch
;
1807 sbufpitch
= slock
.Pitch
;
1808 dbufpitch
= dlock
.Pitch
;
1810 for (y
= 0; y
< h
; y
++)
1812 /* This is pretty easy, a line for line memcpy */
1813 memmove(dbuf
, sbuf
, width
);
1817 TRACE("Copy done\n");
1823 IWineD3DSurface_Unmap(iface
);
1827 IWineD3DSurface_Unmap(iface
);
1828 IWineD3DSurface_Unmap(src_surface
);
1834 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface
*iface
,
1835 WINED3DLOCKED_RECT
*pLockedRect
, const RECT
*pRect
, DWORD flags
)
1837 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1839 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1840 iface
, pLockedRect
, wine_dbgstr_rect(pRect
), flags
);
1842 pLockedRect
->Pitch
= IWineD3DSurface_GetPitch(iface
);
1846 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
1847 This
->lockedRect
.left
= 0;
1848 This
->lockedRect
.top
= 0;
1849 This
->lockedRect
.right
= This
->currentDesc
.Width
;
1850 This
->lockedRect
.bottom
= This
->currentDesc
.Height
;
1852 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1853 &This
->lockedRect
, This
->lockedRect
.left
, This
->lockedRect
.top
,
1854 This
->lockedRect
.right
, This
->lockedRect
.bottom
);
1858 const struct wined3d_format
*format
= This
->resource
.format
;
1860 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1861 pRect
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
1863 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
1865 /* Compressed textures are block based, so calculate the offset of
1866 * the block that contains the top-left pixel of the locked rectangle. */
1867 pLockedRect
->pBits
= This
->resource
.allocatedMemory
1868 + ((pRect
->top
/ format
->block_height
) * pLockedRect
->Pitch
)
1869 + ((pRect
->left
/ format
->block_width
) * format
->block_byte_count
);
1873 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+
1874 (pLockedRect
->Pitch
* pRect
->top
) +
1875 (pRect
->left
* format
->byte_count
);
1877 This
->lockedRect
.left
= pRect
->left
;
1878 This
->lockedRect
.top
= pRect
->top
;
1879 This
->lockedRect
.right
= pRect
->right
;
1880 This
->lockedRect
.bottom
= pRect
->bottom
;
1883 /* No dirtifying is needed for this surface implementation */
1884 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
);
1889 /* TODO: think about moving this down to resource? */
1890 const void *WINAPI
IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface
*iface
)
1892 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1894 /* This should only be called for sysmem textures, it may be a good idea
1895 * to extend this to all pools at some point in the future */
1896 if (This
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
)
1898 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface
);
1900 return This
->resource
.allocatedMemory
;