wined3d: Instancing emulation.
This commit is contained in:
parent
93cd7ef7ff
commit
0feddccfe3
|
@ -2067,6 +2067,8 @@ VertexOffset = StartVertex / Divider * StreamStride +
|
||||||
*/
|
*/
|
||||||
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
|
static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
|
||||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||||
|
UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
|
||||||
|
UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
|
||||||
|
|
||||||
TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
|
TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
|
||||||
This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
|
This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
|
||||||
|
@ -2075,8 +2077,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *ifa
|
||||||
This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
|
This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
|
||||||
This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
|
This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
|
||||||
|
|
||||||
if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
|
if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
|
||||||
FIXME("Stream indexing not fully supported\n");
|
This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
|
||||||
|
IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
|
||||||
}
|
}
|
||||||
|
|
||||||
return WINED3D_OK;
|
return WINED3D_OK;
|
||||||
|
|
|
@ -1770,6 +1770,26 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt
|
||||||
TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */
|
TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */
|
||||||
return WINED3DERR_NOTAVAILABLE;
|
return WINED3DERR_NOTAVAILABLE;
|
||||||
|
|
||||||
|
/* ATI instancing hack: Although ATI cards do not support Shader Model 3.0, they support
|
||||||
|
* instancing. To query if the card supports instancing CheckDeviceFormat with the special format
|
||||||
|
* MAKEFOURCC('I','N','S','T') is used. Should a (broken) app check for this provide a proper return value.
|
||||||
|
* We can do instancing with all shader versions, but we need vertex shaders.
|
||||||
|
*
|
||||||
|
* Additionally applications have to set the D3DRS_POINTSIZE render state to MAKEFOURCC('I','N','S','T') once
|
||||||
|
* to enable instancing. WineD3D doesn't need that and just ignores it.
|
||||||
|
*
|
||||||
|
* With Shader Model 3.0 capable cards Instancing 'just works' in Windows.
|
||||||
|
*/
|
||||||
|
case MAKEFOURCC('I','N','S','T'):
|
||||||
|
TRACE("ATI Instancing check hack\n");
|
||||||
|
if(GL_SUPPORT(ARB_VERTEX_PROGRAM) || GL_SUPPORT(ARB_VERTEX_SHADER)) {
|
||||||
|
TRACE_(d3d_caps)("[OK]\n");
|
||||||
|
return WINED3D_OK;
|
||||||
|
} else {
|
||||||
|
TRACE_(d3d_caps)("[FAILED]\n");
|
||||||
|
return WINED3DERR_NOTAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* Copyright 2004 Christian Costa
|
* Copyright 2004 Christian Costa
|
||||||
* Copyright 2005 Oliver Stieber
|
* Copyright 2005 Oliver Stieber
|
||||||
* Copyright 2006 Henri Verbeet
|
* Copyright 2006 Henri Verbeet
|
||||||
|
* Copyright 2007 Stefan Dösinger for CodeWeavers
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -1155,6 +1156,142 @@ static void depth_copy(IWineD3DDevice *iface) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd, UINT numberOfVertices,
|
||||||
|
GLenum glPrimitiveType, const void *idxData, short idxSize, ULONG minIndex,
|
||||||
|
ULONG startIdx, ULONG startVertex) {
|
||||||
|
UINT numInstances = 0;
|
||||||
|
int numInstancedAttribs = 0, i, j;
|
||||||
|
UINT instancedData[sizeof(sd->u.input) / sizeof(sd->u.input[0]) /* 16 */];
|
||||||
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
|
||||||
|
IWineD3DStateBlockImpl *stateblock = This->stateBlock;
|
||||||
|
|
||||||
|
if (idxData == NULL) {
|
||||||
|
/* This is a nasty thing. MSDN says no hardware supports that and apps have to use software vertex processing.
|
||||||
|
* We don't support this for now
|
||||||
|
*
|
||||||
|
* Shouldn't be too hard to support with opengl, in theory just call glDrawArrays instead of drawElements.
|
||||||
|
* But the StreamSourceFreq value has a different meaning in that situation.
|
||||||
|
*/
|
||||||
|
FIXME("Non-indexed instanced drawing is not supported\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
|
||||||
|
idxData = idxData == (void *)-1 ? NULL : idxData;
|
||||||
|
|
||||||
|
/* First, figure out how many instances we have to draw */
|
||||||
|
for(i = 0; i < MAX_STREAMS; i++) {
|
||||||
|
/* Look at all non-instanced streams */
|
||||||
|
if(!(stateblock->streamFlags[i] & D3DSTREAMSOURCE_INSTANCEDATA) &&
|
||||||
|
stateblock->streamSource[i]) {
|
||||||
|
int inst = stateblock->streamFreq[i];
|
||||||
|
|
||||||
|
if(numInstances && inst != numInstances) {
|
||||||
|
ERR("Two streams specify a different number of instances. Got %d, new is %d\n", numInstances, inst);
|
||||||
|
}
|
||||||
|
numInstances = inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof(sd->u.input) / sizeof(sd->u.input[0]); i++) {
|
||||||
|
if(stateblock->streamFlags[sd->u.input[i].streamNo] & D3DSTREAMSOURCE_INSTANCEDATA) {
|
||||||
|
instancedData[numInstancedAttribs] = i;
|
||||||
|
numInstancedAttribs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now draw numInstances instances :-) */
|
||||||
|
for(i = 0; i < numInstances; i++) {
|
||||||
|
/* Specify the instanced attributes using immediate mode calls */
|
||||||
|
for(j = 0; j < numInstancedAttribs; j++) {
|
||||||
|
BYTE *ptr = sd->u.input[instancedData[j]].lpData +
|
||||||
|
sd->u.input[instancedData[j]].dwStride * i +
|
||||||
|
stateblock->streamOffset[sd->u.input[instancedData[j]].streamNo];
|
||||||
|
if(sd->u.input[instancedData[j]].VBO) {
|
||||||
|
IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) stateblock->streamSource[sd->u.input[instancedData[j]].streamNo];
|
||||||
|
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(glVertexAttrib4NubvARB(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
|
||||||
|
*/
|
||||||
|
FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_2\n");
|
||||||
|
break;
|
||||||
|
case WINED3DDECLTYPE_FLOAT16_4:
|
||||||
|
FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_4\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WINED3DDECLTYPE_UNUSED:
|
||||||
|
default:
|
||||||
|
ERR("Unexpected declaration in instanced attributes\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
|
||||||
|
(const char *)idxData+(idxSize * startIdx));
|
||||||
|
checkGLcall("glDrawElements");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Routine common to the draw primitive and draw indexed primitive routines */
|
/* Routine common to the draw primitive and draw indexed primitive routines */
|
||||||
void drawPrimitive(IWineD3DDevice *iface,
|
void drawPrimitive(IWineD3DDevice *iface,
|
||||||
int PrimitiveType,
|
int PrimitiveType,
|
||||||
|
@ -1202,13 +1339,20 @@ void drawPrimitive(IWineD3DDevice *iface,
|
||||||
if (numberOfVertices == 0 )
|
if (numberOfVertices == 0 )
|
||||||
numberOfVertices = calculatedNumberOfindices;
|
numberOfVertices = calculatedNumberOfindices;
|
||||||
|
|
||||||
if (This->useDrawStridedSlow)
|
if (This->useDrawStridedSlow) {
|
||||||
|
/* Immediate mode drawing */
|
||||||
drawStridedSlow(iface, &This->strided_streams, calculatedNumberOfindices,
|
drawStridedSlow(iface, &This->strided_streams, calculatedNumberOfindices,
|
||||||
glPrimType, idxData, idxSize, minIndex, StartIdx, StartVertexIndex);
|
glPrimType, idxData, idxSize, minIndex, StartIdx, StartVertexIndex);
|
||||||
else
|
} else if(This->instancedDraw) {
|
||||||
|
/* 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 */
|
||||||
drawStridedFast(iface, calculatedNumberOfindices, glPrimType,
|
drawStridedFast(iface, calculatedNumberOfindices, glPrimType,
|
||||||
idxData, idxSize, minIndex, StartIdx, StartVertexIndex);
|
idxData, idxSize, minIndex, StartIdx, StartVertexIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Finshed updating the screen, restore lock */
|
/* Finshed updating the screen, restore lock */
|
||||||
LEAVE_GL();
|
LEAVE_GL();
|
||||||
|
|
|
@ -2146,11 +2146,21 @@ static inline void loadNumberedArrays(IWineD3DStateBlockImpl *stateblock, WineDi
|
||||||
int i;
|
int i;
|
||||||
UINT *offset = stateblock->streamOffset;
|
UINT *offset = stateblock->streamOffset;
|
||||||
|
|
||||||
|
/* Default to no instancing */
|
||||||
|
stateblock->wineD3DDevice->instancedDraw = FALSE;
|
||||||
|
|
||||||
for (i = 0; i < MAX_ATTRIBS; i++) {
|
for (i = 0; i < MAX_ATTRIBS; i++) {
|
||||||
|
|
||||||
if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
|
if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Do not load instance data. It will be specified using glTexCoord by drawprim */
|
||||||
|
if(stateblock->streamFlags[strided->u.input[i].streamNo] & D3DSTREAMSOURCE_INSTANCEDATA) {
|
||||||
|
GL_EXTCALL(glDisableVertexAttribArrayARB(i));
|
||||||
|
stateblock->wineD3DDevice->instancedDraw = TRUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
|
TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
|
||||||
|
|
||||||
if(strided->u.input[i].dwStride) {
|
if(strided->u.input[i].dwStride) {
|
||||||
|
@ -2227,11 +2237,11 @@ static inline void loadNumberedArrays(IWineD3DStateBlockImpl *stateblock, WineDi
|
||||||
|
|
||||||
case WINED3DDECLTYPE_UDEC3:
|
case WINED3DDECLTYPE_UDEC3:
|
||||||
FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n");
|
FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n");
|
||||||
/*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */
|
/*glVertexAttrib3usvARB(i, (GLushort *) ptr); Does not exist */
|
||||||
break;
|
break;
|
||||||
case WINED3DDECLTYPE_DEC3N:
|
case WINED3DDECLTYPE_DEC3N:
|
||||||
FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n");
|
FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n");
|
||||||
/*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */
|
/*glVertexAttrib3NusvARB(i, (GLushort *) ptr); Does not exist */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WINED3DDECLTYPE_FLOAT16_2:
|
case WINED3DDECLTYPE_FLOAT16_2:
|
||||||
|
@ -2262,6 +2272,10 @@ static void loadVertexData(IWineD3DStateBlockImpl *stateblock, WineDirect3DVerte
|
||||||
GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
|
GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
|
||||||
|
|
||||||
TRACE("Using fast vertex array code\n");
|
TRACE("Using fast vertex array code\n");
|
||||||
|
|
||||||
|
/* This is fixed function pipeline only, and the fixed function pipeline doesn't do instancing */
|
||||||
|
stateblock->wineD3DDevice->instancedDraw = FALSE;
|
||||||
|
|
||||||
/* Blend Data ---------------------------------------------- */
|
/* Blend Data ---------------------------------------------- */
|
||||||
if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
|
if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
|
||||||
(sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
|
(sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
|
||||||
|
|
|
@ -681,6 +681,7 @@ struct IWineD3DDeviceImpl
|
||||||
WineDirect3DVertexStridedData strided_streams;
|
WineDirect3DVertexStridedData strided_streams;
|
||||||
WineDirect3DVertexStridedData *up_strided;
|
WineDirect3DVertexStridedData *up_strided;
|
||||||
BOOL useDrawStridedSlow;
|
BOOL useDrawStridedSlow;
|
||||||
|
BOOL instancedDraw;
|
||||||
|
|
||||||
/* Context management */
|
/* Context management */
|
||||||
WineD3DContext **contexts; /* Dynamic array containing pointers to context structures */
|
WineD3DContext **contexts; /* Dynamic array containing pointers to context structures */
|
||||||
|
|
Loading…
Reference in New Issue