wined3d: General cross format blitting infrastrucutre, R32F->R16F blits.
This commit is contained in:
parent
f5149e651e
commit
825506d5ff
|
@ -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
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
Loading…
Reference in New Issue