Added support for OpenGL 4.1 and 4.2. Shared Storage/Uniform Buffer

This commit is contained in:
korenkonder
2025-04-21 21:42:51 +03:00
parent 7f450788a8
commit 33d26a437c
8 changed files with 607 additions and 25 deletions
+268 -4
View File
@@ -412,7 +412,10 @@ void render_data::init() {
buffer_shader.Create(sizeof(obj_shader_data));
buffer_scene.Create(sizeof(obj_scene_data));
buffer_batch.Create(sizeof(obj_batch_data));
buffer_skinning.Create(sizeof(obj_skinning_data));
if (GLAD_GL_VERSION_4_3)
buffer_skinning.Create(sizeof(obj_skinning_data));
else
buffer_skinning_ubo.Create(sizeof(obj_skinning_data));
buffer_shader_data.reset();
enum_or(flags, RENDER_DATA_SHADER_UPDATE);
@@ -423,7 +426,10 @@ void render_data::init() {
}
void render_data::free() {
buffer_skinning.Destroy();
if (GLAD_GL_VERSION_4_3)
buffer_skinning.Destroy();
else
buffer_skinning_ubo.Destroy();
buffer_batch.Destroy();
buffer_scene.Destroy();
buffer_shader.Destroy();
@@ -493,8 +499,11 @@ void render_data::set(render_context* rctx) {
buffer_scene.Bind(1);
buffer_batch.Bind(2);
if (uniform_value[U_SKINNING])
buffer_skinning.Bind(0);
if (uniform_value[U_SKINNING] && !sv_shared_storage_uniform_buffer)
if (GLAD_GL_VERSION_4_3)
buffer_skinning.Bind(0);
else
buffer_skinning_ubo.Bind(6);
}
void render_data::set_shader(uint32_t index) {
@@ -504,6 +513,68 @@ void render_data::set_shader(uint32_t index) {
enum_or(flags, RENDER_DATA_SHADER_UPDATE);
}
bool render_context::shared_storage_buffer::can_fill_data(size_t size) {
return (size + align_val(offset, sv_min_storage_buffer_alignment)) <= this->size;
}
void render_context::shared_storage_buffer::create(size_t size) {
if (buffer)
return;
size = size / sv_min_storage_buffer_alignment * sv_min_storage_buffer_alignment;
buffer.Create(size);
data = force_malloc(size);
memset(data, 0, size);
offset = 0;
this->size = size;
}
void render_context::shared_storage_buffer::destroy() {
buffer.Destroy();
free_def(data);
}
size_t render_context::shared_storage_buffer::fill_data(const void* data, size_t size) {
size_t offset = align_val(this->offset, sv_min_storage_buffer_alignment);
if (offset != this->offset)
memset((void*)((size_t)this->data + this->offset), 0, offset - this->offset);
memcpy((void*)((size_t)this->data + offset), data, size);
this->offset = offset + size;
return offset;
}
bool render_context::shared_uniform_buffer::can_fill_data(size_t size) {
return (size + align_val(offset, sv_min_uniform_buffer_alignment)) <= this->size;
}
void render_context::shared_uniform_buffer::create(size_t size) {
if (buffer)
return;
size = size / sv_min_uniform_buffer_alignment * sv_min_uniform_buffer_alignment;
buffer.Create(size);
data = force_malloc(size);
memset(data, 0, size);
offset = 0;
this->size = size;
}
void render_context::shared_uniform_buffer::destroy() {
buffer.Destroy();
free_def(data);
}
size_t render_context::shared_uniform_buffer::fill_data(const void* data, size_t size) {
size_t offset = align_val(this->offset, sv_min_uniform_buffer_alignment);
if (offset != this->offset)
memset((void*)((size_t)this->data + this->offset), 0, offset - this->offset);
memcpy((void*)((size_t)this->data + offset), data, size);
this->offset = offset + size;
return offset;
}
render_context::render_context() : litproj(), chara_reflect(), chara_refract(), box_vao(), lens_ghost_vao(),
common_vao(), empty_texture_2d(), empty_texture_cube_map(), samplers(), render_samplers(), sprite_samplers(),
sprite_width(), sprite_height(), screen_x_offset(), screen_y_offset(), screen_width(), screen_height() {
@@ -689,9 +760,30 @@ sprite_width(), sprite_height(), screen_x_offset(), screen_y_offset(), screen_wi
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
max_uniform_block_size = min_def((uint32_t)sv_max_uniform_buffer_size, 64u * 1024);
if (GLAD_GL_VERSION_4_3)
max_storage_block_size = min_def((uint32_t)sv_max_storage_buffer_size, 1024u * 1024);
}
render_context::~render_context() {
if (sv_shared_storage_uniform_buffer) {
shared_uniform_buffer_entries.clear();
for (render_context::shared_uniform_buffer& i : shared_uniform_buffers)
i.destroy();
shared_uniform_buffers.clear();
if (GLAD_GL_VERSION_4_3) {
shared_storage_buffer_entries.clear();
for (render_context::shared_storage_buffer& i : shared_storage_buffers)
i.destroy();
shared_storage_buffers.clear();
}
}
glDeleteSamplers(3, sprite_samplers);
glDeleteSamplers(4, render_samplers);
glDeleteSamplers(18, samplers);
@@ -883,6 +975,44 @@ void render_context::resize(int32_t render_width, int32_t render_height,
}
}
void render_context::add_shared_storage_uniform_buffer_data(size_t index,
const void* data, size_t size, size_t buffer_size, bool storage) {
if (storage) {
render_context::shared_storage_buffer* buffer = 0;
for (render_context::shared_storage_buffer& i : shared_storage_buffers)
if (i.can_fill_data(buffer_size)) {
buffer = &i;
break;
}
if (!buffer) {
shared_storage_buffers.push_back({});
buffer = &shared_storage_buffers.back();
buffer->create(max_storage_block_size);
}
size_t offset = buffer->fill_data(data, size);
shared_storage_buffer_entries.insert({ index, { buffer->buffer, offset, buffer_size } });
}
else {
render_context::shared_uniform_buffer* buffer = 0;
for (render_context::shared_uniform_buffer& i : shared_uniform_buffers)
if (i.can_fill_data(buffer_size)) {
buffer = &i;
break;
}
if (!buffer) {
shared_uniform_buffers.push_back({});
buffer = &shared_uniform_buffers.back();
buffer->create(max_uniform_block_size);
}
size_t offset = buffer->fill_data(data, size);
shared_uniform_buffer_entries.insert({ index, { buffer->buffer, offset, buffer_size } });
}
}
void render_context::get_scene_fog_params(render_context::fog_params& value) {
render_data* data = &this->data;
value.depth_color = data->buffer_scene_data.g_fog_depth_color;
@@ -912,6 +1042,140 @@ void render_context::get_scene_light(vec4* light_env_stage_diffuse,
*light_env_chara_specular = data->buffer_scene_data.g_light_env_chara_specular;
}
bool render_context::get_shared_storage_uniform_buffer_data(size_t index,
GLuint& buffer, size_t& offset, size_t& size, bool storage) {
if (storage) {
auto elem = shared_storage_buffer_entries.find(index);
if (elem == shared_storage_buffer_entries.end())
return false;
buffer = elem->second.buffer;
offset = elem->second.offset;
size = elem->second.size;
return true;
}
else {
auto elem = shared_uniform_buffer_entries.find(index);
if (elem == shared_uniform_buffer_entries.end())
return false;
buffer = elem->second.buffer;
offset = elem->second.offset;
size = elem->second.size;
return true;
}
}
void render_context::pre_proc() {
if (sv_shared_storage_uniform_buffer) {
auto add_obj_list = [](render_context* rctx, const mdl::ObjSubMeshArgs* args) {
if (!args->mat_count || !args->mats)
return;
if (GLAD_GL_VERSION_4_3) {
if (rctx->shared_storage_buffer_entries.find((size_t)args->mats)
!= rctx->shared_storage_buffer_entries.end())
return;
}
else {
if (rctx->shared_uniform_buffer_entries.find((size_t)args->mats)
!= rctx->shared_uniform_buffer_entries.end())
return;
}
const int32_t mat_count = min_def(args->mat_count, 256);
const mat4* mats = args->mats;
vec4* g_joint_transforms = rctx->data.buffer_skinning_data.g_joint_transforms;
mat4 mat;
for (int32_t i = 0; i < mat_count; i++, mats++, g_joint_transforms += 3) {
mat4_transpose(mats, &mat);
g_joint_transforms[0] = mat.row0;
g_joint_transforms[1] = mat.row1;
g_joint_transforms[2] = mat.row2;
}
const size_t buffer_size = sizeof(vec4) * 3 * 256;
const size_t size = sizeof(vec4) * 3 * mat_count;
rctx->add_shared_storage_uniform_buffer_data((size_t)args->mats,
rctx->data.buffer_skinning_data.g_joint_transforms, size, buffer_size, !!GLAD_GL_VERSION_4_3);
};
for (int32_t type = 0; type < mdl::OBJ_TYPE_MAX; type++)
for (mdl::ObjData*& i : disp_manager->obj[type])
switch (i->kind) {
case mdl::OBJ_KIND_NORMAL:
add_obj_list(this, &i->args.sub_mesh);
break;
case mdl::OBJ_KIND_TRANSLUCENT:
for (int32_t j = 0; j < i->args.translucent.count; j++)
add_obj_list(this, i->args.translucent.sub_mesh[j]);
break;
}
for (int32_t type = 0; type < mdl::OBJ_TYPE_LOCAL_MAX; type++)
for (mdl::ObjData*& i : disp_manager->obj_local[type])
switch (i->kind) {
case mdl::OBJ_KIND_NORMAL:
add_obj_list(this, &i->args.sub_mesh);
break;
case mdl::OBJ_KIND_TRANSLUCENT:
for (int32_t j = 0; j < i->args.translucent.count; j++)
add_obj_list(this, i->args.translucent.sub_mesh[j]);
break;
}
for (int32_t type = 0; type < mdl::OBJ_TYPE_REFLECT_MAX; type++)
for (mdl::ObjData*& i : disp_manager->obj_reflect[type])
switch (i->kind) {
case mdl::OBJ_KIND_NORMAL:
add_obj_list(this, &i->args.sub_mesh);
break;
case mdl::OBJ_KIND_TRANSLUCENT:
for (int32_t j = 0; j < i->args.translucent.count; j++)
add_obj_list(this, i->args.translucent.sub_mesh[j]);
break;
}
if (GLAD_GL_VERSION_4_3)
for (render_context::shared_storage_buffer& i : shared_storage_buffers) {
if (!i.offset)
continue;
size_t align = align_val(i.offset, sv_min_storage_buffer_alignment) - i.offset;
if (align)
memset((void*)((size_t)i.data + i.offset), 0, align);
i.buffer.WriteMemory(0, i.size, i.data);
}
for (render_context::shared_uniform_buffer& i : shared_uniform_buffers) {
if (!i.offset)
continue;
size_t align = align_val(i.offset, sv_min_uniform_buffer_alignment) - i.offset;
if (align)
memset((void*)((size_t)i.data + i.offset), 0, align);
i.buffer.WriteMemory(0, i.size, i.data);
}
}
}
void render_context::post_proc() {
if (sv_shared_storage_uniform_buffer) {
if (GLAD_GL_VERSION_4_3) {
for (render_context::shared_storage_buffer& i : shared_storage_buffers)
i.offset = 0;
shared_storage_buffer_entries.clear();
}
for (render_context::shared_uniform_buffer& i : shared_uniform_buffers)
i.offset = 0;
shared_uniform_buffer_entries.clear();
}
}
void render_context::set_batch_alpha_threshold(const float_t value) {
render_data* data = &this->data;
data->buffer_batch_data.g_max_alpha.z = value;