Commit 825506d5 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: General cross format blitting infrastrucutre, R32F->R16F blits.

parent f5149e65
......@@ -4153,6 +4153,10 @@ HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3D
return IWineD3DBaseSurfaceImpl_SetContainer(iface, container);
}
static WINED3DSURFTYPE WINAPI IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface *iface) {
return SURFACE_OPENGL;
}
const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
{
/* IUnknown */
......@@ -4208,5 +4212,6 @@ const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
IWineD3DSurfaceImpl_SetFormat,
IWineD3DSurfaceImpl_PrivateSetup,
IWineD3DSurfaceImpl_ModifyLocation,
IWineD3DSurfaceImpl_LoadLocation
IWineD3DSurfaceImpl_LoadLocation,
IWineD3DSurfaceImpl_GetImplType
};
......@@ -575,6 +575,111 @@ HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
return WINED3D_OK;
}
void convert_r32f_r16f(BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h) {
unsigned int x, y;
float *src_f;
unsigned short *dst_s;
TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
for(y = 0; y < h; y++) {
src_f = (float *) (src + y * pitch_in);
dst_s = (unsigned short *) (dst + y * pitch_out);
for(x = 0; x < w; x++) {
dst_s[x] = float_32_to_16(src_f + x);
}
}
}
struct d3dfmt_convertor_desc {
WINED3DFORMAT from, to;
void (*convert)(BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
};
struct d3dfmt_convertor_desc convertors[] = {
{WINED3DFMT_R32F, WINED3DFMT_R16F, convert_r32f_r16f},
};
static inline struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to) {
unsigned int i;
for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
if(convertors[i].from == from && convertors[i].to == to) {
return &convertors[i];
}
}
return NULL;
}
/*****************************************************************************
* surface_convert_format
*
* Creates a duplicate of a surface in a different format. Is used by Blt to
* blit between surfaces with different formats
*
* Parameters
* source: Source surface
* fmt: Requested destination format
*
*****************************************************************************/
IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
IWineD3DSurface *ret = NULL;
struct d3dfmt_convertor_desc *conv;
WINED3DLOCKED_RECT lock_src, lock_dst;
HRESULT hr;
conv = find_convertor(source->resource.format, to_fmt);
if(!conv) {
FIXME("Cannot find a conversion function from format %s to %s\n",
debug_d3dformat(source->resource.format), debug_d3dformat(to_fmt));
return NULL;
}
IWineD3DDevice_CreateSurface((IWineD3DDevice *) source->resource.wineD3DDevice,
source->currentDesc.Width,
source->currentDesc.Height,
to_fmt,
TRUE, /* lockable */
TRUE, /* discard */
0, /* level */
&ret,
WINED3DRTYPE_SURFACE,
0, /* usage */
WINED3DPOOL_SCRATCH,
WINED3DMULTISAMPLE_NONE, /* TODO: Multisampled conversion */
0, /* multisamplequality */
NULL, /* sharedhandle */
IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
NULL); /* parent */
if(!ret) {
ERR("Failed to create a destination surface for conversion\n");
return NULL;
}
memset(&lock_src, 0, sizeof(lock_src));
memset(&lock_dst, 0, sizeof(lock_dst));
hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
if(FAILED(hr)) {
ERR("Failed to lock the source surface\n");
IWineD3DSurface_Release(ret);
return NULL;
}
hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
if(FAILED(hr)) {
ERR("Failed to lock the dest surface\n");
IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
IWineD3DSurface_Release(ret);
return NULL;
}
conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
source->currentDesc.Width, source->currentDesc.Height);
IWineD3DSurface_UnlockRect(ret);
IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
return (IWineD3DSurfaceImpl *) ret;
}
/*****************************************************************************
* _Blt_ColorFill
*
......@@ -710,14 +815,22 @@ IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface,
}
else
{
dfmt = This->resource.format;
dEntry = getFormatDescEntry(dfmt, NULL, NULL);
if (Src)
{
IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, WINED3DLOCK_READONLY);
if(This->resource.format != Src->resource.format) {
Src = surface_convert_format(Src, dfmt);
if(!Src) {
/* The conv function writes a FIXME */
WARN("Cannot convert source surface format to dest format\n");
goto release;
}
}
IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
sfmt = Src->resource.format;
}
sEntry = getFormatDescEntry(sfmt, NULL, NULL);
dfmt = This->resource.format;
dEntry = getFormatDescEntry(dfmt, NULL, NULL);
IWineD3DSurface_LockRect(iface, &dlock,NULL,0);
}
......@@ -725,22 +838,10 @@ IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface,
if (sEntry->isFourcc && dEntry->isFourcc)
{
if (sfmt != dfmt)
{
FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
ret = WINED3DERR_WRONGTEXTUREFORMAT;
goto release;
}
memcpy(dlock.pBits, slock.pBits, This->resource.size);
goto release;
}
if (sEntry->isFourcc && !dEntry->isFourcc)
{
FIXME("DXTC decompression not supported right now\n");
goto release;
}
if (DestRect)
{
memcpy(&xdst,DestRect,sizeof(xdst));
......@@ -977,7 +1078,7 @@ IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface,
sbuf = sbase;
/* check for overlapping surfaces */
if (SrcSurface != iface || xdst.top < xsrc.top ||
if (Src != This || xdst.top < xsrc.top ||
xdst.right <= xsrc.left || xsrc.right <= xdst.left)
{
/* no overlap, or dst above src, so copy from top downwards */
......@@ -1265,7 +1366,9 @@ error:
release:
IWineD3DSurface_UnlockRect(iface);
if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface);
if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
/* Release the converted surface if any */
if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
return ret;
}
......
......@@ -808,6 +808,10 @@ static HRESULT WINAPI IWineGDISurfaceImpl_LoadLocation(IWineD3DSurface *iface, D
return WINED3D_OK;
}
static WINED3DSURFTYPE WINAPI IWineGDISurfaceImpl_GetImplType(IWineD3DSurface *iface) {
return SURFACE_GDI;
}
/* FIXME: This vtable should not use any IWineD3DSurface* implementation functions,
* only IWineD3DBaseSurface and IWineGDISurface ones.
*/
......@@ -866,5 +870,6 @@ const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
IWineD3DBaseSurfaceImpl_SetFormat,
IWineGDISurfaceImpl_PrivateSetup,
IWineGDISurfaceImpl_ModifyLocation,
IWineGDISurfaceImpl_LoadLocation
IWineGDISurfaceImpl_LoadLocation,
IWineGDISurfaceImpl_GetImplType
};
......@@ -121,7 +121,15 @@ void init_type_lookup(WineD3D_GL_Info *gl_info);
#define WINED3D_ATR_NORMALIZED(type) GLINFO_LOCATION.glTypeLookup[type].normalized
#define WINED3D_ATR_TYPESIZE(type) GLINFO_LOCATION.glTypeLookup[type].typesize
/* See GL_NV_half_float for reference */
/* The following functions convert 16 bit floats in the FLOAT16 data type
* to standard C floats and vice versa. They do not depend on the encoding
* of the C float, so they are platform independent, but slow. On x86 and
* other IEEE 754 compliant platforms the conversion can be accelerated with
* bitshifting the exponent and mantissa. There are also some SSE-based
* assembly routines out there
*
* See GL_NV_half_float for a reference of the FLOAT16 / GL_HALF format
*/
static inline float float_16_to_32(const unsigned short *in) {
const unsigned short s = ((*in) & 0x8000);
const unsigned short e = ((*in) & 0x7C00) >> 10;
......@@ -139,6 +147,54 @@ static inline float float_16_to_32(const unsigned short *in) {
}
}
static inline unsigned short float_32_to_16(const float *in) {
int exp = 0;
float tmp = fabs(*in);
unsigned int mantissa;
unsigned short ret;
/* Deal with special numbers */
if(*in == 0.0) return 0x0000;
if(isnan(*in)) return 0x7C01;
if(isinf(*in)) return (*in < 0.0 ? 0xFC00 : 0x7c00);
if(tmp < pow(2, 10)) {
do
{
tmp = tmp * 2.0;
exp--;
}while(tmp < pow(2, 10));
} else if(tmp >= pow(2, 11)) {
do
{
tmp /= 2.0;
exp++;
}while(tmp >= pow(2, 11));
}
mantissa = (unsigned int) tmp;
if(tmp - mantissa >= 0.5) mantissa++; /* round to nearest, away from zero */
exp += 10; /* Normalize the mantissa */
exp += 15; /* Exponent is encoded with excess 15 */
if(exp > 30) { /* too big */
ret = 0x7c00; /* INF */
} else if(exp <= 0) {
/* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
while(exp <= 0) {
mantissa = mantissa >> 1;
exp++;
}
ret = mantissa & 0x3ff;
} else {
ret = (exp << 10) | (mantissa & 0x3ff);
}
ret |= ((*in < 0.0 ? 1 : 0) << 15); /* Add the sign */
return ret;
}
/**
* Settings
*/
......
......@@ -1165,6 +1165,7 @@ DECLARE_INTERFACE_(IWineD3DSurface,IWineD3DResource)
STDMETHOD(PrivateSetup)(THIS) PURE;
STDMETHOD_(void,ModifyLocation)(THIS_ DWORD flag, BOOL persistent);
STDMETHOD(LoadLocation)(THIS_ DWORD flag, const RECT *rect);
STDMETHOD_(WINED3DSURFTYPE,GetImplType)(THIS);
};
#undef INTERFACE
......@@ -1223,7 +1224,8 @@ DECLARE_INTERFACE_(IWineD3DSurface,IWineD3DResource)
#define IWineD3DSurface_SetFormat(p,a) (p)->lpVtbl->SetFormat(p,a)
#define IWineD3DSurface_PrivateSetup(p) (p)->lpVtbl->PrivateSetup(p)
#define IWineD3DSurface_ModifyLocation(p,a,b) (p)->lpVtbl->ModifyLocation(p,a,b)
#define IWineD3DSurface_LoadLocation(p,a,b) (p)->lpVtbl->LoadLocation(p,a,b)
#define IWineD3DSurface_LoadLocation(p,a,b) (p)->lpVtbl->LoadLocation(p,a,b)
#define IWineD3DSurface_GetImplType(p) (p)->lpVtbl->GetImplType(p)
#endif
/*****************************************************************************
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment