From 7a1d35e513d75ec0f86b48418d8b4e6235e8dc19 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20D=C3=B6singer?= Date: Mon, 17 Dec 2007 18:18:19 +0100 Subject: [PATCH] wined3d: Emulate half float vertices if GL_NV_half_float is not there. --- dlls/wined3d/drawprim.c | 257 ++++++++++++++++++++++++++------------- dlls/wined3d/state.c | 6 + dlls/wined3d/vertexdeclaration.c | 3 + dlls/wined3d/wined3d_private.h | 1 + 4 files changed, 185 insertions(+), 82 deletions(-) diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 5b3a2e596db..f044a92e361 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -30,6 +30,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw); #define GLINFO_LOCATION This->adapter->gl_info #include +#include #if 0 /* TODO */ extern IWineD3DVertexShaderImpl* VertexShaders[64]; @@ -200,6 +201,10 @@ void primitiveDeclarationConvertToStridedData( if((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride) { FIXME("System memory vertex data load offset is negative!\n"); } + } else if(vertexDeclaration->half_float_used && !GL_SUPPORT(NV_HALF_FLOAT)) { + WARN("Half float vertex data used, but GL_NV_half_float is not supported. Not using vbos\n"); + streamVBO = 0; + data = ((IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[element->Stream])->resource.allocatedMemory; } if(fixup) { @@ -588,6 +593,170 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData checkGLcall("glEnd and previous calls"); } +/* See GL_NV_half_float for reference */ +static inline float float_16_to_32(const unsigned short *in) { + const unsigned short s = ((*in) & 0x8000); + const unsigned short e = ((*in) & 0x7C00) >> 10; + const unsigned short m = (*in) & 0x3FF; + const float sgn = (s ? -1.0 : 1.0); + + if(e == 0) { + if(m == 0) return sgn * 0.0; /* +0.0 or -0.0 */ + else return sgn * pow(2, -14.0) * ( (float) m / 1024.0); + } else if(e < 31) { + return sgn * pow(2, (float) e-15.0) * (1.0 + ((float) m / 1024.0)); + } else { + if(m == 0) return sgn / 0.0; /* +INF / -INF */ + else return 0.0 / 0.0; /* NAN */ + } +} + +static inline void send_attribute(IWineD3DDeviceImpl *This, const DWORD type, const UINT index, const void *ptr) { + switch(type) { + case WINED3DDECLTYPE_FLOAT1: + GL_EXTCALL(glVertexAttrib1fvARB(index, (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT2: + GL_EXTCALL(glVertexAttrib2fvARB(index, (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT3: + GL_EXTCALL(glVertexAttrib3fvARB(index, (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT4: + GL_EXTCALL(glVertexAttrib4fvARB(index, (float *) ptr)); + break; + + case WINED3DDECLTYPE_UBYTE4: + GL_EXTCALL(glVertexAttrib4ubvARB(index, ptr)); + break; + case WINED3DDECLTYPE_UBYTE4N: + case WINED3DDECLTYPE_D3DCOLOR: + GL_EXTCALL(glVertexAttrib4NubvARB(index, ptr)); + break; + + case WINED3DDECLTYPE_SHORT2: + GL_EXTCALL(glVertexAttrib4svARB(index, (GLshort *) ptr)); + break; + case WINED3DDECLTYPE_SHORT4: + GL_EXTCALL(glVertexAttrib4svARB(index, (GLshort *) ptr)); + break; + + case WINED3DDECLTYPE_SHORT2N: + { + GLshort s[4] = {((short *) ptr)[0], ((short *) ptr)[1], 0, 1}; + GL_EXTCALL(glVertexAttrib4NsvARB(index, s)); + break; + } + case WINED3DDECLTYPE_USHORT2N: + { + GLushort s[4] = {((unsigned short *) ptr)[0], ((unsigned short *) ptr)[1], 0, 1}; + GL_EXTCALL(glVertexAttrib4NusvARB(index, s)); + break; + } + case WINED3DDECLTYPE_SHORT4N: + GL_EXTCALL(glVertexAttrib4NsvARB(index, (GLshort *) ptr)); + break; + case WINED3DDECLTYPE_USHORT4N: + GL_EXTCALL(glVertexAttrib4NusvARB(index, (GLushort *) ptr)); + break; + + case WINED3DDECLTYPE_UDEC3: + FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n"); + /*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */ + break; + case WINED3DDECLTYPE_DEC3N: + FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n"); + /*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */ + break; + + case WINED3DDECLTYPE_FLOAT16_2: + /* Are those 16 bit floats. C doesn't have a 16 bit float type. I could read the single bits and calculate a 4 + * byte float according to the IEEE standard + */ + if (GL_SUPPORT(NV_HALF_FLOAT)) { + GL_EXTCALL(glVertexAttrib2hvNV(index, (GLhalfNV *)ptr)); + } else { + float x = float_16_to_32(((unsigned short *) ptr) + 0); + float y = float_16_to_32(((unsigned short *) ptr) + 1); + GL_EXTCALL(glVertexAttrib2fARB(index, x, y)); + } + break; + case WINED3DDECLTYPE_FLOAT16_4: + if (GL_SUPPORT(NV_HALF_FLOAT)) { + GL_EXTCALL(glVertexAttrib4hvNV(index, (GLhalfNV *)ptr)); + } else { + float x = float_16_to_32(((unsigned short *) ptr) + 0); + float y = float_16_to_32(((unsigned short *) ptr) + 1); + float z = float_16_to_32(((unsigned short *) ptr) + 2); + float w = float_16_to_32(((unsigned short *) ptr) + 3); + GL_EXTCALL(glVertexAttrib4fARB(index, x, y, z, w)); + } + break; + + case WINED3DDECLTYPE_UNUSED: + default: + ERR("Unexpected attribute declaration: %d\n", type); + break; + } +} + +static void drawStridedSlowVs(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd, UINT numberOfVertices, + GLenum glPrimitiveType, const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, + ULONG startVertex) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + long SkipnStrides = startVertex + This->stateBlock->loadBaseVertexIndex; + const WORD *pIdxBufS = NULL; + const DWORD *pIdxBufL = NULL; + LONG vx_index; + int i; + IWineD3DStateBlockImpl *stateblock = (IWineD3DStateBlockImpl *) This->stateBlock; + BYTE *ptr; + + if (idxSize != 0) { + /* Immediate mode drawing can't make use of indices in a vbo - get the data from the index buffer. + * If the index buffer has no vbo(not supported or other reason), or with user pointer drawing + * idxData will be != NULL + */ + if(idxData == NULL) { + idxData = ((IWineD3DIndexBufferImpl *) stateblock->pIndexData)->resource.allocatedMemory; + } + + if (idxSize == 2) pIdxBufS = (const WORD *) idxData; + else pIdxBufL = (const DWORD *) idxData; + } + + /* Start drawing in GL */ + VTRACE(("glBegin(%x)\n", glPrimType)); + glBegin(glPrimitiveType); + + for (vx_index = 0; vx_index < numberOfVertices; ++vx_index) { + if (idxData != NULL) { + + /* Indexed so work out the number of strides to skip */ + if (idxSize == 2) { + VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index])); + SkipnStrides = pIdxBufS[startIdx + vx_index] + stateblock->loadBaseVertexIndex; + } else { + VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index])); + SkipnStrides = pIdxBufL[startIdx + vx_index] + stateblock->loadBaseVertexIndex; + } + } + + for(i = MAX_ATTRIBS - 1; i >= 0; i--) { + if(!sd->u.input[i].lpData) continue; + + ptr = sd->u.input[i].lpData + + sd->u.input[i].dwStride * SkipnStrides + + stateblock->streamOffset[sd->u.input[i].streamNo]; + + send_attribute(This, sd->u.input[i].dwType, i, ptr); + } + } + + glEnd(); +} + static void depth_blt(IWineD3DDevice *iface, GLuint texture) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; GLint old_binding = 0; @@ -741,86 +910,7 @@ static inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVerte ptr += (long) vb->resource.allocatedMemory; } - switch(sd->u.input[instancedData[j]].dwType) { - case WINED3DDECLTYPE_FLOAT1: - GL_EXTCALL(glVertexAttrib1fvARB(instancedData[j], (float *) ptr)); - break; - case WINED3DDECLTYPE_FLOAT2: - GL_EXTCALL(glVertexAttrib2fvARB(instancedData[j], (float *) ptr)); - break; - case WINED3DDECLTYPE_FLOAT3: - GL_EXTCALL(glVertexAttrib3fvARB(instancedData[j], (float *) ptr)); - break; - case WINED3DDECLTYPE_FLOAT4: - GL_EXTCALL(glVertexAttrib4fvARB(instancedData[j], (float *) ptr)); - break; - - case WINED3DDECLTYPE_UBYTE4: - GL_EXTCALL(glVertexAttrib4ubvARB(instancedData[j], ptr)); - break; - case WINED3DDECLTYPE_UBYTE4N: - case WINED3DDECLTYPE_D3DCOLOR: - GL_EXTCALL(glVertexAttrib4NubvARB(instancedData[j], ptr)); - break; - - case WINED3DDECLTYPE_SHORT2: - GL_EXTCALL(glVertexAttrib4svARB(instancedData[j], (GLshort *) ptr)); - break; - case WINED3DDECLTYPE_SHORT4: - GL_EXTCALL(glVertexAttrib4svARB(instancedData[j], (GLshort *) ptr)); - break; - - case WINED3DDECLTYPE_SHORT2N: - { - GLshort s[4] = {((short *) ptr)[0], ((short *) ptr)[1], 0, 1}; - GL_EXTCALL(glVertexAttrib4NsvARB(instancedData[j], s)); - break; - } - case WINED3DDECLTYPE_USHORT2N: - { - GLushort s[4] = {((unsigned short *) ptr)[0], ((unsigned short *) ptr)[1], 0, 1}; - GL_EXTCALL(glVertexAttrib4NusvARB(instancedData[j], s)); - break; - } - case WINED3DDECLTYPE_SHORT4N: - GL_EXTCALL(glVertexAttrib4NsvARB(instancedData[j], (GLshort *) ptr)); - break; - case WINED3DDECLTYPE_USHORT4N: - GL_EXTCALL(glVertexAttrib4NusvARB(instancedData[j], (GLushort *) ptr)); - break; - - case WINED3DDECLTYPE_UDEC3: - FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n"); - /*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */ - break; - case WINED3DDECLTYPE_DEC3N: - FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n"); - /*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */ - break; - - case WINED3DDECLTYPE_FLOAT16_2: - /* Are those 16 bit floats. C doesn't have a 16 bit float type. I could read the single bits and calculate a 4 - * byte float according to the IEEE standard - */ - if (GL_SUPPORT(NV_HALF_FLOAT)) { - GL_EXTCALL(glVertexAttrib2hvNV(instancedData[j], (GLhalfNV *)ptr)); - } else { - FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_2\n"); - } - break; - case WINED3DDECLTYPE_FLOAT16_4: - if (GL_SUPPORT(NV_HALF_FLOAT)) { - GL_EXTCALL(glVertexAttrib4hvNV(instancedData[j], (GLhalfNV *)ptr)); - } else { - FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_4\n"); - } - break; - - case WINED3DDECLTYPE_UNUSED: - default: - ERR("Unexpected declaration in instanced attributes\n"); - break; - } + send_attribute(This, sd->u.input[instancedData[j]].dwType, instancedData[j], ptr); } glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, @@ -1037,10 +1127,13 @@ void drawPrimitive(IWineD3DDevice *iface, /* Instancing emulation with mixing immediate mode and arrays */ drawStridedInstanced(iface, &This->strided_streams, calculatedNumberOfindices, glPrimType, idxData, idxSize, minIndex, StartIdx, StartVertexIndex); - } else { - /* Simple array draw call */ + } else if(GL_SUPPORT(NV_HALF_FLOAT) || (!((IWineD3DVertexDeclarationImpl *) This->stateBlock->vertexDecl)->half_float_used)) { drawStridedFast(iface, calculatedNumberOfindices, glPrimType, idxData, idxSize, minIndex, StartIdx, StartVertexIndex); + } else { + FIXME("Using immediate mode with vertex shaders for half float emulation\n"); + drawStridedSlowVs(iface, strided, calculatedNumberOfindices, glPrimType, + idxData, idxSize, minIndex, StartIdx, StartVertexIndex); } } diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index dca2e882f6c..1ce2cec60cd 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -2884,6 +2884,11 @@ static inline void loadNumberedArrays(IWineD3DStateBlockImpl *stateblock, WineDi /* Default to no instancing */ stateblock->wineD3DDevice->instancedDraw = FALSE; + if(((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_used && !GL_SUPPORT(NV_HALF_FLOAT)) { + /* This will be handled using drawStridedSlow */ + return; + } + for (i = 0; i < MAX_ATTRIBS; i++) { if (!strided->u.input[i].lpData && !strided->u.input[i].VBO) @@ -2997,6 +3002,7 @@ static inline void loadNumberedArrays(IWineD3DStateBlockImpl *stateblock, WineDi } } } + checkGLcall("Loading numbered arrays"); } /* Used from 2 different functions, and too big to justify making it inlined */ diff --git a/dlls/wined3d/vertexdeclaration.c b/dlls/wined3d/vertexdeclaration.c index a62ac0116dc..929fd45dcfd 100644 --- a/dlls/wined3d/vertexdeclaration.c +++ b/dlls/wined3d/vertexdeclaration.c @@ -183,6 +183,9 @@ static HRESULT WINAPI IWineD3DVertexDeclarationImpl_SetDeclaration(IWineD3DVerte This->swizzled_attribs[j].usage = This->pDeclarationWine[i].Usage; This->swizzled_attribs[j].idx = This->pDeclarationWine[i].UsageIndex; This->num_swizzled_attribs++; + } else if(This->pDeclarationWine[i].Type == WINED3DDECLTYPE_FLOAT16_2 || + This->pDeclarationWine[i].Type == WINED3DDECLTYPE_FLOAT16_4) { + This->half_float_used = TRUE; } } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index f4c7c0b05f9..d3f3a59d237 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1268,6 +1268,7 @@ typedef struct IWineD3DVertexDeclarationImpl { DWORD streams[MAX_STREAMS]; UINT num_streams; BOOL position_transformed; + BOOL half_float_used; /* Ordered array of declaration types that need swizzling in a vshader */ attrib_declaration swizzled_attribs[MAX_ATTRIBS]; -- 2.11.4.GIT