Switch to buckets sorting.
This commit is contained in:
parent
3e0ea2560a
commit
39a95e24c3
@ -13,8 +13,6 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#define RK_BUCKETS_SORT
|
|
||||||
|
|
||||||
#include "../render.hpp"
|
#include "../render.hpp"
|
||||||
#include "render_opengles.hpp"
|
#include "render_opengles.hpp"
|
||||||
#include "../display/display_glx.hpp"
|
#include "../display/display_glx.hpp"
|
||||||
@ -29,8 +27,6 @@ typedef void (*rk_MultiDrawElementsIndirectFunc)(rk_uint, rk_uint, const void *,
|
|||||||
static rk_DrawElementsInstancedBaseInstanceFunc rk_DrawElementsInstancedBaseInstance = nullptr;
|
static rk_DrawElementsInstancedBaseInstanceFunc rk_DrawElementsInstancedBaseInstance = nullptr;
|
||||||
static rk_MultiDrawElementsIndirectFunc rk_MultiDrawElementsIndirect = nullptr;
|
static rk_MultiDrawElementsIndirectFunc rk_MultiDrawElementsIndirect = nullptr;
|
||||||
|
|
||||||
#ifdef RK_BUCKETS_SORT
|
|
||||||
|
|
||||||
struct rk_bucket {
|
struct rk_bucket {
|
||||||
unsigned size;
|
unsigned size;
|
||||||
unsigned count;
|
unsigned count;
|
||||||
@ -40,104 +36,6 @@ struct rk_bucket {
|
|||||||
static unsigned rk_nbuckets = 0;
|
static unsigned rk_nbuckets = 0;
|
||||||
static rk_bucket * rk_buckets = nullptr;
|
static rk_bucket * rk_buckets = nullptr;
|
||||||
|
|
||||||
static void rk_buckets_alloc(
|
|
||||||
rk_batch const & batch) {
|
|
||||||
unsigned const count = batch.vertices->nmeshes;
|
|
||||||
unsigned const size = batch.max_size / count;
|
|
||||||
if (!rk_nbuckets) {
|
|
||||||
rk_nbuckets = count;
|
|
||||||
rk_buckets = reinterpret_cast<rk_bucket *>(malloc(count * sizeof(rk_bucket)));
|
|
||||||
for (unsigned index = 0; index < count; ++index) {
|
|
||||||
rk_bucket & bucket = rk_buckets[index];
|
|
||||||
bucket.size = size;
|
|
||||||
bucket.indices = reinterpret_cast<rk_ushort *>(malloc(size * sizeof(rk_ushort)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (count <= rk_nbuckets) {
|
|
||||||
for (unsigned index = 0; index < count; ++index) {
|
|
||||||
rk_bucket & bucket = rk_buckets[index];
|
|
||||||
if (bucket.size < size) {
|
|
||||||
bucket.size = size;
|
|
||||||
bucket.indices = reinterpret_cast<rk_ushort *>(realloc(bucket.indices, size * sizeof(rk_ushort)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rk_buckets = reinterpret_cast<rk_bucket *>(realloc(rk_buckets, count * sizeof(rk_bucket)));
|
|
||||||
for (unsigned index = 0; index < rk_nbuckets; ++index) {
|
|
||||||
rk_bucket & bucket = rk_buckets[index];
|
|
||||||
if (bucket.size < size) {
|
|
||||||
bucket.size = size;
|
|
||||||
bucket.indices = reinterpret_cast<rk_ushort *>(realloc(bucket.indices, size * sizeof(rk_ushort)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (unsigned index = rk_nbuckets; index < count; ++index) {
|
|
||||||
rk_bucket & bucket = rk_buckets[index];
|
|
||||||
bucket.size = size;
|
|
||||||
bucket.indices = reinterpret_cast<rk_ushort *>(malloc(size * sizeof(rk_ushort)));
|
|
||||||
}
|
|
||||||
rk_nbuckets = count;
|
|
||||||
}
|
|
||||||
unsigned total_size = rk_nbuckets * sizeof(rk_bucket);
|
|
||||||
for (unsigned index = 0; index < rk_nbuckets; ++index) {
|
|
||||||
rk_bucket const & bucket = rk_buckets[index];
|
|
||||||
total_size += bucket.size * sizeof(rk_ushort);
|
|
||||||
}
|
|
||||||
printf("[RK] rk_buckets_alloc() -> %d KiB\n", total_size / 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool rk_buckets_sort(
|
|
||||||
rk_batch const & batch) {
|
|
||||||
bool reallocated = false;
|
|
||||||
rk_bucket const * const last_bucket = rk_buckets + batch.vertices->nmeshes;
|
|
||||||
for (rk_bucket * bucket = rk_buckets; bucket < last_bucket; ++bucket) {
|
|
||||||
bucket->count = 0;
|
|
||||||
}
|
|
||||||
rk_instance_flags const * flags = batch.flags;
|
|
||||||
rk_ushort const * mesh_index = batch.meshes;
|
|
||||||
for (unsigned index = 0; index < batch.count; ++index, ++flags, ++mesh_index) {
|
|
||||||
if ((*flags & RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) == RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) {
|
|
||||||
rk_bucket & bucket = rk_buckets[*mesh_index];
|
|
||||||
if (bucket.count == bucket.size) {
|
|
||||||
bucket.size *= 2;
|
|
||||||
bucket.indices = reinterpret_cast<rk_ushort *>(
|
|
||||||
realloc(bucket.indices, bucket.size * sizeof(rk_ushort)));
|
|
||||||
reallocated = true;
|
|
||||||
}
|
|
||||||
bucket.indices[bucket.count++] = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool modified = false;
|
|
||||||
rk_ushort * indices = batch.indices;
|
|
||||||
rk_command * command = batch.commands;
|
|
||||||
rk_mesh const * mesh = batch.vertices->meshes;
|
|
||||||
for (rk_bucket const * bucket = rk_buckets; bucket < last_bucket; ++bucket, ++mesh) {
|
|
||||||
if (bucket->count) {
|
|
||||||
command->nvertices = static_cast<GLuint>(mesh->ntriangles) * 3;
|
|
||||||
command->ninstances = bucket->count;
|
|
||||||
command->base_index = mesh->base_index;
|
|
||||||
command->base_vertex = 0;
|
|
||||||
command->base_instance = indices - batch.indices;
|
|
||||||
modified |= rk_cmp_memcpy<sizeof(rk_ushort)>(indices, bucket->indices, bucket->count * sizeof(rk_ushort));
|
|
||||||
indices += bucket->count;
|
|
||||||
++command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
batch.ninstances = indices - batch.indices;
|
|
||||||
batch.ncommands = command - batch.commands;
|
|
||||||
if (reallocated) {
|
|
||||||
unsigned total_size = rk_nbuckets * sizeof(rk_bucket);
|
|
||||||
for (unsigned index = 0; index < rk_nbuckets; ++index) {
|
|
||||||
rk_bucket const & bucket = rk_buckets[index];
|
|
||||||
total_size += bucket.size * sizeof(rk_ushort);
|
|
||||||
}
|
|
||||||
printf("[RK] rk_buckets_sort() -> %d KiB\n", total_size / 1024);
|
|
||||||
}
|
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // RK_BUCKETS_SORT
|
|
||||||
|
|
||||||
static void rk_gl_printf(char const * message) {
|
static void rk_gl_printf(char const * message) {
|
||||||
printf("[GL] %s\n", message);
|
printf("[GL] %s\n", message);
|
||||||
}
|
}
|
||||||
@ -474,6 +372,58 @@ rk_vertices_t rk_create_vertices(
|
|||||||
return reinterpret_cast<rk_vertices_t>(vertices);
|
return reinterpret_cast<rk_vertices_t>(vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rk_buckets_alloc(
|
||||||
|
rk_batch const & batch) {
|
||||||
|
unsigned const count = batch.vertices->nmeshes;
|
||||||
|
unsigned const size = batch.max_size;
|
||||||
|
bool reallocated = false;
|
||||||
|
if (!rk_nbuckets) {
|
||||||
|
rk_nbuckets = count;
|
||||||
|
rk_buckets = reinterpret_cast<rk_bucket *>(malloc(count * sizeof(rk_bucket)));
|
||||||
|
for (unsigned index = 0; index < count; ++index) {
|
||||||
|
rk_bucket & bucket = rk_buckets[index];
|
||||||
|
bucket.size = size;
|
||||||
|
bucket.indices = reinterpret_cast<rk_ushort *>(malloc(size * sizeof(rk_ushort)));
|
||||||
|
}
|
||||||
|
reallocated = true;
|
||||||
|
}
|
||||||
|
else if (count <= rk_nbuckets) {
|
||||||
|
for (unsigned index = 0; index < count; ++index) {
|
||||||
|
rk_bucket & bucket = rk_buckets[index];
|
||||||
|
if (bucket.size < size) {
|
||||||
|
bucket.size = size;
|
||||||
|
bucket.indices = reinterpret_cast<rk_ushort *>(realloc(bucket.indices, size * sizeof(rk_ushort)));
|
||||||
|
reallocated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rk_buckets = reinterpret_cast<rk_bucket *>(realloc(rk_buckets, count * sizeof(rk_bucket)));
|
||||||
|
for (unsigned index = 0; index < rk_nbuckets; ++index) {
|
||||||
|
rk_bucket & bucket = rk_buckets[index];
|
||||||
|
if (bucket.size < size) {
|
||||||
|
bucket.size = size;
|
||||||
|
bucket.indices = reinterpret_cast<rk_ushort *>(realloc(bucket.indices, size * sizeof(rk_ushort)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned index = rk_nbuckets; index < count; ++index) {
|
||||||
|
rk_bucket & bucket = rk_buckets[index];
|
||||||
|
bucket.size = size;
|
||||||
|
bucket.indices = reinterpret_cast<rk_ushort *>(malloc(size * sizeof(rk_ushort)));
|
||||||
|
}
|
||||||
|
rk_nbuckets = count;
|
||||||
|
reallocated = true;
|
||||||
|
}
|
||||||
|
if (reallocated) {
|
||||||
|
unsigned total_size = rk_nbuckets * sizeof(rk_bucket);
|
||||||
|
for (unsigned index = 0; index < rk_nbuckets; ++index) {
|
||||||
|
rk_bucket const & bucket = rk_buckets[index];
|
||||||
|
total_size += bucket.size * sizeof(rk_ushort);
|
||||||
|
}
|
||||||
|
printf("[RK] rk_buckets_alloc() -> %d KiB\n", total_size / 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void rk_pack_vec3_float(
|
static void rk_pack_vec3_float(
|
||||||
unsigned const count,
|
unsigned const count,
|
||||||
rk_ushort const * const __restrict indices,
|
rk_ushort const * const __restrict indices,
|
||||||
@ -666,7 +616,9 @@ rk_batch_t rk_create_batch(
|
|||||||
batch->flags = new rk_instance_flags[max_size];
|
batch->flags = new rk_instance_flags[max_size];
|
||||||
batch->meshes = new rk_ushort[max_size];
|
batch->meshes = new rk_ushort[max_size];
|
||||||
batch->indices = new rk_ushort[max_size];
|
batch->indices = new rk_ushort[max_size];
|
||||||
|
memset(batch->indices, 0xFF, max_size * sizeof(rk_ushort));
|
||||||
batch->commands = new rk_command[vertices->nmeshes];
|
batch->commands = new rk_command[vertices->nmeshes];
|
||||||
|
memset(batch->commands, 0, vertices->nmeshes * sizeof(rk_command));
|
||||||
if (nparams) {
|
if (nparams) {
|
||||||
batch->params = new rk_parameter[nparams];
|
batch->params = new rk_parameter[nparams];
|
||||||
} else {
|
} else {
|
||||||
@ -800,58 +752,46 @@ rk_batch_t rk_create_batch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
#ifdef RK_BUCKETS_SORT
|
|
||||||
rk_buckets_alloc(*batch);
|
rk_buckets_alloc(*batch);
|
||||||
#endif
|
|
||||||
return reinterpret_cast<rk_batch_t>(batch);
|
return reinterpret_cast<rk_batch_t>(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk_sort_batch(
|
static void rk_sort_batch(
|
||||||
rk_batch const & batch) {
|
rk_batch const & batch) {
|
||||||
#ifdef RK_BUCKETS_SORT
|
rk_bucket const * const last_bucket = rk_buckets + batch.vertices->nmeshes;
|
||||||
bool const modified = rk_buckets_sort(batch);
|
for (rk_bucket * __restrict bucket = rk_buckets; bucket < last_bucket; ++bucket) {
|
||||||
|
bucket->count = 0;
|
||||||
|
}
|
||||||
|
rk_instance_flags const * __restrict flags = batch.flags;
|
||||||
|
rk_ushort const * __restrict mesh_index = batch.meshes;
|
||||||
|
for (unsigned index = 0; index < batch.count; ++index, ++flags, ++mesh_index) {
|
||||||
|
if ((*flags & RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) == RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) {
|
||||||
|
rk_bucket & __restrict bucket = rk_buckets[*mesh_index];
|
||||||
|
bucket.indices[bucket.count++] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool modified = false;
|
||||||
|
rk_ushort * __restrict indices = batch.indices;
|
||||||
|
rk_command * __restrict command = batch.commands;
|
||||||
|
rk_mesh const * __restrict mesh = batch.vertices->meshes;
|
||||||
|
for (rk_bucket const * __restrict bucket = rk_buckets; bucket < last_bucket; ++bucket, ++mesh) {
|
||||||
|
if (bucket->count) {
|
||||||
|
command->nvertices = static_cast<GLuint>(mesh->ntriangles) * 3;
|
||||||
|
command->ninstances = bucket->count;
|
||||||
|
command->base_index = mesh->base_index;
|
||||||
|
command->base_instance = indices - batch.indices;
|
||||||
|
modified |= rk_cmp_memcpy<sizeof(rk_ushort)>(indices, bucket->indices, bucket->count * sizeof(rk_ushort));
|
||||||
|
indices += bucket->count;
|
||||||
|
++command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned const ninstances = indices - batch.indices;
|
||||||
|
modified |= (ninstances != batch.ninstances);
|
||||||
|
batch.ninstances = ninstances;
|
||||||
|
batch.ncommands = command - batch.commands;
|
||||||
if (modified && rk_MultiDrawElementsIndirect) {
|
if (modified && rk_MultiDrawElementsIndirect) {
|
||||||
glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, batch.ncommands * sizeof(rk_command), batch.commands);
|
glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, batch.ncommands * sizeof(rk_command), batch.commands);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
rk_instance_flags const * flags = batch.flags;
|
|
||||||
rk_ushort * indices = batch.indices;
|
|
||||||
for (unsigned index = 0; index < batch.count; ++index, ++flags) {
|
|
||||||
if ((*flags & RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) == RK_INSTANCE_FLAGS_SPAWNED_VISIBLE) {
|
|
||||||
*indices++ = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
batch.ninstances = indices - batch.indices;
|
|
||||||
batch.ncommands = 0;
|
|
||||||
if (batch.ninstances) {
|
|
||||||
rk_command * const last_command = batch.commands + batch.vertices->nmeshes;
|
|
||||||
rk_command * command = batch.commands;
|
|
||||||
rk_ushort * base = batch.indices;
|
|
||||||
rk_ushort * const last = batch.indices + batch.ninstances;
|
|
||||||
for (rk_ushort * first = batch.indices; first < last && command < last_command; base = first, ++command) {
|
|
||||||
unsigned const mesh_index = batch.meshes[*first++];
|
|
||||||
for ( ; first < last && mesh_index == batch.meshes[*first]; ++first) {
|
|
||||||
}
|
|
||||||
for (rk_ushort * second = first; second < last; ++second) {
|
|
||||||
unsigned const index = *second;
|
|
||||||
if (mesh_index == batch.meshes[index]) {
|
|
||||||
*second = *first;
|
|
||||||
*first++ = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rk_mesh const & mesh = batch.vertices->meshes[mesh_index];
|
|
||||||
command->nvertices = static_cast<GLuint>(mesh.ntriangles) * 3;
|
|
||||||
command->ninstances = first - base;
|
|
||||||
command->base_index = mesh.base_index;
|
|
||||||
command->base_vertex = 0;
|
|
||||||
command->base_instance = base - batch.indices;
|
|
||||||
}
|
|
||||||
batch.ncommands = command - batch.commands;
|
|
||||||
if (rk_MultiDrawElementsIndirect && batch.ncommands) {
|
|
||||||
glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, batch.ncommands * sizeof(rk_command), batch.commands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // RK_BUCKETS_SORT
|
|
||||||
batch.state = RK_BATCH_STATE_SORTED;
|
batch.state = RK_BATCH_STATE_SORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user