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;
header->platform = PLATFORM_D3D8;
header->serialNumber = 0;
header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes;
header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY);

View File

@ -97,14 +97,12 @@ getDeclaration(void *declaration, VertexElement *elements)
#endif
}
void*
destroyNativeData(void *object, int32, int32)
void
freeInstanceData(Geometry *geometry)
{
Geometry *geometry = (Geometry*)object;
if(geometry->instData == nil ||
geometry->instData->platform != PLATFORM_D3D9)
return object;
return;
InstanceDataHeader *header =
(InstanceDataHeader*)geometry->instData;
geometry->instData = nil;
@ -114,6 +112,14 @@ destroyNativeData(void *object, int32, int32)
deleteObject(header->vertexStream[1].vertexBuffer);
rwFree(header->inst);
rwFree(header);
return;
}
void*
destroyNativeData(void *object, int32, int32)
{
freeInstanceData((Geometry*)object);
return object;
}
@ -309,23 +315,18 @@ registerNativeDataPlugin(void)
getSizeNativeData);
}
static void
instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
static InstanceDataHeader*
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);
MeshHeader *meshh = geo->meshHeader;
geo->instData = header;
header->platform = PLATFORM_D3D9;
header->serialNumber = 0;
header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes;
header->primType = meshh->flags == 1 ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST;
header->useOffsets = 0;
header->vertexDeclaration = nil;
header->totalNumVertex = geo->numVertices;
header->totalNumIndex = meshh->totalIndices;
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));
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
@ -401,9 +431,7 @@ render(rw::ObjPipeline *rwpipe, Atomic *atomic)
{
ObjPipeline *pipe = (ObjPipeline*)rwpipe;
Geometry *geo = atomic->geometry;
// TODO: allow for REINSTANCE
if(geo->instData == nil)
pipe->instance(atomic);
pipe->instance(atomic);
assert(geo->instData != nil);
assert(geo->instData->platform == PLATFORM_D3D9);
if(pipe->renderCB)
@ -422,81 +450,95 @@ ObjPipeline::ObjPipeline(uint32 platform)
}
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;
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;
VertexElement dcl[NUMDECLELT];
VertexStream *s = &header->vertexStream[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;
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
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++)
;
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(i = 0; dcl[i].usage != D3DDECLUSAGE_TEXCOORD || dcl[i].usageIndex != n; i++)
;
instTexCoords(vertFormatMap[dcl[i].type], verts + dcl[i].offset,
geo->texCoords[n],
header->totalNumVertex,
header->vertexStream[dcl[i].stream].stride);
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],
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++)
;
instV3d(vertFormatMap[dcl[i].type], verts + dcl[i].offset,

View File

@ -67,14 +67,14 @@ void registerNativeDataPlugin(void);
class ObjPipeline : public rw::ObjPipeline
{
public:
void (*instanceCB)(Geometry *geo, InstanceDataHeader *header);
void (*instanceCB)(Geometry *geo, InstanceDataHeader *header, bool32 reinstance);
void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header);
void (*renderCB)(Atomic *atomic, InstanceDataHeader *header);
ObjPipeline(uint32 platform);
};
void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header);
void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance);
void defaultUninstanceCB(Geometry *geo, 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.
// We don't have it but it's used for alignment.
header->data = rwNewT(uint8, header->size + 0x18, MEMDUR_EVENT | ID_GEOMETRY);
header->serialNumber = 0;
header->serialNumber = meshh->serialNum;
header->numMeshes = meshh->numMeshes;
header->primType = meshh->flags == MeshHeader::TRISTRIP ?
D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST;

View File

@ -73,6 +73,7 @@ Geometry::create(int32 numVerts, int32 numTris, uint32 flags)
geo->addMorphTargets(1);
geo->matList.init();
geo->lockedSinceInst = 0;
geo->meshHeader = nil;
geo->instData = nil;
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
{
uint32 flags;

View File

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

View File

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

View File

@ -343,7 +343,7 @@ struct MeshHeader
};
uint32 flags;
uint16 numMeshes;
uint16 serialNum; // not used yet
uint16 serialNum;
uint32 totalIndices;
uint32 pad; // needed for alignment of Meshes
// after this the meshes
@ -391,13 +391,13 @@ struct MaterialList
uint32 streamGetSize(void);
};
// TODO: implement locking
struct Geometry
{
PLUGINBASE
enum { ID = 8 };
Object object;
uint32 flags;
uint16 lockedSinceInst;
int32 numTriangles;
int32 numVertices;
int32 numMorphTargets;
@ -417,6 +417,8 @@ struct Geometry
static Geometry *create(int32 numVerts, int32 numTris, uint32 flags);
void destroy(void);
void lock(int32 lockFlags);
void unlock(void);
void addMorphTargets(int32 n);
void calculateBoundingSphere(void);
bool32 hasColoredMaterial(void);
@ -453,6 +455,26 @@ struct Geometry
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);