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
, struct wined3d_palette
*palette
)
221 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
223 TRACE("iface %p, palette %p.\n", iface
, palette
);
225 if (This
->palette
== palette
)
227 TRACE("Nop palette change\n");
232 if (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
233 This
->palette
->flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
235 This
->palette
= palette
;
239 if (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
240 palette
->flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
242 This
->surface_ops
->surface_realize_palette(This
);
248 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface
*iface
, DWORD flags
, const WINEDDCOLORKEY
*CKey
)
250 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
252 TRACE("iface %p, flags %#x, color_key %p.\n", iface
, flags
, CKey
);
254 if (flags
& WINEDDCKEY_COLORSPACE
)
256 FIXME(" colorkey value not supported (%08x) !\n", flags
);
257 return WINED3DERR_INVALIDCALL
;
260 /* Dirtify the surface, but only if a key was changed */
263 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
265 case WINEDDCKEY_DESTBLT
:
266 This
->DestBltCKey
= *CKey
;
267 This
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
270 case WINEDDCKEY_DESTOVERLAY
:
271 This
->DestOverlayCKey
= *CKey
;
272 This
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
275 case WINEDDCKEY_SRCOVERLAY
:
276 This
->SrcOverlayCKey
= *CKey
;
277 This
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
280 case WINEDDCKEY_SRCBLT
:
281 This
->SrcBltCKey
= *CKey
;
282 This
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
288 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
290 case WINEDDCKEY_DESTBLT
:
291 This
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
294 case WINEDDCKEY_DESTOVERLAY
:
295 This
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
298 case WINEDDCKEY_SRCOVERLAY
:
299 This
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
302 case WINEDDCKEY_SRCBLT
:
303 This
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
311 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface
*iface
, struct wined3d_palette
**palette
)
313 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
315 TRACE("iface %p, palette %p.\n", iface
, palette
);
317 *palette
= This
->palette
;
322 DWORD WINAPI
IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface
*iface
)
324 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
325 const struct wined3d_format
*format
= This
->resource
.format
;
327 TRACE("(%p)\n", This
);
329 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
331 /* Since compressed formats are block based, pitch means the amount of
332 * bytes to the next row of block rather than the next row of pixels. */
333 UINT row_block_count
= (This
->currentDesc
.Width
+ format
->block_width
- 1) / format
->block_width
;
334 ret
= row_block_count
* format
->block_byte_count
;
338 unsigned char alignment
= This
->resource
.device
->surface_alignment
;
339 ret
= This
->resource
.format
->byte_count
* This
->currentDesc
.Width
; /* Bytes / row */
340 ret
= (ret
+ alignment
- 1) & ~(alignment
- 1);
342 TRACE("(%p) Returning %d\n", This
, ret
);
346 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface
*iface
, LONG X
, LONG Y
) {
347 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
350 TRACE("(%p)->(%d,%d) Stub!\n", This
, X
, Y
);
352 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
354 TRACE("(%p): Not an overlay surface\n", This
);
355 return WINEDDERR_NOTAOVERLAYSURFACE
;
358 w
= This
->overlay_destrect
.right
- This
->overlay_destrect
.left
;
359 h
= This
->overlay_destrect
.bottom
- This
->overlay_destrect
.top
;
360 This
->overlay_destrect
.left
= X
;
361 This
->overlay_destrect
.top
= Y
;
362 This
->overlay_destrect
.right
= X
+ w
;
363 This
->overlay_destrect
.bottom
= Y
+ h
;
365 This
->surface_ops
->surface_draw_overlay(This
);
370 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface
*iface
, LONG
*X
, LONG
*Y
) {
371 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
374 TRACE("(%p)->(%p,%p)\n", This
, X
, Y
);
376 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
378 TRACE("(%p): Not an overlay surface\n", This
);
379 return WINEDDERR_NOTAOVERLAYSURFACE
;
382 if (!This
->overlay_dest
)
385 hr
= WINEDDERR_OVERLAYNOTVISIBLE
;
387 *X
= This
->overlay_destrect
.left
;
388 *Y
= This
->overlay_destrect
.top
;
392 TRACE("Returning 0x%08x, position %d, %d\n", hr
, *X
, *Y
);
396 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface
*iface
, DWORD flags
, IWineD3DSurface
*Ref
)
398 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
400 FIXME("iface %p, flags %#x, ref %p stub!\n", iface
, flags
, Ref
);
402 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
404 TRACE("(%p): Not an overlay surface\n", This
);
405 return WINEDDERR_NOTAOVERLAYSURFACE
;
411 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface
*iface
, const RECT
*SrcRect
,
412 IWineD3DSurface
*DstSurface
, const RECT
*DstRect
, DWORD flags
, const WINEDDOVERLAYFX
*FX
)
414 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
415 IWineD3DSurfaceImpl
*Dst
= (IWineD3DSurfaceImpl
*) DstSurface
;
417 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
418 iface
, wine_dbgstr_rect(SrcRect
), DstSurface
, wine_dbgstr_rect(DstRect
), flags
, FX
);
420 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
422 WARN("(%p): Not an overlay surface\n", This
);
423 return WINEDDERR_NOTAOVERLAYSURFACE
;
424 } else if(!DstSurface
) {
425 WARN("(%p): Dest surface is NULL\n", This
);
426 return WINED3DERR_INVALIDCALL
;
430 This
->overlay_srcrect
= *SrcRect
;
432 This
->overlay_srcrect
.left
= 0;
433 This
->overlay_srcrect
.top
= 0;
434 This
->overlay_srcrect
.right
= This
->currentDesc
.Width
;
435 This
->overlay_srcrect
.bottom
= This
->currentDesc
.Height
;
439 This
->overlay_destrect
= *DstRect
;
441 This
->overlay_destrect
.left
= 0;
442 This
->overlay_destrect
.top
= 0;
443 This
->overlay_destrect
.right
= Dst
? Dst
->currentDesc
.Width
: 0;
444 This
->overlay_destrect
.bottom
= Dst
? Dst
->currentDesc
.Height
: 0;
447 if (This
->overlay_dest
&& (This
->overlay_dest
!= Dst
|| flags
& WINEDDOVER_HIDE
))
449 list_remove(&This
->overlay_entry
);
452 if (flags
& WINEDDOVER_SHOW
)
454 if (This
->overlay_dest
!= Dst
)
456 This
->overlay_dest
= Dst
;
457 list_add_tail(&Dst
->overlays
, &This
->overlay_entry
);
460 else if (flags
& WINEDDOVER_HIDE
)
462 /* tests show that the rectangles are erased on hide */
463 This
->overlay_srcrect
.left
= 0; This
->overlay_srcrect
.top
= 0;
464 This
->overlay_srcrect
.right
= 0; This
->overlay_srcrect
.bottom
= 0;
465 This
->overlay_destrect
.left
= 0; This
->overlay_destrect
.top
= 0;
466 This
->overlay_destrect
.right
= 0; This
->overlay_destrect
.bottom
= 0;
467 This
->overlay_dest
= NULL
;
470 This
->surface_ops
->surface_draw_overlay(This
);
475 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface
*iface
, struct wined3d_clipper
*clipper
)
477 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
479 TRACE("iface %p, clipper %p.\n", iface
, clipper
);
481 This
->clipper
= clipper
;
486 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface
*iface
, struct wined3d_clipper
**clipper
)
488 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
490 TRACE("iface %p, clipper %p.\n", iface
, clipper
);
492 *clipper
= This
->clipper
;
494 wined3d_clipper_incref(*clipper
);
499 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface
*iface
, enum wined3d_format_id format_id
)
501 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
502 const struct wined3d_format
*format
= wined3d_get_format(&This
->resource
.device
->adapter
->gl_info
, format_id
);
504 if (This
->resource
.format
->id
!= WINED3DFMT_UNKNOWN
)
506 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This
);
507 return WINED3DERR_INVALIDCALL
;
510 TRACE("(%p) : Setting texture format to %s (%#x).\n", This
, debug_d3dformat(format_id
), format_id
);
512 This
->resource
.size
= wined3d_format_calculate_size(format
, This
->resource
.device
->surface_alignment
,
513 This
->pow2Width
, This
->pow2Height
);
515 This
->flags
|= (WINED3DFMT_D16_LOCKABLE
== format_id
) ? SFLAG_LOCKABLE
: 0;
517 This
->resource
.format
= format
;
519 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This
, This
->resource
.size
, format
->byte_count
);
524 HRESULT
IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface
*iface
)
526 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
527 const struct wined3d_format
*format
= This
->resource
.format
;
535 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
537 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format
->id
));
538 return WINED3DERR_INVALIDCALL
;
541 switch (format
->byte_count
)
545 /* Allocate extra space to store the RGB bit masks. */
546 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
550 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
554 /* Allocate extra space for a palette. */
555 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
556 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
561 return E_OUTOFMEMORY
;
563 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
564 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
565 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
566 * add an extra line to the dib section
568 GetSystemInfo(&sysInfo
);
569 if( ((This
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4) {
571 TRACE("Adding an extra line to the dib section\n");
574 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
575 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
576 b_info
->bmiHeader
.biWidth
= IWineD3DSurface_GetPitch(iface
) / format
->byte_count
;
577 b_info
->bmiHeader
.biHeight
= -This
->currentDesc
.Height
-extraline
;
578 b_info
->bmiHeader
.biSizeImage
= ( This
->currentDesc
.Height
+ extraline
) * IWineD3DSurface_GetPitch(iface
);
579 b_info
->bmiHeader
.biPlanes
= 1;
580 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
582 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
583 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
584 b_info
->bmiHeader
.biClrUsed
= 0;
585 b_info
->bmiHeader
.biClrImportant
= 0;
587 /* Get the bit masks */
588 masks
= (DWORD
*)b_info
->bmiColors
;
589 switch (This
->resource
.format
->id
)
591 case WINED3DFMT_B8G8R8_UNORM
:
592 usage
= DIB_RGB_COLORS
;
593 b_info
->bmiHeader
.biCompression
= BI_RGB
;
596 case WINED3DFMT_B5G5R5X1_UNORM
:
597 case WINED3DFMT_B5G5R5A1_UNORM
:
598 case WINED3DFMT_B4G4R4A4_UNORM
:
599 case WINED3DFMT_B4G4R4X4_UNORM
:
600 case WINED3DFMT_B2G3R3_UNORM
:
601 case WINED3DFMT_B2G3R3A8_UNORM
:
602 case WINED3DFMT_R10G10B10A2_UNORM
:
603 case WINED3DFMT_R8G8B8A8_UNORM
:
604 case WINED3DFMT_R8G8B8X8_UNORM
:
605 case WINED3DFMT_B10G10R10A2_UNORM
:
606 case WINED3DFMT_B5G6R5_UNORM
:
607 case WINED3DFMT_R16G16B16A16_UNORM
:
609 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
610 masks
[0] = format
->red_mask
;
611 masks
[1] = format
->green_mask
;
612 masks
[2] = format
->blue_mask
;
616 /* Don't know palette */
617 b_info
->bmiHeader
.biCompression
= BI_RGB
;
622 if (!(ddc
= GetDC(0)))
624 HeapFree(GetProcessHeap(), 0, b_info
);
625 return HRESULT_FROM_WIN32(GetLastError());
628 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
);
629 This
->dib
.DIBsection
= CreateDIBSection(ddc
, b_info
, usage
, &This
->dib
.bitmap_data
, 0 /* Handle */, 0 /* Offset */);
632 if (!This
->dib
.DIBsection
) {
633 ERR("CreateDIBSection failed!\n");
634 HeapFree(GetProcessHeap(), 0, b_info
);
635 return HRESULT_FROM_WIN32(GetLastError());
638 TRACE("DIBSection at : %p\n", This
->dib
.bitmap_data
);
639 /* copy the existing surface to the dib section */
640 if(This
->resource
.allocatedMemory
) {
641 memcpy(This
->dib
.bitmap_data
, This
->resource
.allocatedMemory
, This
->currentDesc
.Height
* IWineD3DSurface_GetPitch(iface
));
643 /* This is to make LockRect read the gl Texture although memory is allocated */
644 This
->flags
&= ~SFLAG_INSYSMEM
;
646 This
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
648 HeapFree(GetProcessHeap(), 0, b_info
);
650 /* Now allocate a HDC */
651 This
->hDC
= CreateCompatibleDC(0);
652 This
->dib
.holdbitmap
= SelectObject(This
->hDC
, This
->dib
.DIBsection
);
653 TRACE("using wined3d palette %p\n", This
->palette
);
654 SelectPalette(This
->hDC
,
655 This
->palette
? This
->palette
->hpal
: 0,
658 This
->flags
|= SFLAG_DIBSECTION
;
660 HeapFree(GetProcessHeap(), 0, This
->resource
.heapMemory
);
661 This
->resource
.heapMemory
= NULL
;
666 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
667 unsigned int w
, unsigned int h
)
671 unsigned short *dst_s
;
673 TRACE("Converting %dx%d pixels, pitches %d %d\n", w
, h
, pitch_in
, pitch_out
);
674 for(y
= 0; y
< h
; y
++) {
675 src_f
= (const float *)(src
+ y
* pitch_in
);
676 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
677 for(x
= 0; x
< w
; x
++) {
678 dst_s
[x
] = float_32_to_16(src_f
+ x
);
683 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
684 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
686 static const unsigned char convert_5to8
[] =
688 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
689 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
690 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
691 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
693 static const unsigned char convert_6to8
[] =
695 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
696 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
697 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
698 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
699 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
700 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
701 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
702 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
706 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
708 for (y
= 0; y
< h
; ++y
)
710 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
711 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
712 for (x
= 0; x
< w
; ++x
)
714 WORD pixel
= src_line
[x
];
715 dst_line
[x
] = 0xff000000
716 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
717 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
718 | convert_5to8
[(pixel
& 0x001f)];
723 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
724 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
728 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
730 for (y
= 0; y
< h
; ++y
)
732 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
733 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
735 for (x
= 0; x
< w
; ++x
)
737 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
742 static inline BYTE
cliptobyte(int x
)
744 return (BYTE
) ((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
747 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
748 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
751 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
753 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
755 for (y
= 0; y
< h
; ++y
)
757 const BYTE
*src_line
= src
+ y
* pitch_in
;
758 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
759 for (x
= 0; x
< w
; ++x
)
761 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
762 * C = Y - 16; D = U - 128; E = V - 128;
763 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
764 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
765 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
766 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
767 * U and V are shared between the pixels.
769 if (!(x
& 1)) /* for every even pixel, read new U and V */
771 d
= (int) src_line
[1] - 128;
772 e
= (int) src_line
[3] - 128;
774 g2
= - 100 * d
- 208 * e
+ 128;
777 c2
= 298 * ((int) src_line
[0] - 16);
778 dst_line
[x
] = 0xff000000
779 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
780 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
781 | cliptobyte((c2
+ b2
) >> 8); /* blue */
782 /* Scale RGB values to 0..255 range,
783 * then clip them if still not in range (may be negative),
784 * then shift them within DWORD if necessary.
791 struct d3dfmt_convertor_desc
793 enum wined3d_format_id from
, to
;
794 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
797 static const struct d3dfmt_convertor_desc convertors
[] =
799 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
800 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
801 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
802 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
805 static inline const struct d3dfmt_convertor_desc
*find_convertor(enum wined3d_format_id from
, enum wined3d_format_id to
)
808 for(i
= 0; i
< (sizeof(convertors
) / sizeof(convertors
[0])); i
++) {
809 if(convertors
[i
].from
== from
&& convertors
[i
].to
== to
) {
810 return &convertors
[i
];
816 /*****************************************************************************
817 * surface_convert_format
819 * Creates a duplicate of a surface in a different format. Is used by Blt to
820 * blit between surfaces with different formats
823 * source: Source surface
824 * fmt: Requested destination format
826 *****************************************************************************/
827 static IWineD3DSurfaceImpl
*surface_convert_format(IWineD3DSurfaceImpl
*source
, enum wined3d_format_id to_fmt
)
829 IWineD3DSurface
*ret
= NULL
;
830 const struct d3dfmt_convertor_desc
*conv
;
831 WINED3DLOCKED_RECT lock_src
, lock_dst
;
834 conv
= find_convertor(source
->resource
.format
->id
, to_fmt
);
837 FIXME("Cannot find a conversion function from format %s to %s.\n",
838 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
842 IWineD3DDevice_CreateSurface((IWineD3DDevice
*)source
->resource
.device
, source
->currentDesc
.Width
,
843 source
->currentDesc
.Height
, to_fmt
, TRUE
/* lockable */, TRUE
/* discard */, 0 /* level */,
844 0 /* usage */, WINED3DPOOL_SCRATCH
, WINED3DMULTISAMPLE_NONE
/* TODO: Multisampled conversion */,
845 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface
*) source
),
846 NULL
/* parent */, &wined3d_null_parent_ops
, &ret
);
848 ERR("Failed to create a destination surface for conversion\n");
852 memset(&lock_src
, 0, sizeof(lock_src
));
853 memset(&lock_dst
, 0, sizeof(lock_dst
));
855 hr
= IWineD3DSurface_Map((IWineD3DSurface
*)source
, &lock_src
, NULL
, WINED3DLOCK_READONLY
);
858 ERR("Failed to lock the source surface.\n");
859 IWineD3DSurface_Release(ret
);
862 hr
= IWineD3DSurface_Map(ret
, &lock_dst
, NULL
, WINED3DLOCK_READONLY
);
865 ERR("Failed to lock the dest surface\n");
866 IWineD3DSurface_Unmap((IWineD3DSurface
*)source
);
867 IWineD3DSurface_Release(ret
);
871 conv
->convert(lock_src
.pBits
, lock_dst
.pBits
, lock_src
.Pitch
, lock_dst
.Pitch
,
872 source
->currentDesc
.Width
, source
->currentDesc
.Height
);
874 IWineD3DSurface_Unmap(ret
);
875 IWineD3DSurface_Unmap((IWineD3DSurface
*)source
);
877 return (IWineD3DSurfaceImpl
*) ret
;
880 /*****************************************************************************
883 * Helper function that fills a memory area with a specific color
886 * buf: memory address to start filling at
887 * width, height: Dimensions of the area to fill
888 * bpp: Bit depth of the surface
889 * lPitch: pitch of the surface
890 * color: Color to fill with
892 *****************************************************************************/
894 _Blt_ColorFill(BYTE
*buf
,
895 int width
, int height
,
896 int bpp
, LONG lPitch
,
904 #define COLORFILL_ROW(type) \
906 type *d = (type *) buf; \
907 for (x = 0; x < width; x++) \
908 d[x] = (type) color; \
913 case 1: COLORFILL_ROW(BYTE
)
914 case 2: COLORFILL_ROW(WORD
)
918 for (x
= 0; x
< width
; x
++,d
+=3)
920 d
[0] = (color
) & 0xFF;
921 d
[1] = (color
>> 8) & 0xFF;
922 d
[2] = (color
>>16) & 0xFF;
926 case 4: COLORFILL_ROW(DWORD
)
928 FIXME("Color fill not implemented for bpp %d!\n", bpp
*8);
929 return WINED3DERR_NOTAVAILABLE
;
934 /* Now copy first row */
936 for (y
= 1; y
< height
; y
++)
939 memcpy(buf
, first
, width
* bpp
);
944 /*****************************************************************************
945 * IWineD3DSurface::Blt, SW emulation version
947 * Performs a blit to a surface, with or without a source surface.
948 * This is the main functionality of DirectDraw
951 * DestRect: Destination rectangle to write to
952 * src_surface: Source surface, can be NULL
953 * SrcRect: Source rectangle
954 *****************************************************************************/
955 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface
*iface
, const RECT
*DestRect
, IWineD3DSurface
*src_surface
,
956 const RECT
*SrcRect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
, WINED3DTEXTUREFILTERTYPE Filter
)
958 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
959 IWineD3DSurfaceImpl
*src
= (IWineD3DSurfaceImpl
*)src_surface
;
961 HRESULT ret
= WINED3D_OK
;
962 WINED3DLOCKED_RECT dlock
, slock
;
963 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
964 const struct wined3d_format
*sEntry
, *dEntry
;
969 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
970 iface
, wine_dbgstr_rect(DestRect
), src_surface
, wine_dbgstr_rect(SrcRect
),
971 flags
, DDBltFx
, debug_d3dtexturefiltertype(Filter
));
973 if ((This
->flags
& SFLAG_LOCKED
) || (src
&& (src
->flags
& SFLAG_LOCKED
)))
975 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
976 return WINEDDERR_SURFACEBUSY
;
979 /* First check for the validity of source / destination rectangles.
980 * This was verified using a test application + by MSDN. */
986 if (SrcRect
->right
< SrcRect
->left
|| SrcRect
->bottom
< SrcRect
->top
987 || SrcRect
->left
> src
->currentDesc
.Width
|| SrcRect
->left
< 0
988 || SrcRect
->top
> src
->currentDesc
.Height
|| SrcRect
->top
< 0
989 || SrcRect
->right
> src
->currentDesc
.Width
|| SrcRect
->right
< 0
990 || SrcRect
->bottom
> src
->currentDesc
.Height
|| SrcRect
->bottom
< 0)
992 WARN("Application gave us bad source rectangle for Blt.\n");
993 return WINEDDERR_INVALIDRECT
;
996 if (!SrcRect
->right
|| !SrcRect
->bottom
997 || SrcRect
->left
== (int)src
->currentDesc
.Width
998 || SrcRect
->top
== (int)src
->currentDesc
.Height
)
1000 TRACE("Nothing to be done.\n");
1011 xsrc
.right
= src
->currentDesc
.Width
;
1012 xsrc
.bottom
= src
->currentDesc
.Height
;
1016 memset(&xsrc
, 0, sizeof(xsrc
));
1021 /* For the Destination rect, it can be out of bounds on the condition
1022 * that a clipper is set for the given surface. */
1023 if (!This
->clipper
&& (DestRect
->right
< DestRect
->left
|| DestRect
->bottom
< DestRect
->top
1024 || DestRect
->left
> This
->currentDesc
.Width
|| DestRect
->left
< 0
1025 || DestRect
->top
> This
->currentDesc
.Height
|| DestRect
->top
< 0
1026 || DestRect
->right
> This
->currentDesc
.Width
|| DestRect
->right
< 0
1027 || DestRect
->bottom
> This
->currentDesc
.Height
|| DestRect
->bottom
< 0))
1029 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1030 return WINEDDERR_INVALIDRECT
;
1033 if (DestRect
->right
<= 0 || DestRect
->bottom
<= 0
1034 || DestRect
->left
>= (int)This
->currentDesc
.Width
1035 || DestRect
->top
>= (int)This
->currentDesc
.Height
)
1037 TRACE("Nothing to be done.\n");
1047 full_rect
.right
= This
->currentDesc
.Width
;
1048 full_rect
.bottom
= This
->currentDesc
.Height
;
1049 IntersectRect(&xdst
, &full_rect
, DestRect
);
1053 BOOL clip_horiz
, clip_vert
;
1056 clip_horiz
= xdst
.left
< 0 || xdst
.right
> (int)This
->currentDesc
.Width
;
1057 clip_vert
= xdst
.top
< 0 || xdst
.bottom
> (int)This
->currentDesc
.Height
;
1059 if (clip_vert
|| clip_horiz
)
1061 /* Now check if this is a special case or not... */
1062 if ((flags
& WINEDDBLT_DDFX
)
1063 || (clip_horiz
&& xdst
.right
- xdst
.left
!= xsrc
.right
- xsrc
.left
)
1064 || (clip_vert
&& xdst
.bottom
- xdst
.top
!= xsrc
.bottom
- xsrc
.top
))
1066 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1074 xsrc
.left
-= xdst
.left
;
1077 if (xdst
.right
> This
->currentDesc
.Width
)
1079 xsrc
.right
-= (xdst
.right
- (int)This
->currentDesc
.Width
);
1080 xdst
.right
= (int)This
->currentDesc
.Width
;
1088 xsrc
.top
-= xdst
.top
;
1091 if (xdst
.bottom
> This
->currentDesc
.Height
)
1093 xsrc
.bottom
-= (xdst
.bottom
- (int)This
->currentDesc
.Height
);
1094 xdst
.bottom
= (int)This
->currentDesc
.Height
;
1098 /* And check if after clipping something is still to be done... */
1099 if ((xdst
.right
<= 0) || (xdst
.bottom
<= 0)
1100 || (xdst
.left
>= (int)This
->currentDesc
.Width
)
1101 || (xdst
.top
>= (int)This
->currentDesc
.Height
)
1102 || (xsrc
.right
<= 0) || (xsrc
.bottom
<= 0)
1103 || (xsrc
.left
>= (int)src
->currentDesc
.Width
)
1104 || (xsrc
.top
>= (int)src
->currentDesc
.Height
))
1106 TRACE("Nothing to be done after clipping.\n");
1116 xdst
.right
= This
->currentDesc
.Width
;
1117 xdst
.bottom
= This
->currentDesc
.Height
;
1122 IWineD3DSurface_Map(iface
, &dlock
, NULL
, 0);
1124 sEntry
= This
->resource
.format
;
1129 dEntry
= This
->resource
.format
;
1132 if (This
->resource
.format
->id
!= src
->resource
.format
->id
)
1134 src
= surface_convert_format(src
, dEntry
->id
);
1137 /* The conv function writes a FIXME */
1138 WARN("Cannot convert source surface format to dest format\n");
1142 IWineD3DSurface_Map((IWineD3DSurface
*)src
, &slock
, NULL
, WINED3DLOCK_READONLY
);
1143 sEntry
= src
->resource
.format
;
1150 IWineD3DSurface_Map(iface
, &dlock
, &xdst
, 0);
1152 IWineD3DSurface_Map(iface
, &dlock
, NULL
, 0);
1155 if (!DDBltFx
|| !(DDBltFx
->dwDDFX
)) flags
&= ~WINEDDBLT_DDFX
;
1157 if (sEntry
->flags
& dEntry
->flags
& WINED3DFMT_FLAG_FOURCC
)
1159 if (!DestRect
|| src
== This
)
1161 memcpy(dlock
.pBits
, slock
.pBits
, This
->resource
.size
);
1166 bpp
= This
->resource
.format
->byte_count
;
1167 srcheight
= xsrc
.bottom
- xsrc
.top
;
1168 srcwidth
= xsrc
.right
- xsrc
.left
;
1169 dstheight
= xdst
.bottom
- xdst
.top
;
1170 dstwidth
= xdst
.right
- xdst
.left
;
1171 width
= (xdst
.right
- xdst
.left
) * bpp
;
1173 if (DestRect
&& src
!= This
)
1176 dbuf
= (BYTE
*)dlock
.pBits
+(xdst
.top
*dlock
.Pitch
)+(xdst
.left
*bpp
);
1178 if (flags
& WINEDDBLT_WAIT
)
1180 flags
&= ~WINEDDBLT_WAIT
;
1182 if (flags
& WINEDDBLT_ASYNC
)
1184 static BOOL displayed
= FALSE
;
1186 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1188 flags
&= ~WINEDDBLT_ASYNC
;
1190 if (flags
& WINEDDBLT_DONOTWAIT
)
1192 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1193 static BOOL displayed
= FALSE
;
1195 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1197 flags
&= ~WINEDDBLT_DONOTWAIT
;
1200 /* First, all the 'source-less' blits */
1201 if (flags
& WINEDDBLT_COLORFILL
)
1203 ret
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
,
1204 dlock
.Pitch
, DDBltFx
->u5
.dwFillColor
);
1205 flags
&= ~WINEDDBLT_COLORFILL
;
1208 if (flags
& WINEDDBLT_DEPTHFILL
)
1210 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1212 if (flags
& WINEDDBLT_ROP
)
1214 /* Catch some degenerate cases here */
1215 switch(DDBltFx
->dwROP
)
1218 ret
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,0);
1220 case 0xAA0029: /* No-op */
1223 ret
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,~0);
1225 case SRCCOPY
: /* well, we do that below ? */
1228 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx
->dwROP
, DDBltFx
->u5
.lpDDSPattern
);
1231 flags
&= ~WINEDDBLT_ROP
;
1233 if (flags
& WINEDDBLT_DDROPS
)
1235 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx
->dwDDROP
, DDBltFx
->u5
.lpDDSPattern
);
1237 /* Now the 'with source' blits */
1241 int sx
, xinc
, sy
, yinc
;
1243 if (!dstwidth
|| !dstheight
) /* hmm... stupid program ? */
1246 if (Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
1247 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
1249 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1250 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter
));
1253 sbase
= (BYTE
*)slock
.pBits
+(xsrc
.top
*slock
.Pitch
)+xsrc
.left
*bpp
;
1254 xinc
= (srcwidth
<< 16) / dstwidth
;
1255 yinc
= (srcheight
<< 16) / dstheight
;
1259 /* No effects, we can cheat here */
1260 if (dstwidth
== srcwidth
)
1262 if (dstheight
== srcheight
)
1264 /* No stretching in either direction. This needs to be as
1265 * fast as possible */
1268 /* check for overlapping surfaces */
1269 if (src
!= This
|| xdst
.top
< xsrc
.top
||
1270 xdst
.right
<= xsrc
.left
|| xsrc
.right
<= xdst
.left
)
1272 /* no overlap, or dst above src, so copy from top downwards */
1273 for (y
= 0; y
< dstheight
; y
++)
1275 memcpy(dbuf
, sbuf
, width
);
1276 sbuf
+= slock
.Pitch
;
1277 dbuf
+= dlock
.Pitch
;
1280 else if (xdst
.top
> xsrc
.top
) /* copy from bottom upwards */
1282 sbuf
+= (slock
.Pitch
*dstheight
);
1283 dbuf
+= (dlock
.Pitch
*dstheight
);
1284 for (y
= 0; y
< dstheight
; y
++)
1286 sbuf
-= slock
.Pitch
;
1287 dbuf
-= dlock
.Pitch
;
1288 memcpy(dbuf
, sbuf
, width
);
1291 else /* src and dst overlapping on the same line, use memmove */
1293 for (y
= 0; y
< dstheight
; y
++)
1295 memmove(dbuf
, sbuf
, width
);
1296 sbuf
+= slock
.Pitch
;
1297 dbuf
+= dlock
.Pitch
;
1301 /* Stretching in Y direction only */
1302 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
) {
1303 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1304 memcpy(dbuf
, sbuf
, width
);
1305 dbuf
+= dlock
.Pitch
;
1311 /* Stretching in X direction */
1313 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
)
1315 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1317 if ((sy
>> 16) == (last_sy
>> 16))
1319 /* this sourcerow is the same as last sourcerow -
1320 * copy already stretched row
1322 memcpy(dbuf
, dbuf
- dlock
.Pitch
, width
);
1326 #define STRETCH_ROW(type) { \
1327 const type *s = (const type *)sbuf; \
1328 type *d = (type *)dbuf; \
1329 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1330 d[x] = s[sx >> 16]; \
1335 case 1: STRETCH_ROW(BYTE
)
1336 case 2: STRETCH_ROW(WORD
)
1337 case 4: STRETCH_ROW(DWORD
)
1342 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
1346 s
= sbuf
+3*(sx
>>16);
1347 pixel
= s
[0]|(s
[1]<<8)|(s
[2]<<16);
1348 d
[0] = (pixel
)&0xff;
1349 d
[1] = (pixel
>> 8)&0xff;
1350 d
[2] = (pixel
>>16)&0xff;
1356 FIXME("Stretched blit not implemented for bpp %d!\n", bpp
*8);
1357 ret
= WINED3DERR_NOTAVAILABLE
;
1362 dbuf
+= dlock
.Pitch
;
1369 LONG dstyinc
= dlock
.Pitch
, dstxinc
= bpp
;
1370 DWORD keylow
= 0xFFFFFFFF, keyhigh
= 0, keymask
= 0xFFFFFFFF;
1371 DWORD destkeylow
= 0x0, destkeyhigh
= 0xFFFFFFFF, destkeymask
= 0xFFFFFFFF;
1372 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
1374 /* The color keying flags are checked for correctness in ddraw */
1375 if (flags
& WINEDDBLT_KEYSRC
)
1377 keylow
= src
->SrcBltCKey
.dwColorSpaceLowValue
;
1378 keyhigh
= src
->SrcBltCKey
.dwColorSpaceHighValue
;
1380 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
1382 keylow
= DDBltFx
->ddckSrcColorkey
.dwColorSpaceLowValue
;
1383 keyhigh
= DDBltFx
->ddckSrcColorkey
.dwColorSpaceHighValue
;
1386 if (flags
& WINEDDBLT_KEYDEST
)
1388 /* Destination color keys are taken from the source surface ! */
1389 destkeylow
= src
->DestBltCKey
.dwColorSpaceLowValue
;
1390 destkeyhigh
= src
->DestBltCKey
.dwColorSpaceHighValue
;
1392 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
1394 destkeylow
= DDBltFx
->ddckDestColorkey
.dwColorSpaceLowValue
;
1395 destkeyhigh
= DDBltFx
->ddckDestColorkey
.dwColorSpaceHighValue
;
1404 keymask
= sEntry
->red_mask
1405 | sEntry
->green_mask
1406 | sEntry
->blue_mask
;
1408 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
1411 if (flags
& WINEDDBLT_DDFX
)
1413 LPBYTE dTopLeft
, dTopRight
, dBottomLeft
, dBottomRight
, tmp
;
1416 dTopRight
= dbuf
+((dstwidth
-1)*bpp
);
1417 dBottomLeft
= dTopLeft
+((dstheight
-1)*dlock
.Pitch
);
1418 dBottomRight
= dBottomLeft
+((dstwidth
-1)*bpp
);
1420 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
1422 /* I don't think we need to do anything about this flag */
1423 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1425 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
1428 dTopRight
= dTopLeft
;
1431 dBottomRight
= dBottomLeft
;
1433 dstxinc
= dstxinc
*-1;
1435 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
1438 dTopLeft
= dBottomLeft
;
1441 dTopRight
= dBottomRight
;
1443 dstyinc
= dstyinc
*-1;
1445 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
1447 /* I don't think we need to do anything about this flag */
1448 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1450 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
1453 dBottomRight
= dTopLeft
;
1456 dBottomLeft
= dTopRight
;
1458 dstxinc
= dstxinc
* -1;
1459 dstyinc
= dstyinc
* -1;
1461 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
1464 dTopLeft
= dBottomLeft
;
1465 dBottomLeft
= dBottomRight
;
1466 dBottomRight
= dTopRight
;
1471 dstxinc
= dstxinc
* -1;
1473 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
1476 dTopLeft
= dTopRight
;
1477 dTopRight
= dBottomRight
;
1478 dBottomRight
= dBottomLeft
;
1483 dstyinc
= dstyinc
* -1;
1485 if (DDBltFx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
1487 /* I don't think we need to do anything about this flag */
1488 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1491 flags
&= ~(WINEDDBLT_DDFX
);
1494 #define COPY_COLORKEY_FX(type) { \
1496 type *d = (type *)dbuf, *dx, tmp; \
1497 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1498 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1500 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1501 tmp = s[sx >> 16]; \
1502 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1503 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1506 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1508 d = (type*)(((LPBYTE)d)+dstyinc); \
1513 case 1: COPY_COLORKEY_FX(BYTE
)
1514 case 2: COPY_COLORKEY_FX(WORD
)
1515 case 4: COPY_COLORKEY_FX(DWORD
)
1519 BYTE
*d
= dbuf
, *dx
;
1520 for (y
= sy
= 0; y
< dstheight
; y
++, sy
+= yinc
)
1522 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
1524 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
1526 DWORD pixel
, dpixel
= 0;
1527 s
= sbuf
+3*(sx
>>16);
1528 pixel
= s
[0]|(s
[1]<<8)|(s
[2]<<16);
1529 dpixel
= dx
[0]|(dx
[1]<<8)|(dx
[2]<<16);
1530 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
) &&
1531 ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
1533 dx
[0] = (pixel
)&0xff;
1534 dx
[1] = (pixel
>> 8)&0xff;
1535 dx
[2] = (pixel
>>16)&0xff;
1544 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1545 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
*8);
1546 ret
= WINED3DERR_NOTAVAILABLE
;
1548 #undef COPY_COLORKEY_FX
1554 if (flags
&& FIXME_ON(d3d_surface
))
1556 FIXME("\tUnsupported flags: %#x.\n", flags
);
1560 IWineD3DSurface_Unmap(iface
);
1561 if (src
&& src
!= This
) IWineD3DSurface_Unmap((IWineD3DSurface
*)src
);
1562 /* Release the converted surface if any */
1563 if (src
&& src_surface
!= (IWineD3DSurface
*)src
) IWineD3DSurface_Release((IWineD3DSurface
*)src
);
1567 /*****************************************************************************
1568 * IWineD3DSurface::BltFast, SW emulation version
1570 * This is the software implementation of BltFast, as used by GDI surfaces
1571 * and as a fallback for OpenGL surfaces. This code is taken from the old
1572 * DirectDraw code, and was originally written by TransGaming.
1577 * src_surface: Source surface to copy from
1578 * rsrc: Source rectangle
1582 * WINED3D_OK on success
1584 *****************************************************************************/
1585 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface
*iface
, DWORD dstx
, DWORD dsty
,
1586 IWineD3DSurface
*src_surface
, const RECT
*rsrc
, DWORD trans
)
1588 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1589 IWineD3DSurfaceImpl
*src
= (IWineD3DSurfaceImpl
*)src_surface
;
1591 int bpp
, w
, h
, x
, y
;
1592 WINED3DLOCKED_RECT dlock
,slock
;
1593 HRESULT ret
= WINED3D_OK
;
1595 RECT lock_src
, lock_dst
, lock_union
;
1598 const struct wined3d_format
*sEntry
, *dEntry
;
1600 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1601 iface
, dstx
, dsty
, src_surface
, wine_dbgstr_rect(rsrc
), trans
);
1603 if ((This
->flags
& SFLAG_LOCKED
) || (src
->flags
& SFLAG_LOCKED
))
1605 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1606 return WINEDDERR_SURFACEBUSY
;
1611 WARN("rsrc is NULL!\n");
1614 rsrc2
.right
= src
->currentDesc
.Width
;
1615 rsrc2
.bottom
= src
->currentDesc
.Height
;
1619 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1620 if ((rsrc
->bottom
> src
->currentDesc
.Height
) || (rsrc
->bottom
< 0)
1621 || (rsrc
->top
> src
->currentDesc
.Height
) || (rsrc
->top
< 0)
1622 || (rsrc
->left
> src
->currentDesc
.Width
) || (rsrc
->left
< 0)
1623 || (rsrc
->right
> src
->currentDesc
.Width
) || (rsrc
->right
< 0)
1624 || (rsrc
->right
< rsrc
->left
) || (rsrc
->bottom
< rsrc
->top
))
1626 WARN("Application gave us bad source rectangle for BltFast.\n");
1627 return WINEDDERR_INVALIDRECT
;
1630 h
= rsrc
->bottom
- rsrc
->top
;
1631 if (h
> This
->currentDesc
.Height
-dsty
) h
= This
->currentDesc
.Height
-dsty
;
1632 if (h
> src
->currentDesc
.Height
-rsrc
->top
) h
= src
->currentDesc
.Height
-rsrc
->top
;
1633 if (h
<= 0) return WINEDDERR_INVALIDRECT
;
1635 w
= rsrc
->right
- rsrc
->left
;
1636 if (w
> This
->currentDesc
.Width
-dstx
) w
= This
->currentDesc
.Width
-dstx
;
1637 if (w
> src
->currentDesc
.Width
-rsrc
->left
) w
= src
->currentDesc
.Width
-rsrc
->left
;
1638 if (w
<= 0) return WINEDDERR_INVALIDRECT
;
1640 /* Now compute the locking rectangle... */
1641 lock_src
.left
= rsrc
->left
;
1642 lock_src
.top
= rsrc
->top
;
1643 lock_src
.right
= lock_src
.left
+ w
;
1644 lock_src
.bottom
= lock_src
.top
+ h
;
1646 lock_dst
.left
= dstx
;
1647 lock_dst
.top
= dsty
;
1648 lock_dst
.right
= dstx
+ w
;
1649 lock_dst
.bottom
= dsty
+ h
;
1651 bpp
= This
->resource
.format
->byte_count
;
1653 /* We need to lock the surfaces, or we won't get refreshes when done. */
1658 UnionRect(&lock_union
, &lock_src
, &lock_dst
);
1660 /* Lock the union of the two rectangles */
1661 ret
= IWineD3DSurface_Map(iface
, &dlock
, &lock_union
, 0);
1662 if (FAILED(ret
)) goto error
;
1664 pitch
= dlock
.Pitch
;
1665 slock
.Pitch
= dlock
.Pitch
;
1667 /* Since slock was originally copied from this surface's description, we can just reuse it */
1668 sbuf
= This
->resource
.allocatedMemory
+ lock_src
.top
* pitch
+ lock_src
.left
* bpp
;
1669 dbuf
= This
->resource
.allocatedMemory
+ lock_dst
.top
* pitch
+ lock_dst
.left
* bpp
;
1670 sEntry
= src
->resource
.format
;
1675 ret
= IWineD3DSurface_Map(src_surface
, &slock
, &lock_src
, WINED3DLOCK_READONLY
);
1676 if (FAILED(ret
)) goto error
;
1677 ret
= IWineD3DSurface_Map(iface
, &dlock
, &lock_dst
, 0);
1678 if (FAILED(ret
)) goto error
;
1682 TRACE("Dst is at %p, Src is at %p\n", dbuf
, sbuf
);
1684 sEntry
= src
->resource
.format
;
1685 dEntry
= This
->resource
.format
;
1688 /* Handle compressed surfaces first... */
1689 if (sEntry
->flags
& dEntry
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1691 UINT row_block_count
;
1693 TRACE("compressed -> compressed copy\n");
1695 FIXME("trans arg not supported when a compressed surface is involved\n");
1697 FIXME("offset for destination surface is not supported\n");
1698 if (src
->resource
.format
->id
!= This
->resource
.format
->id
)
1700 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1701 ret
= WINED3DERR_WRONGTEXTUREFORMAT
;
1705 row_block_count
= (w
+ dEntry
->block_width
- 1) / dEntry
->block_width
;
1706 for (y
= 0; y
< h
; y
+= dEntry
->block_height
)
1708 memcpy(dbuf
, sbuf
, row_block_count
* dEntry
->block_byte_count
);
1709 dbuf
+= dlock
.Pitch
;
1710 sbuf
+= slock
.Pitch
;
1715 if ((sEntry
->flags
& WINED3DFMT_FLAG_COMPRESSED
) && !(dEntry
->flags
& WINED3DFMT_FLAG_COMPRESSED
))
1717 /* TODO: Use the libtxc_dxtn.so shared library to do
1718 * software decompression
1720 ERR("Software decompression not supported.\n");
1724 if (trans
& (WINEDDBLTFAST_SRCCOLORKEY
| WINEDDBLTFAST_DESTCOLORKEY
))
1726 DWORD keylow
, keyhigh
;
1727 DWORD mask
= src
->resource
.format
->red_mask
1728 | src
->resource
.format
->green_mask
1729 | src
->resource
.format
->blue_mask
;
1731 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1735 TRACE("Color keyed copy\n");
1736 if (trans
& WINEDDBLTFAST_SRCCOLORKEY
)
1738 keylow
= src
->SrcBltCKey
.dwColorSpaceLowValue
;
1739 keyhigh
= src
->SrcBltCKey
.dwColorSpaceHighValue
;
1743 /* I'm not sure if this is correct */
1744 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1745 keylow
= This
->DestBltCKey
.dwColorSpaceLowValue
;
1746 keyhigh
= This
->DestBltCKey
.dwColorSpaceHighValue
;
1749 #define COPYBOX_COLORKEY(type) { \
1750 const type *s = (const type *)sbuf; \
1751 type *d = (type *)dbuf; \
1753 for (y = 0; y < h; y++) { \
1754 for (x = 0; x < w; x++) { \
1756 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1758 s = (const type *)((const BYTE *)s + slock.Pitch); \
1759 d = (type *)((BYTE *)d + dlock.Pitch); \
1765 case 1: COPYBOX_COLORKEY(BYTE
)
1766 case 2: COPYBOX_COLORKEY(WORD
)
1767 case 4: COPYBOX_COLORKEY(DWORD
)
1775 for (y
= 0; y
< h
; y
++)
1777 for (x
= 0; x
< w
* 3; x
+= 3)
1779 tmp
= (DWORD
)s
[x
] + ((DWORD
)s
[x
+ 1] << 8) + ((DWORD
)s
[x
+ 2] << 16);
1780 if (tmp
< keylow
|| tmp
> keyhigh
)
1782 d
[x
+ 0] = s
[x
+ 0];
1783 d
[x
+ 1] = s
[x
+ 1];
1784 d
[x
+ 2] = s
[x
+ 2];
1793 FIXME("Source color key blitting not supported for bpp %d\n",bpp
*8);
1794 ret
= WINED3DERR_NOTAVAILABLE
;
1797 #undef COPYBOX_COLORKEY
1798 TRACE("Copy Done\n");
1802 int width
= w
* bpp
;
1803 INT sbufpitch
, dbufpitch
;
1805 TRACE("NO color key copy\n");
1806 /* Handle overlapping surfaces */
1809 sbuf
+= (h
- 1) * slock
.Pitch
;
1810 dbuf
+= (h
- 1) * dlock
.Pitch
;
1811 sbufpitch
= -slock
.Pitch
;
1812 dbufpitch
= -dlock
.Pitch
;
1816 sbufpitch
= slock
.Pitch
;
1817 dbufpitch
= dlock
.Pitch
;
1819 for (y
= 0; y
< h
; y
++)
1821 /* This is pretty easy, a line for line memcpy */
1822 memmove(dbuf
, sbuf
, width
);
1826 TRACE("Copy done\n");
1832 IWineD3DSurface_Unmap(iface
);
1836 IWineD3DSurface_Unmap(iface
);
1837 IWineD3DSurface_Unmap(src_surface
);
1843 HRESULT WINAPI
IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface
*iface
,
1844 WINED3DLOCKED_RECT
*pLockedRect
, const RECT
*pRect
, DWORD flags
)
1846 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1848 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1849 iface
, pLockedRect
, wine_dbgstr_rect(pRect
), flags
);
1851 pLockedRect
->Pitch
= IWineD3DSurface_GetPitch(iface
);
1855 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
1856 This
->lockedRect
.left
= 0;
1857 This
->lockedRect
.top
= 0;
1858 This
->lockedRect
.right
= This
->currentDesc
.Width
;
1859 This
->lockedRect
.bottom
= This
->currentDesc
.Height
;
1861 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1862 &This
->lockedRect
, This
->lockedRect
.left
, This
->lockedRect
.top
,
1863 This
->lockedRect
.right
, This
->lockedRect
.bottom
);
1867 const struct wined3d_format
*format
= This
->resource
.format
;
1869 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1870 pRect
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
1872 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
1874 /* Compressed textures are block based, so calculate the offset of
1875 * the block that contains the top-left pixel of the locked rectangle. */
1876 pLockedRect
->pBits
= This
->resource
.allocatedMemory
1877 + ((pRect
->top
/ format
->block_height
) * pLockedRect
->Pitch
)
1878 + ((pRect
->left
/ format
->block_width
) * format
->block_byte_count
);
1882 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+
1883 (pLockedRect
->Pitch
* pRect
->top
) +
1884 (pRect
->left
* format
->byte_count
);
1886 This
->lockedRect
.left
= pRect
->left
;
1887 This
->lockedRect
.top
= pRect
->top
;
1888 This
->lockedRect
.right
= pRect
->right
;
1889 This
->lockedRect
.bottom
= pRect
->bottom
;
1892 /* No dirtifying is needed for this surface implementation */
1893 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
);