implemented reinstancing for d3d9

This commit is contained in:
aap 2020-04-16 12:53:25 +02:00
parent 47fcb3001a
commit f1c9112f27
8 changed files with 189 additions and 100 deletions

View File

@ -257,7 +257,7 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
geo->instData = header; geo->instData = header;
header->platform = PLATFORM_D3D8; header->platform = PLATFORM_D3D8;
header->serialNumber = 0; header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes; header->numMeshes = meshh->numMeshes;
header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY); header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY);

View File

@ -97,14 +97,12 @@ getDeclaration(void *declaration, VertexElement *elements)
#endif #endif
} }
void
void* freeInstanceData(Geometry *geometry)
destroyNativeData(void *object, int32, int32)
{ {
Geometry *geometry = (Geometry*)object;
if(geometry->instData == nil || if(geometry->instData == nil ||
geometry->instData->platform != PLATFORM_D3D9) geometry->instData->platform != PLATFORM_D3D9)
return object; return;
InstanceDataHeader *header = InstanceDataHeader *header =
(InstanceDataHeader*)geometry->instData; (InstanceDataHeader*)geometry->instData;
geometry->instData = nil; geometry->instData = nil;
@ -114,6 +112,14 @@ destroyNativeData(void *object, int32, int32)
deleteObject(header->vertexStream[1].vertexBuffer); deleteObject(header->vertexStream[1].vertexBuffer);
rwFree(header->inst); rwFree(header->inst);
rwFree(header); rwFree(header);
return;
}
void*
destroyNativeData(void *object, int32, int32)
{
freeInstanceData((Geometry*)object);
return object; return object;
} }
@ -309,23 +315,18 @@ registerNativeDataPlugin(void)
getSizeNativeData); getSizeNativeData);
} }
static void static InstanceDataHeader*
instance(rw::ObjPipeline *rwpipe, Atomic *atomic) instanceMesh(rw::ObjPipeline *rwpipe, Geometry *geo)
{ {
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
Geometry *geo = atomic->geometry;
// TODO: allow for REINSTANCE
if(geo->instData)
return;
InstanceDataHeader *header = rwNewT(InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY); InstanceDataHeader *header = rwNewT(InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY);
MeshHeader *meshh = geo->meshHeader; MeshHeader *meshh = geo->meshHeader;
geo->instData = header;
header->platform = PLATFORM_D3D9; header->platform = PLATFORM_D3D9;
header->serialNumber = 0; header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes; header->numMeshes = meshh->numMeshes;
header->primType = meshh->flags == 1 ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST; header->primType = meshh->flags == 1 ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST;
header->useOffsets = 0; header->useOffsets = 0;
header->vertexDeclaration = nil;
header->totalNumVertex = geo->numVertices; header->totalNumVertex = geo->numVertices;
header->totalNumIndex = meshh->totalIndices; header->totalNumIndex = meshh->totalIndices;
header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY); header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY);
@ -359,7 +360,36 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
memset(&header->vertexStream, 0, 2*sizeof(VertexStream)); memset(&header->vertexStream, 0, 2*sizeof(VertexStream));
pipe->instanceCB(geo, header); return header;
}
static void
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
{
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
Geometry *geo = atomic->geometry;
// don't try to (re)instance native data
if(geo->flags & Geometry::NATIVE)
return;
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
if(geo->instData){
// Already have instanced data, so check if we have to reinstance
assert(header->platform == PLATFORM_D3D9);
if(header->serialNumber != geo->meshHeader->serialNum){
// Mesh changed, so reinstance everything
freeInstanceData(geo);
}
}
// no instance or complete reinstance
if(geo->instData == nil){
geo->instData = instanceMesh(rwpipe, geo);
pipe->instanceCB(geo, (InstanceDataHeader*)geo->instData, 0);
}else if(geo->lockedSinceInst)
pipe->instanceCB(geo, (InstanceDataHeader*)geo->instData, 1);
geo->lockedSinceInst = 0;
} }
static void static void
@ -401,9 +431,7 @@ render(rw::ObjPipeline *rwpipe, Atomic *atomic)
{ {
ObjPipeline *pipe = (ObjPipeline*)rwpipe; ObjPipeline *pipe = (ObjPipeline*)rwpipe;
Geometry *geo = atomic->geometry; Geometry *geo = atomic->geometry;
// TODO: allow for REINSTANCE pipe->instance(atomic);
if(geo->instData == nil)
pipe->instance(atomic);
assert(geo->instData != nil); assert(geo->instData != nil);
assert(geo->instData->platform == PLATFORM_D3D9); assert(geo->instData->platform == PLATFORM_D3D9);
if(pipe->renderCB) if(pipe->renderCB)
@ -422,81 +450,95 @@ ObjPipeline::ObjPipeline(uint32 platform)
} }
void void
defaultInstanceCB(Geometry *geo, InstanceDataHeader *header) defaultInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance)
{ {
VertexElement dcl[NUMDECLELT];
VertexStream *s = &header->vertexStream[0];
s->offset = 0;
s->managed = 1;
s->geometryFlags = 0;
s->dynamicLock = 0;
int i = 0; int i = 0;
dcl[i].stream = 0; VertexElement dcl[NUMDECLELT];
dcl[i].offset = 0; VertexStream *s = &header->vertexStream[0];
dcl[i].type = D3DDECLTYPE_FLOAT3;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_POSITION;
dcl[i].usageIndex = 0;
i++;
uint16 stride = 12;
s->geometryFlags |= 0x2;
bool isPrelit = (geo->flags & Geometry::PRELIT) != 0; bool isPrelit = (geo->flags & Geometry::PRELIT) != 0;
if(isPrelit){
dcl[i].stream = 0;
dcl[i].offset = stride;
dcl[i].type = D3DDECLTYPE_D3DCOLOR;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_COLOR;
dcl[i].usageIndex = 0;
i++;
s->geometryFlags |= 0x8;
stride += 4;
}
for(int32 n = 0; n < geo->numTexCoordSets; n++){
dcl[i].stream = 0;
dcl[i].offset = stride;
dcl[i].type = D3DDECLTYPE_FLOAT2;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_TEXCOORD;
dcl[i].usageIndex = (uint8)n;
i++;
s->geometryFlags |= 0x10 << n;
stride += 8;
}
bool hasNormals = (geo->flags & Geometry::NORMALS) != 0; bool hasNormals = (geo->flags & Geometry::NORMALS) != 0;
if(hasNormals){
dcl[i].stream = 0;
dcl[i].offset = stride;
dcl[i].type = D3DDECLTYPE_FLOAT3;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_NORMAL;
dcl[i].usageIndex = 0;
i++;
s->geometryFlags |= 0x4;
stride += 12;
}
dcl[i] = D3DDECL_END();
header->vertexStream[0].stride = stride;
header->vertexDeclaration = createVertexDeclaration((VertexElement*)dcl);
s->vertexBuffer = createVertexBuffer(header->totalNumVertex*s->stride, 0, D3DPOOL_MANAGED);
// TODO: support both vertex buffers // TODO: support both vertex buffers
uint8 *verts = lockVertices(s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
for(i = 0; dcl[i].usage != D3DDECLUSAGE_POSITION || dcl[i].usageIndex != 0; i++)
;
instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
geo->morphTargets[0].vertices,
header->totalNumVertex,
header->vertexStream[dcl[i].stream].stride);
if(isPrelit){ if(!reinstance){
// Create declarations and buffers only the first time
assert(s->vertexBuffer == nil);
s->offset = 0;
s->managed = 1;
s->geometryFlags = 0;
s->dynamicLock = 0;
dcl[i].stream = 0;
dcl[i].offset = 0;
dcl[i].type = D3DDECLTYPE_FLOAT3;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_POSITION;
dcl[i].usageIndex = 0;
i++;
uint16 stride = 12;
s->geometryFlags |= 0x2;
if(isPrelit){
dcl[i].stream = 0;
dcl[i].offset = stride;
dcl[i].type = D3DDECLTYPE_D3DCOLOR;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_COLOR;
dcl[i].usageIndex = 0;
i++;
s->geometryFlags |= 0x8;
stride += 4;
}
for(int32 n = 0; n < geo->numTexCoordSets; n++){
dcl[i].stream = 0;
dcl[i].offset = stride;
dcl[i].type = D3DDECLTYPE_FLOAT2;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_TEXCOORD;
dcl[i].usageIndex = (uint8)n;
i++;
s->geometryFlags |= 0x10 << n;
stride += 8;
}
if(hasNormals){
dcl[i].stream = 0;
dcl[i].offset = stride;
dcl[i].type = D3DDECLTYPE_FLOAT3;
dcl[i].method = D3DDECLMETHOD_DEFAULT;
dcl[i].usage = D3DDECLUSAGE_NORMAL;
dcl[i].usageIndex = 0;
i++;
s->geometryFlags |= 0x4;
stride += 12;
}
dcl[i] = D3DDECL_END();
s->stride = stride;
assert(header->vertexDeclaration == nil);
header->vertexDeclaration = createVertexDeclaration((VertexElement*)dcl);
s->vertexBuffer = createVertexBuffer(header->totalNumVertex*s->stride, 0, D3DPOOL_MANAGED);
}else
getDeclaration(header->vertexDeclaration, dcl);
uint8 *verts = lockVertices(s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
// Instance vertices
if(!reinstance || geo->lockedSinceInst&Geometry::LOCKVERTICES){
for(i = 0; dcl[i].usage != D3DDECLUSAGE_POSITION || dcl[i].usageIndex != 0; i++)
;
instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
geo->morphTargets[0].vertices,
header->totalNumVertex,
header->vertexStream[dcl[i].stream].stride);
}
// Instance prelight colors
if(isPrelit && (!reinstance || geo->lockedSinceInst&Geometry::LOCKPRELIGHT)){
for(i = 0; dcl[i].usage != D3DDECLUSAGE_COLOR || dcl[i].usageIndex != 0; i++) for(i = 0; dcl[i].usage != D3DDECLUSAGE_COLOR || dcl[i].usageIndex != 0; i++)
; ;
InstanceData *inst = header->inst; InstanceData *inst = header->inst;
@ -512,16 +554,20 @@ defaultInstanceCB(Geometry *geo, InstanceDataHeader *header)
} }
} }
// Instance tex coords
for(int32 n = 0; n < geo->numTexCoordSets; n++){ for(int32 n = 0; n < geo->numTexCoordSets; n++){
for(i = 0; dcl[i].usage != D3DDECLUSAGE_TEXCOORD || dcl[i].usageIndex != n; i++) if(!reinstance || geo->lockedSinceInst&(Geometry::LOCKTEXCOORDS<<n)){
; for(i = 0; dcl[i].usage != D3DDECLUSAGE_TEXCOORD || dcl[i].usageIndex != n; i++)
instTexCoords(vertFormatMap[dcl[i].type], verts + dcl[i].offset, ;
geo->texCoords[n], instTexCoords(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
header->totalNumVertex, geo->texCoords[n],
header->vertexStream[dcl[i].stream].stride); header->totalNumVertex,
header->vertexStream[dcl[i].stream].stride);
}
} }
if(hasNormals){ // Instance normals
if(hasNormals && (!reinstance || geo->lockedSinceInst&Geometry::LOCKNORMALS)){
for(i = 0; dcl[i].usage != D3DDECLUSAGE_NORMAL || dcl[i].usageIndex != 0; i++) for(i = 0; dcl[i].usage != D3DDECLUSAGE_NORMAL || dcl[i].usageIndex != 0; i++)
; ;
instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset, instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset,

View File

@ -67,14 +67,14 @@ void registerNativeDataPlugin(void);
class ObjPipeline : public rw::ObjPipeline class ObjPipeline : public rw::ObjPipeline
{ {
public: public:
void (*instanceCB)(Geometry *geo, InstanceDataHeader *header); void (*instanceCB)(Geometry *geo, InstanceDataHeader *header, bool32 reinstance);
void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header); void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header);
void (*renderCB)(Atomic *atomic, InstanceDataHeader *header); void (*renderCB)(Atomic *atomic, InstanceDataHeader *header);
ObjPipeline(uint32 platform); ObjPipeline(uint32 platform);
}; };
void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header); void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance);
void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header); void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header);
void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header); void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header);

