Merge pull request #545 from tophyr/pr/improve-render-perf

Improve Renderer Performance
This commit is contained in:
Louis Gombert 2024-08-27 23:19:55 +02:00 committed by GitHub
commit 2db85ca6ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 70 additions and 26 deletions

View File

@ -108,16 +108,21 @@ struct Renderer {
shader_.setUniform1i("u_texture_enable", texture_enable_);
}
void setVertexData(size_t offset, size_t count, PosColorUV2Vertex const* vertices) {
shader_.setVertexData(offset, count, vertices);
template <typename VertexIter,
typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<VertexIter>::value_type, PosColorUV2Vertex>>>
size_t addVertexData(VertexIter begin, VertexIter end) {
return shader_.addVertexData(begin, end);
}
void setVertexData(size_t offset, size_t count, PosColorUVVertex const* vertices) {
struct PosColorUVVertex_tag {};
template <typename VertexIter,
typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<VertexIter>::value_type, PosColorUVVertex>>>
size_t addVertexData(VertexIter begin, VertexIter end, PosColorUVVertex_tag = {}) {
std::array<PosColorUV2Vertex, MAX_POINTS_IN_POLY> converted;
std::transform(vertices, vertices + count, converted.begin(), [](auto const& vtx) {
std::transform(begin, end, converted.begin(), [](auto const& vtx) {
return PosColorUV2Vertex{vtx.pos, vtx.color, vtx.uv, {}};
});
setVertexData(offset, count, converted.data());
return shader_.addVertexData(converted.cbegin(), converted.cend());
}
void setFogEnabled(bool enabled) {
@ -1281,8 +1286,6 @@ void gpu_BindTexture(int handle, int map_type, int slot) {
}
void gpu_RenderPolygon(PosColorUVVertex *vData, uint32_t nv) {
gRenderer->setVertexData(0, nv, vData);
if (gpu_state.cur_texture_quality == 0) {
// force disable textures
gRenderer->setTextureEnabled(0, false);
@ -1291,7 +1294,7 @@ void gpu_RenderPolygon(PosColorUVVertex *vData, uint32_t nv) {
gRenderer->setTextureEnabled(1, false);
// draw the data in the arrays
dglDrawArrays(GL_TRIANGLE_FAN, 0, nv);
dglDrawArrays(GL_TRIANGLE_FAN, gRenderer->addVertexData(vData, vData + nv), nv);
if (gpu_state.cur_texture_quality == 0) {
// re-enable textures
@ -1304,9 +1307,8 @@ void gpu_RenderPolygon(PosColorUVVertex *vData, uint32_t nv) {
void gpu_RenderPolygonUV2(PosColorUV2Vertex *vData, uint32_t nv) {
gRenderer->setTextureEnabled(1, true);
gRenderer->setVertexData(0, nv, vData);
dglDrawArrays(GL_TRIANGLE_FAN, 0, nv);
dglDrawArrays(GL_TRIANGLE_FAN, gRenderer->addVertexData(vData, vData + nv), nv);
OpenGL_polys_drawn++;
OpenGL_verts_processed += nv;
@ -1547,8 +1549,7 @@ void rend_SetPixel(ddgr_color color, int x, int y) {
{},
{}
};
gRenderer->setVertexData(0, 1, &vtx);
dglDrawArrays(GL_POINTS, 0, 1);
dglDrawArrays(GL_POINTS, gRenderer->addVertexData(&vtx, &vtx + 1), 1);
}
// Sets a pixel on the display
@ -1594,8 +1595,7 @@ void rend_DrawLine(int x1, int y1, int x2, int y2) {
}
};
gRenderer->setVertexData(0, vertices.size(), vertices.data());
dglDrawArrays(GL_LINES, 0, vertices.size());
dglDrawArrays(GL_LINES, gRenderer->addVertexData(vertices.begin(), vertices.end()), vertices.size());
rend_SetAlphaType(atype);
rend_SetLighting(ltype);
@ -1675,8 +1675,7 @@ void rend_DrawSpecialLine(g3Point *p0, g3Point *p1) {
{}};
});
gRenderer->setVertexData(0, vertices.size(), vertices.data());
dglDrawArrays(GL_LINES, 0, vertices.size());
dglDrawArrays(GL_LINES, gRenderer->addVertexData(vertices.begin(), vertices.end()), vertices.size());
}
// Takes a screenshot of the current frame and puts it into the handle passed

View File

@ -54,15 +54,16 @@ template <typename V>
struct VertexBuffer {
VertexBuffer(GLuint program,
std::vector<VertexAttrib<V>> attribs,
size_t vertex_count,
size_t vertexCount,
GLenum bufferType,
V const* initialData = nullptr)
: vao_{outval(dglGenVertexArrays)},
vbo_{outval(dglGenBuffers)} {
dglBindVertexArray(vao_);
dglBindBuffer(GL_ARRAY_BUFFER, vbo_);
bind();
dglBufferData(GL_ARRAY_BUFFER,
vertex_count * sizeof(PosColorUV2Vertex),
vertexCount * sizeof(V),
initialData,
bufferType);
@ -78,11 +79,16 @@ struct VertexBuffer {
}
}
void UpdateData(size_t vtx_offset, size_t vtx_count, V const* vertices) const {
dglBindBuffer(GL_ARRAY_BUFFER, vbo_);
void UpdateData(size_t vtx_offset, size_t vtx_count, V const* vertices) {
bind();
dglBufferSubData(GL_ARRAY_BUFFER, vtx_offset * sizeof(V), vtx_count * sizeof(V), vertices);
}
protected:
void bind() {
dglBindBuffer(GL_ARRAY_BUFFER, vbo_);
}
private:
static void DeleteBuffer(GLuint id) {
dglDeleteBuffers(1, &id);
@ -101,6 +107,41 @@ private:
MoveOnlyHolder<GLuint, DeleteBuffer> vbo_;
};
// https://www.khronos.org/opengl/wiki/Buffer_Object_Streaming#Buffer_update
template <typename V>
struct OrphaningVertexBuffer : VertexBuffer<V> {
OrphaningVertexBuffer(GLuint program, std::vector<VertexAttrib<V>> attribs)
: VertexBuffer<V>{program, std::move(attribs), kVertexCount, kBufferType} {}
template <typename VertexIter,
typename = std::enable_if<std::is_convertible_v<typename std::iterator_traits<VertexIter>::value_type, V>>>
size_t AddVertexData(VertexIter begin, VertexIter end) {
this->bind();
auto dist = std::distance(begin, end);
if (nextVertex_ + dist >= kVertexCount) {
dglBufferData(GL_ARRAY_BUFFER,
kVertexCount * sizeof(V),
nullptr,
kBufferType);
nextVertex_ = 0;
}
auto start = nextVertex_;
V* mapped = reinterpret_cast<V*>(dglMapBufferRange(GL_ARRAY_BUFFER, start * sizeof(V), dist * sizeof(V), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
std::copy(begin, end, mapped);
dglUnmapBuffer(GL_ARRAY_BUFFER);
nextVertex_ += dist;
return start;
}
private:
static constexpr size_t kVertexCount{1 << 16};
static constexpr GLenum kBufferType{GL_STREAM_DRAW};
size_t nextVertex_{};
};
template <GLenum kType>
struct Shader {
static_assert(kType == GL_VERTEX_SHADER || kType == GL_FRAGMENT_SHADER);
@ -141,7 +182,7 @@ private:
template <typename V>
struct ShaderProgram {
explicit ShaderProgram(std::string_view vertexSrc, std::string_view fragmentSrc, std::vector<VertexAttrib<V>> attribs)
: id_{dglCreateProgram()}, vertex_{vertexSrc}, fragment_{fragmentSrc}, vbo_{id_, std::move(attribs), MAX_POINTS_IN_POLY, GL_DYNAMIC_DRAW} {
: id_{dglCreateProgram()}, vertex_{vertexSrc}, fragment_{fragmentSrc}, vbo_{id_, std::move(attribs)} {
if (id_ == 0) {
throw std::runtime_error("error creating GL program");
}
@ -170,8 +211,10 @@ struct ShaderProgram {
dglUseProgram(0);
}
void setVertexData(size_t offset, size_t count, PosColorUV2Vertex const* vertices) {
vbo_.UpdateData(offset, count, vertices);
template <typename VertexIter,
typename = std::enable_if<std::is_convertible_v<typename std::iterator_traits<VertexIter>::value_type, V>>>
size_t addVertexData(VertexIter begin, VertexIter end) {
return vbo_.AddVertexData(begin, end);
}
void setUniformMat4f(std::string const& name, glm::mat4x4 const& matrix) {
@ -212,6 +255,6 @@ private:
MoveOnlyHolder<GLuint, DeleteProgram> id_;
Shader<GL_VERTEX_SHADER> vertex_;
Shader<GL_FRAGMENT_SHADER> fragment_;
VertexBuffer<V> vbo_;
OrphaningVertexBuffer<V> vbo_;
std::unordered_map<std::string, GLint> uniform_cache_;
};

View File

@ -165,6 +165,7 @@ DYNAEXTERN(glGetString);
DYNAEXTERN(glGetStringi);
DYNAEXTERN(glGetUniformLocation);
DYNAEXTERN(glLinkProgram);
DYNAEXTERN(glMapBufferRange);
DYNAEXTERN(glPixelStorei);
DYNAEXTERN(glPolygonOffset);
DYNAEXTERN(glReadPixels);
@ -177,6 +178,7 @@ DYNAEXTERN(glUniform1f);
DYNAEXTERN(glUniform1i);
DYNAEXTERN(glUniform4f);
DYNAEXTERN(glUniformMatrix4fv);
DYNAEXTERN(glUnmapBuffer);
DYNAEXTERN(glUseProgram);
DYNAEXTERN(glVertexAttribPointer);
DYNAEXTERN(glViewport);