- make RenderCommands able to use Shape2D vertex buffers past the Shape2D's lifetime without crashing

This commit is contained in:
Gutawer 2021-07-29 18:58:29 +01:00 committed by Christoph Oelckers
parent ccf46281df
commit 67e7d1a6f5
3 changed files with 47 additions and 37 deletions

View file

@ -124,7 +124,7 @@ static void Shape2D_Clear(DShape2D* self, int which)
if (which & C_Verts) self->mVertices.Clear(); if (which & C_Verts) self->mVertices.Clear();
if (which & C_Coords) self->mCoords.Clear(); if (which & C_Coords) self->mCoords.Clear();
if (which & C_Indices) self->mIndices.Clear(); if (which & C_Indices) self->mIndices.Clear();
self->needsVertexUpload = true; self->bufferInfo->needsVertexUpload = true;
} }
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear) DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear)
@ -138,7 +138,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear)
static void Shape2D_PushVertex(DShape2D* self, double x, double y) static void Shape2D_PushVertex(DShape2D* self, double x, double y)
{ {
self->mVertices.Push(DVector2(x, y)); self->mVertices.Push(DVector2(x, y));
self->needsVertexUpload = true; self->bufferInfo->needsVertexUpload = true;
} }
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex) DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex)
@ -153,7 +153,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex)
static void Shape2D_PushCoord(DShape2D* self, double u, double v) static void Shape2D_PushCoord(DShape2D* self, double u, double v)
{ {
self->mCoords.Push(DVector2(u, v)); self->mCoords.Push(DVector2(u, v));
self->needsVertexUpload = true; self->bufferInfo->needsVertexUpload = true;
} }
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushCoord, Shape2D_PushCoord) DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushCoord, Shape2D_PushCoord)
@ -170,7 +170,7 @@ static void Shape2D_PushTriangle(DShape2D* self, int a, int b, int c)
self->mIndices.Push(a); self->mIndices.Push(a);
self->mIndices.Push(b); self->mIndices.Push(b);
self->mIndices.Push(c); self->mIndices.Push(c);
self->needsVertexUpload = true; self->bufferInfo->needsVertexUpload = true;
} }
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle) DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle)
@ -534,7 +534,7 @@ void DShape2D::OnDestroy() {
mIndices.Reset(); mIndices.Reset();
mVertices.Reset(); mVertices.Reset();
mCoords.Reset(); mCoords.Reset();
buffers.Reset(); bufferInfo.reset();
} }
//========================================================================== //==========================================================================
@ -567,11 +567,11 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
shape->lastParms = new DrawParms(parms); shape->lastParms = new DrawParms(parms);
} }
else if (shape->lastParms->vertexColorChange(parms)) { else if (shape->lastParms->vertexColorChange(parms)) {
shape->needsVertexUpload = true; shape->bufferInfo->needsVertexUpload = true;
if (!shape->uploadedOnce) { if (!shape->bufferInfo->uploadedOnce) {
shape->bufIndex = -1; shape->bufferInfo->bufIndex = -1;
shape->buffers.Clear(); shape->bufferInfo->buffers.Clear();
shape->lastCommand = -1; shape->bufferInfo->lastCommand = -1;
} }
delete shape->lastParms; delete shape->lastParms;
shape->lastParms = new DrawParms(parms); shape->lastParms = new DrawParms(parms);
@ -583,7 +583,7 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
auto osave = offset; auto osave = offset;
if (parms.nooffset) offset = { 0,0 }; if (parms.nooffset) offset = { 0,0 };
if (shape->needsVertexUpload) if (shape->bufferInfo->needsVertexUpload)
{ {
shape->minx = 16383; shape->minx = 16383;
shape->miny = 16383; shape->miny = 16383;
@ -622,15 +622,15 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
dg.transform = shape->transform; dg.transform = shape->transform;
dg.transform.Cells[0][2] += offset.X; dg.transform.Cells[0][2] += offset.X;
dg.transform.Cells[1][2] += offset.Y; dg.transform.Cells[1][2] += offset.Y;
dg.shape2D = shape; dg.shape2DBufInfo = shape->bufferInfo;
dg.shape2DIndexCount = shape->mIndices.Size(); dg.shape2DIndexCount = shape->mIndices.Size();
if (shape->needsVertexUpload) if (shape->bufferInfo->needsVertexUpload)
{ {
shape->bufIndex += 1; shape->bufferInfo->bufIndex += 1;
shape->buffers.Reserve(1); shape->bufferInfo->buffers.Reserve(1);
auto buf = &shape->buffers[shape->bufIndex]; auto buf = &shape->bufferInfo->buffers[shape->bufferInfo->bufIndex];
auto verts = TArray<TwoDVertex>(dg.mVertCount, true); auto verts = TArray<TwoDVertex>(dg.mVertCount, true);
for ( int i=0; i<dg.mVertCount; i++ ) for ( int i=0; i<dg.mVertCount; i++ )
@ -649,12 +649,12 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
} }
buf->UploadData(&verts[0], dg.mVertCount, &shape->mIndices[0], shape->mIndices.Size()); buf->UploadData(&verts[0], dg.mVertCount, &shape->mIndices[0], shape->mIndices.Size());
shape->needsVertexUpload = false; shape->bufferInfo->needsVertexUpload = false;
shape->uploadedOnce = true; shape->bufferInfo->uploadedOnce = true;
} }
dg.shape2DBufIndex = shape->bufIndex; dg.shape2DBufIndex = shape->bufferInfo->bufIndex;
shape->lastCommand += 1; shape->bufferInfo->lastCommand += 1;
dg.shape2DCommandCounter = shape->lastCommand; dg.shape2DCommandCounter = shape->bufferInfo->lastCommand;
AddCommand(&dg); AddCommand(&dg);
offset = osave; offset = osave;
} }

