From c7eefb08e7a777259330f4403ea704e3c982c4d7 Mon Sep 17 00:00:00 2001 From: korenkonder Date: Thu, 6 Nov 2025 01:30:35 +0300 Subject: [PATCH] Texture Skinning Buffer --- src/CRE/render_context.cpp | 170 ++++++++++++++++++++++++++++++++++--- src/CRE/render_context.hpp | 23 +++++ src/CRE/shader.cpp | 55 ++++++++++++ src/CRE/static_var.cpp | 2 + src/CRE/static_var.hpp | 2 + src/ReDIVA/app.cpp | 2 + 6 files changed, 240 insertions(+), 14 deletions(-) diff --git a/src/CRE/render_context.cpp b/src/CRE/render_context.cpp index 86b5edb7..962c43e4 100644 --- a/src/CRE/render_context.cpp +++ b/src/CRE/render_context.cpp @@ -475,7 +475,17 @@ void render_data::set_skinning_data(p_gl_rend_state& p_gl_rend_st, const mat4* m } } - if (sv_shared_storage_uniform_buffer) { + if (sv_texture_skinning_buffer) { + GLuint texture = 0; + vec2i offset = 0; + if (rctx_ptr->get_texture_skinning_buffer_data((size_t)mats, texture, offset)) { + vec2i_to_vec2(offset, *(vec2*)&buffer_batch_data.g_bump_depth.z); + enum_or(flags, RENDER_DATA_BATCH_UPDATE); + p_gl_rend_st.active_bind_texture_2d(21, texture); + p_gl_rend_st.bind_sampler(21, rctx_ptr->render_samplers[1]); + } + } + else if (sv_shared_storage_uniform_buffer) { GLuint buffer = 0; size_t offset = 0; size_t size = 0; @@ -570,7 +580,7 @@ void render_data::set_state(p_gl_rend_state& p_gl_rend_st) { p_gl_rend_st.bind_uniform_buffer_base(1, buffer_scene); p_gl_rend_st.bind_uniform_buffer_base(2, buffer_batch); - if (shader_flags.arr[U_SKINNING] && !sv_shared_storage_uniform_buffer) + if (shader_flags.arr[U_SKINNING] && !sv_shared_storage_uniform_buffer && !sv_texture_skinning_buffer) if (GLAD_GL_VERSION_4_3) p_gl_rend_st.bind_shader_storage_buffer_base(0, buffer_skinning); else @@ -675,7 +685,10 @@ void render_data_context::set_batch_material_parameter(const vec4* specular, con const vec4& intensity, const float_t reflect_uv_scale, const float_t refract_uv_scale) { if (specular) data.buffer_batch_data.g_material_state_specular = *specular; - data.buffer_batch_data.g_bump_depth = bump_depth; + if (sv_texture_skinning_buffer) + *(vec2*)&data.buffer_batch_data.g_bump_depth.x = *(vec2*)&bump_depth; + else + data.buffer_batch_data.g_bump_depth = bump_depth; data.buffer_batch_data.g_intensity = intensity; data.buffer_batch_data.g_reflect_uv_scale.x = reflect_uv_scale; data.buffer_batch_data.g_reflect_uv_scale.y = reflect_uv_scale; @@ -983,6 +996,59 @@ size_t render_context::shared_uniform_buffer::fill_data(const void* data, size_t return offset; } +bool render_context::texture_skinning_buffer::can_fill_data(int32_t width) { + return (x + width) <= this->width || (y + 1) < height; +} + +void render_context::texture_skinning_buffer::create(int32_t width, int32_t height) { + if (texture) + return; + + glGenTextures(1, &texture); + gl_state.bind_texture_2d(texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + static const vec4 border_color = 0.0f; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, (GLfloat*)&border_color); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, 0); + gl_state.bind_texture_2d(0); + data = force_malloc(sizeof(vec4) * width * height); + memset(data, 0, sizeof(vec4) * width * height); + x = 0; + y = 0; + this->width = width; + this->height = height; +} + +void render_context::texture_skinning_buffer::destroy() { + if (texture) { + glDeleteTextures(1, &texture); + texture = 0; + } + + free_def(data); +} + +vec2i render_context::texture_skinning_buffer::fill_data(const void* data, int32_t width) { + if (x + width > this->width) { + x = 0; + y++; + } + + int32_t x = this->x; + int32_t y = this->y; + memcpy((void*)((size_t)this->data + (sizeof(vec4) * this->width * y + + sizeof(vec4) * x)), data, sizeof(vec4) * width); + this->x = x + width; + return { x, y }; +} + 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() { @@ -1181,6 +1247,14 @@ sprite_width(), sprite_height(), screen_x_offset(), screen_y_offset(), screen_wi } render_context::~render_context() { + if (sv_texture_skinning_buffer) { + texture_skinning_buffer_entries.clear(); + + for (render_context::texture_skinning_buffer& i : texture_skinning_buffers) + i.destroy(); + texture_skinning_buffers.clear(); + } + if (sv_shared_storage_uniform_buffer) { shared_uniform_buffer_entries.clear(); @@ -1434,6 +1508,24 @@ void render_context::add_shared_storage_uniform_buffer_data(size_t index, } } +void render_context::add_texture_skinning_buffer_data(size_t index, const void* data, int32_t width) { + render_context::texture_skinning_buffer* buffer = 0; + for (render_context::texture_skinning_buffer& i : texture_skinning_buffers) + if (i.can_fill_data(width)) { + buffer = &i; + break; + } + + if (!buffer) { + texture_skinning_buffers.push_back({}); + buffer = &texture_skinning_buffers.back(); + buffer->create(1024, 128); + } + + vec2i offset = buffer->fill_data(data, width); + texture_skinning_buffer_entries.insert({ index, { buffer->texture, offset } }); +} + bool render_context::get_shared_storage_uniform_buffer_data(size_t index, GLuint& buffer, size_t& offset, size_t& size, bool storage) { if (storage) { @@ -1458,21 +1550,38 @@ bool render_context::get_shared_storage_uniform_buffer_data(size_t index, } } +bool render_context::get_texture_skinning_buffer_data(size_t index, GLuint& texture, vec2i& offset) { + auto elem = texture_skinning_buffer_entries.find(index); + if (elem == texture_skinning_buffer_entries.end()) + return false; + + texture = elem->second.texture; + offset = elem->second.offset; + return true; +} + void render_context::pre_proc() { - if (sv_shared_storage_uniform_buffer) { + if (sv_texture_skinning_buffer || 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) { - auto elem = rctx->shared_storage_buffer_entries.find((size_t)args->mats); - if (elem != rctx->shared_storage_buffer_entries.end()) + if (sv_texture_skinning_buffer) { + auto elem = rctx->texture_skinning_buffer_entries.find((size_t)args->mats); + if (elem != rctx->texture_skinning_buffer_entries.end()) return; } else { - auto elem = rctx->shared_uniform_buffer_entries.find((size_t)args->mats); - if (elem != rctx->shared_uniform_buffer_entries.end()) - return; + if (GLAD_GL_VERSION_4_3) { + auto elem = rctx->shared_storage_buffer_entries.find((size_t)args->mats); + if (elem != rctx->shared_storage_buffer_entries.end()) + return; + } + else { + auto elem = rctx->shared_uniform_buffer_entries.find((size_t)args->mats); + if (elem != rctx->shared_uniform_buffer_entries.end()) + return; + } } const int32_t mat_count = min_def(args->mat_count, 256); @@ -1488,10 +1597,15 @@ void render_context::pre_proc() { g_joint_transform[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, - g_joint_transforms, size, buffer_size, !!GLAD_GL_VERSION_4_3); + if (sv_texture_skinning_buffer) + rctx->add_texture_skinning_buffer_data((size_t)args->mats, + g_joint_transforms, 3 * mat_count); + else { + 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, + g_joint_transforms, size, buffer_size, !!GLAD_GL_VERSION_4_3); + } }; for (int32_t type = 0; type < mdl::OBJ_TYPE_MAX; type++) @@ -1552,6 +1666,25 @@ void render_context::pre_proc() { memset((void*)((size_t)i.data + i.offset), 0, align); i.buffer.WriteMemory(gl_state, 0, size, i.data); } + + for (render_context::texture_skinning_buffer& i : texture_skinning_buffers) { + if (!i.x && !i.y) + continue; + + const int32_t align_x = i.width - i.x; + if (align_x) + memset((void*)((size_t)i.data + (sizeof(vec4) * i.width * i.y + + sizeof(vec4) * i.x)), 0, sizeof(vec4) * align_x); + if (GLAD_GL_VERSION_4_5) + glTextureSubImage2D(i.texture, 0, 0, 0, i.width, i.y + 1, GL_RGBA, GL_FLOAT, i.data); + else { + gl_state.bind_texture_2d(i.texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, i.width, i.y + 1, GL_RGBA, GL_FLOAT, i.data); + } + } + + if (!GLAD_GL_VERSION_4_5) + gl_state.bind_texture_2d(0); } } @@ -1573,4 +1706,13 @@ void render_context::post_proc() { shared_uniform_buffer_entries.clear(); } + + if (sv_texture_skinning_buffer) { + for (render_context::texture_skinning_buffer& i : texture_skinning_buffers) { + i.x = 0; + i.y = 0; + } + + texture_skinning_buffer_entries.clear(); + } } diff --git a/src/CRE/render_context.hpp b/src/CRE/render_context.hpp index c1fa4a7f..1852cba4 100644 --- a/src/CRE/render_context.hpp +++ b/src/CRE/render_context.hpp @@ -530,6 +530,25 @@ struct render_context { size_t size; }; + struct texture_skinning_buffer { + void* data; + int32_t x; + int32_t y; + int32_t width; + int32_t height; + GLuint texture; + + bool can_fill_data(int32_t width); + void create(int32_t width, int32_t height); + void destroy(); + vec2i fill_data(const void* data, int32_t width); + }; + + struct texture_skinning_buffer_entry { + GLuint texture; + vec2i offset; + }; + ::camera* camera; draw_state* draw_state; mdl::DispManager* disp_manager; @@ -602,6 +621,8 @@ struct render_context { std::unordered_map shared_storage_buffer_entries; std::vector shared_uniform_buffers; std::unordered_map shared_uniform_buffer_entries; + std::vector texture_skinning_buffers; + std::unordered_map texture_skinning_buffer_entries; render_context(); ~render_context(); @@ -616,8 +637,10 @@ struct render_context { void add_shared_storage_uniform_buffer_data(size_t index, const void* data, size_t size, size_t max_size, bool storage = false); + void add_texture_skinning_buffer_data(size_t index, const void* data, int32_t width); bool get_shared_storage_uniform_buffer_data(size_t index, GLuint& buffer, size_t& offset, size_t& size, bool storage = false); + bool get_texture_skinning_buffer_data(size_t index, GLuint& texture, vec2i& offset); void post_proc(); void pre_proc(); }; diff --git a/src/CRE/shader.cpp b/src/CRE/shader.cpp index dd7f8729..faeeaf14 100644 --- a/src/CRE/shader.cpp +++ b/src/CRE/shader.cpp @@ -300,6 +300,56 @@ static char* get_uniform_location(char* data, prj::vector_pair(data_len - (apply_skinning_pos - buffer_skinning_pos) + replacement_len + 1); + memcpy(p, data, buffer_skinning_pos); + memcpy(p + buffer_skinning_pos, replacement, replacement_len); + memcpy(p + buffer_skinning_pos + replacement_len, + data + apply_skinning_pos, data_len - apply_skinning_pos); + free_def(data); + return p; +} + static void parse_define_inner(std::string& temp, bool vulkan) { if (!vulkan) { size_t off = 0; @@ -975,6 +1025,11 @@ void shader_set_data::load(farc* f, bool ignore_cache, vert_data = shader::parse_include(vert_data, f); frag_data = shader::parse_include(frag_data, f); + if (sv_texture_skinning_buffer) { + vert_data = replace_skinning_with_g_skinning(vert_data); + frag_data = replace_skinning_with_g_skinning(frag_data); + } + prj::vector_pair samplers; prj::vector_pair uniforms; if (!GLAD_GL_VERSION_4_3) { diff --git a/src/CRE/static_var.cpp b/src/CRE/static_var.cpp index 8de52fba..8830d982 100644 --- a/src/CRE/static_var.cpp +++ b/src/CRE/static_var.cpp @@ -22,6 +22,8 @@ gpu_vendor sv_gpu_vendor = GPU_VENDOR_UNKNOWN; bool sv_shared_storage_uniform_buffer = true; +bool sv_texture_skinning_buffer = false; + const vec3 sv_rgb_to_luma = { 0.2126f, 0.7152f, 0.0722f }; diff --git a/src/CRE/static_var.hpp b/src/CRE/static_var.hpp index f4f8d829..9496a959 100644 --- a/src/CRE/static_var.hpp +++ b/src/CRE/static_var.hpp @@ -125,6 +125,8 @@ extern gpu_vendor sv_gpu_vendor; extern bool sv_shared_storage_uniform_buffer; +extern bool sv_texture_skinning_buffer; + extern const vec3 sv_rgb_to_luma; extern const mat3 sv_rgb_to_ypbpr; extern const mat3 sv_ypbpr_to_rgb; diff --git a/src/ReDIVA/app.cpp b/src/ReDIVA/app.cpp index c076e0d7..c7a3fc5e 100644 --- a/src/ReDIVA/app.cpp +++ b/src/ReDIVA/app.cpp @@ -466,6 +466,8 @@ int32_t app_main(const app_init_struct& ais) { glfwTerminate(); return ret; } + + sv_texture_skinning_buffer = false; } #ifdef USE_OPENGL else {