Permalink
Browse files

Use Stack Memory & Same Allocation For Primitive Optimization (#1366)

* `current_primitive` of Model is now in the same allocation avoiding unnecessary memory allocation and overhead
* `currentVertexFormat` global is now stack allocated to avoid allocation overhead
* Calling `vertex_format_end` without calling begin is no longer an error
* Calling `vertex_format_begin` twice is no longer an error, but less efficient because `currentVertexFormat` will be reinitialized twice
* Calling `d3d_model_primitive_end` without calling begin is no longer an error
* Calling `d3d_model_primitive_begin` twice is no longer an error, but less efficient because `current_primitive` will be reinitialized twice
* `std::vector::emplace_back` is now used instead of `push_back` to keep the current primitive or vertex format for obvious reasons
* Removed `vertex_format_exists()` that takes no parameters because it doesn't make sense now
  • Loading branch information...
RobertBColton committed Aug 25, 2018
1 parent 21dce9b commit 5fa7fcecbd0aaf493103149407c88a13105280a5
@@ -165,7 +165,6 @@ void d3d_model_clear(int id) {
enigma::Model* model = enigma::models[id];
vertex_clear(model->vertex_buffer);
model->primitives.clear();
model->current_primitive = 0;
model->vertex_started = false;
model->vertex_colored = true;
}
@@ -214,19 +213,12 @@ void d3d_model_draw(int id, gs_scalar x, gs_scalar y, gs_scalar z, int texId) {

void d3d_model_primitive_begin(int id, int kind, int format) {
enigma::Model* model = enigma::models[id];
#ifdef DEBUG_MODE
if (model->current_primitive) {
show_error("d3d_model_primitive_begin called again without ending " \
"the previous primitive for model: " + std::to_string(id), false);
return;
}
#endif
if (!model->vertex_started) {
model->vertex_started = true;
vertex_begin(model->vertex_buffer);
}
model->vertex_colored = true;
model->current_primitive = new enigma::Primitive(
model->current_primitive = enigma::Primitive(
kind,
format,
vertex_format_exists(format),
@@ -236,32 +228,13 @@ void d3d_model_primitive_begin(int id, int kind, int format) {

void d3d_model_primitive_end(int id) {
enigma::Model* model = enigma::models[id];
#ifdef DEBUG_MODE
if (!model->current_primitive) {
show_error("d3d_model_primitive_end called for model " + std::to_string(id) + " and no current primitive exists! " \
"This can occur if you call end without actually calling begin.", false);
return;
}
#endif
// copy current primitive to the stack
enigma::Primitive primitive = *model->current_primitive;
// delete the current primitive from the heap
delete model->current_primitive;
model->current_primitive = 0;
enigma::Primitive& primitive = model->current_primitive;

// if the primitive doesn't have a valid vertex format
// and one does exist that we were guessing, then end
// that vertex format now
if (!vertex_format_exists(primitive.format)) {
// we can't do anything if we can't figure out the format
if (!vertex_format_exists()) {
#ifdef DEBUG_MODE
show_error("d3d_model_primitive_end called for primitive of model " + std::to_string(id) + " that has " \
"non-existant vertex format and one could not be determined based on vertex specification", false);
#endif
return;
}
if (!primitive.format_defined && model->use_draw_color && !model->vertex_colored) {
if (!primitive.format_defined) {
if (primitive.format_started && model->use_draw_color && !model->vertex_colored) {
vertex_format_add_color();
}
primitive.format = vertex_format_end();
@@ -319,7 +292,7 @@ void d3d_model_primitive_end(int id) {
// not mergeable with the previous primitive so looks like we have to keep it...
}

model->primitives.push_back(primitive);
model->primitives.emplace_back(primitive);
}

void d3d_model_float1(int id, float f1) {
@@ -349,21 +322,23 @@ void d3d_model_ubyte4(int id, uint8_t u1, uint8_t u2, uint8_t u3, uint8_t u4) {

void d3d_model_vertex(int id, gs_scalar x, gs_scalar y) {
enigma::Model* model = enigma::models[id];
enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined) {
if (vertex_format_exists()) {
enigma::Primitive& primitive = model->current_primitive;
if (primitive.format_started && model->use_draw_color && !model->vertex_colored) {
vertex_color(model->vertex_buffer, model->vertex_color, model->vertex_alpha);
}
if (!primitive.format_defined) {
if (primitive.format_started) {
if (model->use_draw_color && !model->vertex_colored) {
vertex_format_add_color();
}
primitive->format_defined = true;
primitive.format = vertex_format_end();
primitive.format_defined = true;
} else {
vertex_format_begin();
vertex_format_add_position();
primitive.format_started = true;
}
}
if (primitive->format_defined && model->use_draw_color && !model->vertex_colored) {
vertex_color(model->vertex_buffer, model->vertex_color, model->vertex_alpha);
}
vertex_position(model->vertex_buffer, x, y);
model->vertex_colored = false;
model->vertex_color = draw_get_color();
@@ -372,21 +347,23 @@ void d3d_model_vertex(int id, gs_scalar x, gs_scalar y) {

void d3d_model_vertex(int id, gs_scalar x, gs_scalar y, gs_scalar z) {
enigma::Model* model = enigma::models[id];
enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined) {
if (vertex_format_exists()) {
enigma::Primitive& primitive = model->current_primitive;
if (primitive.format_started && model->use_draw_color && !model->vertex_colored) {
vertex_color(model->vertex_buffer, model->vertex_color, model->vertex_alpha);
}
if (!primitive.format_defined) {
if (primitive.format_started) {
if (model->use_draw_color && !model->vertex_colored) {
vertex_format_add_color();
}
primitive->format_defined = true;
primitive.format = vertex_format_end();
primitive.format_defined = true;
} else {
vertex_format_begin();
vertex_format_add_position_3d();
primitive.format_started = true;
}
}
if (primitive->format_defined && model->use_draw_color && !model->vertex_colored) {
vertex_color(model->vertex_buffer, model->vertex_color, model->vertex_alpha);
}
vertex_position_3d(model->vertex_buffer, x, y, z);
model->vertex_colored = false;
model->vertex_color = draw_get_color();
@@ -395,74 +372,74 @@ void d3d_model_vertex(int id, gs_scalar x, gs_scalar y, gs_scalar z) {

void d3d_model_color(int id, int col, double alpha) {
enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_color();
vertex_color(model->vertex_buffer, col, alpha);
model->vertex_colored = true;
}

void d3d_model_argb(int id, unsigned argb) {
enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_color();
vertex_argb(model->vertex_buffer, argb);
model->vertex_colored = true;
}

void d3d_model_texture(int id, gs_scalar tx, gs_scalar ty) {
const enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_textcoord();
vertex_texcoord(model->vertex_buffer, tx, ty);
}

void d3d_model_normal(int id, gs_scalar nx, gs_scalar ny, gs_scalar nz) {
const enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_normal();
vertex_normal(model->vertex_buffer, nx, ny, nz);
}

void d3d_model_float1(int id, int usage, float f1) {
const enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_custom(vertex_type_float1, usage);
vertex_float1(model->vertex_buffer, f1);
}

void d3d_model_float2(int id, int usage, float f1, float f2) {
const enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_custom(vertex_type_float2, usage);
vertex_float2(model->vertex_buffer, f1, f2);
}

void d3d_model_float3(int id, int usage, float f1, float f2, float f3) {
const enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_custom(vertex_type_float3, usage);
vertex_float3(model->vertex_buffer, f1, f2, f3);
}

void d3d_model_float4(int id, int usage, float f1, float f2, float f3, float f4) {
const enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_custom(vertex_type_float4, usage);
vertex_float4(model->vertex_buffer, f1, f2, f3, f4);
}

void d3d_model_ubyte4(int id, int usage, uint8_t u1, uint8_t u2, uint8_t u3, uint8_t u4) {
const enigma::Model* model = enigma::models[id];
const enigma::Primitive* primitive = model->current_primitive;
if (!primitive->format_defined)
const enigma::Primitive& primitive = model->current_primitive;
if (!primitive.format_defined)
vertex_format_add_custom(vertex_type_ubyte4, usage);
vertex_ubyte4(model->vertex_buffer, u1, u2, u3, u4);
}
@@ -36,21 +36,23 @@ namespace enigma {
struct Primitive {
int type; // one of the enigma_user primitive type constants (e.g, pr_trianglelist)
int format; // index of the user vertex format that describes the vertex data of this primitive
bool format_started; // if the format has been started yet from specifying any vertex data
bool format_defined; // if the format has been guessed yet from how vertex data is being specified
unsigned vertex_offset; // byte offset into the vertex buffer where this primitive's data begins
unsigned vertex_count; // number of vertices this primitive is composed of

// NOTE: format may not exist until d3d_model_primitive_end is called
// NOTE: when format_defined is true the format may still not exist yet

Primitive(int type, int format, bool format_defined, unsigned offset):
type(type), format(format), format_defined(format_defined), vertex_offset(offset), vertex_count(0) {}
Primitive(): type(0), format(-1), format_started(false), format_defined(false), vertex_offset(0), vertex_count(0) {}
Primitive(int type, int format, bool format_exists, unsigned offset):
type(type), format(format), format_started(format_exists), format_defined(format_exists), vertex_offset(offset), vertex_count(0) {}
};

struct Model {
int type; // one of the enigma_user model type constants (e.g, model_static is the default)
int vertex_buffer; // index of the user vertex buffer this model uses to buffer its vertex data
Primitive* current_primitive; // pointer to the current primitive being specified by the user
Primitive current_primitive; // the current primitive being specified by the user
bool vertex_started; // whether the user has begun specifying the model by starting a primitive
vector<Primitive> primitives; // all primitives the user has finished specifying for this model

@@ -60,13 +62,14 @@ struct Model {
gs_scalar vertex_alpha; // the alpha that was set when the last vertex was added

// NOTE: vertex_buffer should always exist but not outlive the model
// NOTE: current_primitive does not exist outside of the begin/end calls
// NOTE: current_primitive is not reset until the next begin call
// NOTE: current_primitive is not a pointer (same allocation) to avoid allocation overhead
// NOTE: vertex_started is true until the user attempts to draw the model
// NOTE: vertex_colored waits until the next vertex or primitive end to add the color
// because GM has always specified color as the last argument on its vertex formats

Model(int type, bool use_draw_color):
type(type), vertex_buffer(-1), current_primitive(0), vertex_started(false), use_draw_color(use_draw_color),
type(type), vertex_buffer(-1), current_primitive(), vertex_started(false), use_draw_color(use_draw_color),
vertex_colored(true), vertex_color(enigma_user::c_white), vertex_alpha(1.0) {}
};

@@ -40,8 +40,9 @@ namespace {
std::unordered_map<size_t, int> vertexFormatCache;

// current vertex format being specified
// NOTE: this is NULl outside of vertex_format_begin and vertex_format_end
enigma::VertexFormat* currentVertexFormat = 0;
// NOTE: this is not reset until the next vertex_format_begin
// NOTE: this uses the stack until vertex_format_end to speed up creation
enigma::VertexFormat currentVertexFormat;

#define RESOURCE_EXISTS(id, container) return (id >= 0 && (unsigned)id < enigma::container.size() && enigma::container[id] != nullptr);

@@ -58,77 +59,58 @@ vector<IndexBuffer*> indexBuffers;
namespace enigma_user {

void vertex_format_begin() {
#ifdef DEBUG_MODE
if (currentVertexFormat) {
show_error("vertex_format_begin called again without ending the previous format", false);
vertex_format_end();
}
#endif
currentVertexFormat = new enigma::VertexFormat();
currentVertexFormat = enigma::VertexFormat();
}

unsigned vertex_format_get_hash() {
return currentVertexFormat->hash;
return currentVertexFormat.hash;
}

unsigned vertex_format_get_stride() {
return currentVertexFormat->stride;
return currentVertexFormat.stride;
}

unsigned vertex_format_get_stride_size() {
return currentVertexFormat->stride_size;
return currentVertexFormat.stride_size;
}

void vertex_format_add_color() {
currentVertexFormat->AddAttribute(vertex_type_color, vertex_usage_color);
currentVertexFormat.AddAttribute(vertex_type_color, vertex_usage_color);
}

void vertex_format_add_position() {
currentVertexFormat->AddAttribute(vertex_type_float2, vertex_usage_position);
currentVertexFormat.AddAttribute(vertex_type_float2, vertex_usage_position);
}

void vertex_format_add_position_3d() {
currentVertexFormat->AddAttribute(vertex_type_float3, vertex_usage_position);
currentVertexFormat.AddAttribute(vertex_type_float3, vertex_usage_position);
}

void vertex_format_add_textcoord() {
currentVertexFormat->AddAttribute(vertex_type_float2, vertex_usage_textcoord);
currentVertexFormat.AddAttribute(vertex_type_float2, vertex_usage_textcoord);
}

void vertex_format_add_normal() {
currentVertexFormat->AddAttribute(vertex_type_float3, vertex_usage_normal);
currentVertexFormat.AddAttribute(vertex_type_float3, vertex_usage_normal);
}

void vertex_format_add_custom(int type, int usage) {
currentVertexFormat->AddAttribute(type, usage);
currentVertexFormat.AddAttribute(type, usage);
}

int vertex_format_end() {
int id = -1;
#ifdef DEBUG_MODE
if (!currentVertexFormat) {
show_error("vertex_format_end called and no current vertex format exists! " \
"This can occur if you call end without actually calling begin.", false);
return id;
}
#endif
auto search = vertexFormatCache.find(currentVertexFormat->hash);
auto search = vertexFormatCache.find(currentVertexFormat.hash);
if (search != vertexFormatCache.end()) {
id = search->second;
delete currentVertexFormat;
} else {
id = enigma::vertexFormats.size();
enigma::vertexFormats.push_back(currentVertexFormat);
vertexFormatCache[currentVertexFormat->hash] = id;
enigma::vertexFormats.emplace_back(new enigma::VertexFormat(currentVertexFormat));
vertexFormatCache[currentVertexFormat.hash] = id;
}
currentVertexFormat = 0;
return id;
}

bool vertex_format_exists() {
return (currentVertexFormat != 0);
}

bool vertex_format_exists(int id) {
RESOURCE_EXISTS(id, vertexFormats);
}
@@ -53,7 +53,6 @@ enum {

void vertex_format_begin();
int vertex_format_end();
bool vertex_format_exists();
bool vertex_format_exists(int id);
unsigned vertex_format_get_hash(int id);
unsigned vertex_format_get_stride(int id);

0 comments on commit 5fa7fce

Please sign in to comment.