View file

@ -7,6 +7,7 @@
#include "textures.h" #include "textures.h"
#include "renderstyle.h" #include "renderstyle.h"
#include "dobject.h" #include "dobject.h"
#include <memory>
struct DrawParms; struct DrawParms;
struct FColormap; struct FColormap;
@ -49,6 +50,7 @@ struct F2DPolygons
}; };
class DShape2D; class DShape2D;
class DShape2DBufferInfo;
class F2DDrawer class F2DDrawer
{ {
@ -123,7 +125,7 @@ public:
bool useTransform; bool useTransform;
DMatrix3x3 transform; DMatrix3x3 transform;
DShape2D* shape2D; std::shared_ptr<DShape2DBufferInfo> shape2DBufInfo;
int shape2DBufIndex; int shape2DBufIndex;
int shape2DIndexCount; int shape2DIndexCount;
int shape2DCommandCounter; int shape2DCommandCounter;
@ -131,12 +133,13 @@ public:
RenderCommand() RenderCommand()
{ {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
shape2DBufInfo.reset();
} }
// If these fields match, two draw commands can be batched. // If these fields match, two draw commands can be batched.
bool isCompatible(const RenderCommand &other) const bool isCompatible(const RenderCommand &other) const
{ {
if (shape2D != nullptr || other.shape2D != nullptr) return false; if (shape2DBufInfo != nullptr || other.shape2DBufInfo != nullptr) return false;
return mTexture == other.mTexture && return mTexture == other.mTexture &&
mType == other.mType && mType == other.mType &&
mTranslationId == other.mTranslationId && mTranslationId == other.mTranslationId &&
@ -240,6 +243,16 @@ public:
bool mIsFirstPass = true; bool mIsFirstPass = true;
}; };
class DShape2DBufferInfo
{
public:
TArray<F2DVertexBuffer> buffers;
bool needsVertexUpload = true;
int bufIndex = -1;
int lastCommand = -1;
bool uploadedOnce = false;
};
class DShape2D : public DObject class DShape2D : public DObject
{ {
@ -247,6 +260,7 @@ class DShape2D : public DObject
public: public:
DShape2D() DShape2D()
{ {
bufferInfo = std::make_shared<DShape2DBufferInfo>();
transform.Identity(); transform.Identity();
} }
@ -261,12 +275,8 @@ public:
DMatrix3x3 transform; DMatrix3x3 transform;
TArray<F2DVertexBuffer> buffers; std::shared_ptr<DShape2DBufferInfo> bufferInfo;
bool needsVertexUpload = true;
int bufIndex = -1;
int lastCommand = -1;
bool uploadedOnce = false;
DrawParms* lastParms; DrawParms* lastParms;
void OnDestroy() override; void OnDestroy() override;

View file

@ -178,22 +178,22 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state)
state.EnableTexture(false); state.EnableTexture(false);
} }
if (cmd.shape2D != nullptr) if (cmd.shape2DBufInfo != nullptr)
{ {
state.SetVertexBuffer(&cmd.shape2D->buffers[cmd.shape2DBufIndex]); state.SetVertexBuffer(&cmd.shape2DBufInfo->buffers[cmd.shape2DBufIndex]);
state.DrawIndexed(DT_Triangles, 0, cmd.shape2DIndexCount); state.DrawIndexed(DT_Triangles, 0, cmd.shape2DIndexCount);
state.SetVertexBuffer(&vb); state.SetVertexBuffer(&vb);
if (cmd.shape2DCommandCounter == cmd.shape2D->lastCommand) if (cmd.shape2DCommandCounter == cmd.shape2DBufInfo->lastCommand)
{ {
cmd.shape2D->lastCommand = -1; cmd.shape2DBufInfo->lastCommand = -1;
if (cmd.shape2D->bufIndex > 0) if (cmd.shape2DBufInfo->bufIndex > 0)
{ {
cmd.shape2D->needsVertexUpload = true; cmd.shape2DBufInfo->needsVertexUpload = true;
cmd.shape2D->buffers.Clear(); cmd.shape2DBufInfo->buffers.Clear();
cmd.shape2D->bufIndex = -1; cmd.shape2DBufInfo->bufIndex = -1;
} }
} }
cmd.shape2D->uploadedOnce = false; cmd.shape2DBufInfo->uploadedOnce = false;
} }
else else
{ {