View File

@ -212,7 +212,7 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
// The 0x18 byte are the resentryheader. // The 0x18 byte are the resentryheader.
// We don't have it but it's used for alignment. // We don't have it but it's used for alignment.
header->data = rwNewT(uint8, header->size + 0x18, MEMDUR_EVENT | ID_GEOMETRY); header->data = rwNewT(uint8, header->size + 0x18, MEMDUR_EVENT | ID_GEOMETRY);
header->serialNumber = 0; header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes; header->numMeshes = meshh->numMeshes;
header->primType = meshh->flags == MeshHeader::TRISTRIP ? header->primType = meshh->flags == MeshHeader::TRISTRIP ?
D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST; D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST;

View File

@ -73,6 +73,7 @@ Geometry::create(int32 numVerts, int32 numTris, uint32 flags)
geo->addMorphTargets(1); geo->addMorphTargets(1);
geo->matList.init(); geo->matList.init();
geo->lockedSinceInst = 0;
geo->meshHeader = nil; geo->meshHeader = nil;
geo->instData = nil; geo->instData = nil;
geo->refCount = 1; geo->refCount = 1;
@ -98,6 +99,24 @@ Geometry::destroy(void)
} }
} }
void
Geometry::lock(int32 lockFlags)
{
lockedSinceInst |= lockFlags;
if(lockFlags & LOCKPOLYGONS){
rwFree(this->meshHeader);
this->meshHeader = nil;
}
}
void
Geometry::unlock(void)
{
if(this->meshHeader == nil)
this->buildMeshes();
}
struct GeoStreamData struct GeoStreamData
{ {
uint32 flags; uint32 flags;

View File

@ -23,6 +23,8 @@
namespace rw { namespace rw {
static uint16 nextSerialNum = 1;
// Mesh // Mesh
// Allocate a mesh header, meshes and optionally indices. // Allocate a mesh header, meshes and optionally indices.
@ -50,7 +52,7 @@ Geometry::allocateMeshes(int32 numMeshes, uint32 numIndices, bool32 noIndices)
this->meshHeader = mh; this->meshHeader = mh;
} }
mh->numMeshes = numMeshes; mh->numMeshes = numMeshes;
mh->serialNum = 0; // TODO mh->serialNum = nextSerialNum++;
mh->totalIndices = numIndices; mh->totalIndices = numIndices;
m = mh->getMeshes(); m = mh->getMeshes();
indices = (uint16*)&m[numMeshes]; indices = (uint16*)&m[numMeshes];

View File

@ -35,7 +35,7 @@ instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
geo->instData = header; geo->instData = header;
header->platform = PLATFORM_GL3; header->platform = PLATFORM_GL3;
header->serialNumber = 0; header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes; header->numMeshes = meshh->numMeshes;
header->primType = meshh->flags == 1 ? GL_TRIANGLE_STRIP : GL_TRIANGLES; header->primType = meshh->flags == 1 ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
header->totalNumVertex = geo->numVertices; header->totalNumVertex = geo->numVertices;

View File

@ -343,7 +343,7 @@ struct MeshHeader
}; };
uint32 flags; uint32 flags;
uint16 numMeshes; uint16 numMeshes;
uint16 serialNum; // not used yet uint16 serialNum;
uint32 totalIndices; uint32 totalIndices;
uint32 pad; // needed for alignment of Meshes uint32 pad; // needed for alignment of Meshes
// after this the meshes // after this the meshes
@ -391,13 +391,13 @@ struct MaterialList
uint32 streamGetSize(void); uint32 streamGetSize(void);
}; };
// TODO: implement locking
struct Geometry struct Geometry
{ {
PLUGINBASE PLUGINBASE
enum { ID = 8 }; enum { ID = 8 };
Object object; Object object;
uint32 flags; uint32 flags;
uint16 lockedSinceInst;
int32 numTriangles; int32 numTriangles;
int32 numVertices; int32 numVertices;
int32 numMorphTargets; int32 numMorphTargets;
@ -417,6 +417,8 @@ struct Geometry
static Geometry *create(int32 numVerts, int32 numTris, uint32 flags); static Geometry *create(int32 numVerts, int32 numTris, uint32 flags);
void destroy(void); void destroy(void);
void lock(int32 lockFlags);
void unlock(void);
void addMorphTargets(int32 n); void addMorphTargets(int32 n);
void calculateBoundingSphere(void); void calculateBoundingSphere(void);
bool32 hasColoredMaterial(void); bool32 hasColoredMaterial(void);
@ -453,6 +455,26 @@ struct Geometry
NATIVEINSTANCE = 0x02000000 NATIVEINSTANCE = 0x02000000
}; };
enum LockFlags
{
LOCKPOLYGONS = 0x0001,
LOCKVERTICES = 0x0002,
LOCKNORMALS = 0x0004,
LOCKPRELIGHT = 0x0008,
LOCKTEXCOORDS = 0x0010,
LOCKTEXCOORDS1 = 0x0010,
LOCKTEXCOORDS2 = 0x0020,
LOCKTEXCOORDS3 = 0x0040,
LOCKTEXCOORDS4 = 0x0080,
LOCKTEXCOORDS5 = 0x0100,
LOCKTEXCOORDS6 = 0x0200,
LOCKTEXCOORDS7 = 0x0400,
LOCKTEXCOORDS8 = 0x0800,
LOCKTEXCOORDSALL = 0x0ff0,
LOCKALL = 0x0fff
};
}; };
void registerMeshPlugin(void); void registerMeshPlugin(void);