diff --git a/res/ft_shaders.farc b/res/ft_shaders.farc index 2e74de2..b2e3abf 100644 Binary files a/res/ft_shaders.farc and b/res/ft_shaders.farc differ diff --git a/src/DivaGL/dllmain.cpp b/src/DivaGL/dllmain.cpp index 4bcb269..4fd4e5d 100644 --- a/src/DivaGL/dllmain.cpp +++ b/src/DivaGL/dllmain.cpp @@ -21,6 +21,7 @@ bool cpu_caps_aes_ni; bool cpu_caps_f16c; bool config_reflect_full = true; int32_t config_reflect_res_scale = 100; +bool config_shared_storage_uniform_buffer = false; static std::wstring GetDirPath(); @@ -57,9 +58,11 @@ bool APIENTRY DllMain(HMODULE handle, DWORD ul_reason_for_call, LPVOID lpReserve config_reflect_full = GetPrivateProfileIntW(L"general", L"reflect_full", 0, CONFIG_FILE) > 0 ? true : false; config_reflect_res_scale = GetPrivateProfileIntW(L"general", L"reflect_res_scale", 1, CONFIG_FILE); config_reflect_res_scale = config_reflect_res_scale ? clamp_def(config_reflect_res_scale, 25, 100) : 100; + config_shared_storage_uniform_buffer = GetPrivateProfileIntW(L"experimentals", + L"shared_storage_uniform_buffer", 0, CONFIG_FILE) > 0 ? true : false; dll_handle = (size_t)handle; - printf_divagl("Current version - v0.7.3.0"); + printf_divagl("Current version - v0.7.3.0 (Build date: " __DATE__ ")"); printf_divagl("Attach"); divagl_main(); break; @@ -76,7 +79,7 @@ extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { } extern "C" __declspec(dllexport) LPCWSTR GetBuildDate(void) { - return L"v0.7.3.0"; + return L"v0.7.3.0 (Build date: " __DATE__ ")"; } static std::wstring GetDirPath() { @@ -115,12 +118,24 @@ PluginConfig::PluginConfigOption config[] = { L"general", CONFIG_FILE, L"Reflect Resolution Scale", - L"Sets resolution for Full Reflect as a percentage relative to the Internal Resolution values.\nImportant note! Scale doesn't apply can't go lower than 256x144 or Internal Resolution.", + L"Sets resolution for Full Reflect as a percentage relative to the Internal Resolution values.\nImportant note! Scale can't go lower than 256x144 or Internal Resolution.", 100, 25, 100, } }, + { + PluginConfig::CONFIG_BOOLEAN, + new PluginConfig::PluginConfigBooleanData { + L"shared_storage_uniform_buffer", + L"experimentals", + CONFIG_FILE, + L"Shared Storage/Uniform Buffer", + L"May be seful for running AFT via Mesa or on Apple devices\nor when driver doesn't support OpenGL 4.3.", + false, + false, + } + }, }; extern "C" __declspec(dllexport) PluginConfig::PluginConfigArray GetPluginOptions(void) { diff --git a/src/DivaGL/hook.cpp b/src/DivaGL/hook.cpp index f9e08f9..9b98e49 100644 --- a/src/DivaGL/hook.cpp +++ b/src/DivaGL/hook.cpp @@ -165,6 +165,7 @@ HOOK(void, FASTCALL, rndr__RenderManager__rndpass_pre_proc, 0x0000000140502C90) render_manager.render->pre_proc(); Glitter::glt_particle_manager->CalcDisp(); Glitter::glt_particle_manager_x->CalcDisp(); + rctx->pre_proc(); gl_state_end_event(); } @@ -174,6 +175,7 @@ HOOK(void, FASTCALL, rndr__RenderManager__render_all, 0x0000000140502CA0) { HOOK(void, FASTCALL, rndr__RenderManager__rndpass_post_proc, 0x0000000140502C70) { gl_state_begin_event("rndpass_post_proc"); + rctx->post_proc(); render_manager.render->post_proc(); render_manager.field_31C = false; gl_state_end_event(); diff --git a/src/DivaGL/mdl/draw_object.cpp b/src/DivaGL/mdl/draw_object.cpp index 97a0809..521751d 100644 --- a/src/DivaGL/mdl/draw_object.cpp +++ b/src/DivaGL/mdl/draw_object.cpp @@ -30,6 +30,8 @@ static void draw_object_vertex_attrib_set_reflect(const mdl::ObjSubMeshArgs* arg static bool(FASTCALL* use_shader_get)() = (bool(FASTCALL*)())0x0000000140440E30; +extern bool config_shared_storage_uniform_buffer; + namespace mdl { void draw(obj_primitive_type primitive_type, uint32_t count, uint16_t start, uint16_t end, obj_index_format index_format, size_t indices) { @@ -183,21 +185,33 @@ namespace mdl { if (args->mat_count == 2) rctx->set_batch_joint(mats[0]); - vec4* g_joint_transforms = rctx->data.buffer_skinning_data.g_joint_transforms; - - mat4 mat; - for (int32_t i = 0; i < args->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; + if (config_shared_storage_uniform_buffer) { + GLuint buffer = 0; + size_t offset = 0; + size_t size = 0; + if (rctx->get_shared_storage_uniform_buffer_data((size_t)args->mats, buffer, offset, size, !!GL_VERSION_4_3)) + if (GL_VERSION_4_3) + gl_state_bind_shader_storage_buffer_range(0, buffer, (GLintptr)offset, (GLsizeiptr)size); + else + gl_state_bind_uniform_buffer_range(6, buffer, (GLintptr)offset, (GLsizeiptr)size); } + else { + vec4* g_joint_transforms = rctx->data.buffer_skinning_data.g_joint_transforms; - if (GL_VERSION_4_3) - rctx->data.buffer_skinning.WriteMemory(rctx->data.buffer_skinning_data); - else - rctx->data.buffer_skinning_ubo.WriteMemory(0, - sizeof(vec4) * 3 * args->mat_count, &rctx->data.buffer_skinning_data); + mat4 mat; + for (int32_t i = 0; i < args->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; + } + + if (GL_VERSION_4_3) + rctx->data.buffer_skinning.WriteMemory(rctx->data.buffer_skinning_data); + else + rctx->data.buffer_skinning_ubo.WriteMemory(0, + sizeof(vec4) * 3 * args->mat_count, &rctx->data.buffer_skinning_data); + } rctx->set_batch_worlds(mat4_identity); diff --git a/src/DivaGL/render_context.cpp b/src/DivaGL/render_context.cpp index 9829189..e3007a8 100644 --- a/src/DivaGL/render_context.cpp +++ b/src/DivaGL/render_context.cpp @@ -14,6 +14,8 @@ sss_data& _sss_data = *(sss_data*)0x000000014CC924E0; render_context* rctx; +extern bool config_shared_storage_uniform_buffer; + void draw_state_stats::reset() { object_draw_count = 0; object_translucent_draw_count = 0; @@ -345,7 +347,7 @@ void render_data::set(render_context* rctx) { buffer_scene.Bind(1); buffer_batch.Bind(2); - if (uniform->arr[U_SKINNING]) + if (uniform->arr[U_SKINNING] && !config_shared_storage_uniform_buffer) if (GL_VERSION_4_3) buffer_skinning.Bind(0); else @@ -359,6 +361,76 @@ void render_data::set_shader(uint32_t index) { enum_or(flags, RENDER_DATA_SHADER_UPDATE); } +bool render_context::shared_storage_buffer::can_fill_data(render_context* rctx, size_t size) { + return (size + align_val(offset, rctx->storage_buffer_offset_alignment)) <= this->size; +} + +void render_context::shared_storage_buffer::create(size_t size) { + if (buffer) + return; + + size = size / rctx->storage_buffer_offset_alignment * rctx->storage_buffer_offset_alignment; + + buffer.Create(size); + data = _operator_new(size); + memset(data, 0, size); + offset = 0; + this->size = size; +} + +void render_context::shared_storage_buffer::destroy() { + buffer.Destroy(); + + if (data) { + _operator_delete(data); + data = 0; + } +} + +size_t render_context::shared_storage_buffer::fill_data(render_context* rctx, const void* data, size_t size) { + size_t offset = align_val(this->offset, rctx->storage_buffer_offset_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(render_context* rctx, size_t size) { + return (size + align_val(offset, rctx->uniform_buffer_offset_alignment)) <= this->size; +} + +void render_context::shared_uniform_buffer::create(size_t size) { + if (buffer) + return; + + size = size / rctx->uniform_buffer_offset_alignment * rctx->uniform_buffer_offset_alignment; + + buffer.Create(size); + data = _operator_new(size); + memset(data, 0, size); + offset = 0; + this->size = size; +} + +void render_context::shared_uniform_buffer::destroy() { + buffer.Destroy(); + + if (data) { + _operator_delete(data); + data = 0; + } +} + +size_t render_context::shared_uniform_buffer::fill_data(render_context* rctx, const void* data, size_t size) { + size_t offset = align_val(this->offset, rctx->uniform_buffer_offset_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() : box_vao(), lens_ghost_vao(), common_vao(), reflect_buffer(), render_buffer(), screen_buffer(), shadow_buffer(), empty_texture_2d(), empty_texture_cube_map(), samplers(), render_samplers(), sprite_samplers(), screen_width(), screen_height() { @@ -538,9 +610,35 @@ samplers(), render_samplers(), sprite_samplers(), screen_width(), screen_height( 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); + + glGetIntegervDLL(GL_MAX_UNIFORM_BLOCK_SIZE, (GLint*)&max_uniform_block_size); + glGetIntegervDLL(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, (GLint*)&uniform_buffer_offset_alignment); + + if (GL_VERSION_4_3) { + glGetIntegervDLL(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, (GLint*)&max_storage_block_size); + glGetIntegervDLL(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, (GLint*)&storage_buffer_offset_alignment); + + max_storage_block_size = min_def(max_storage_block_size, 16u * 1024 * 1024); + } } render_context::~render_context() { + if (config_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 (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); @@ -701,6 +799,154 @@ void render_context::init() { screen_buffer.Init(screen_width, screen_height, 0, GL_RGBA8, 0); } +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(this, 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(this, 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(this, 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(this, data, size); + shared_uniform_buffer_entries.insert({ index, { buffer->buffer, offset, buffer_size } }); + } +} + +void render_context::pre_proc() { + if (config_shared_storage_uniform_buffer) { + auto add_obj_list = [](render_context* rctx, const mdl::ObjSubMeshArgs* args) { + if (!args->mat_count || !args->mats) + return; + + if (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, !!GL_VERSION_4_3); + }; + + for (int32_t type = 0; type < mdl::OBJ_TYPE_MAX; type++) + for (mdl::ObjData*& i : disp_manager->get_obj_list((mdl::ObjType)type)) + switch (i->kind) { + case mdl::OBJ_KIND_NORMAL: + add_obj_list(rctx, &i->args.sub_mesh); + break; + case mdl::OBJ_KIND_TRANSLUCENT: + for (int32_t j = 0; j < i->args.translucent.count; j++) + add_obj_list(rctx, 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->get_obj_list((mdl::ObjTypeLocal)type)) + switch (i->kind) { + case mdl::OBJ_KIND_NORMAL: + add_obj_list(rctx, &i->args.sub_mesh); + break; + case mdl::OBJ_KIND_TRANSLUCENT: + for (int32_t j = 0; j < i->args.translucent.count; j++) + add_obj_list(rctx, 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->get_obj_list((mdl::ObjTypeReflect)type)) + switch (i->kind) { + case mdl::OBJ_KIND_NORMAL: + add_obj_list(rctx, &i->args.sub_mesh); + break; + case mdl::OBJ_KIND_TRANSLUCENT: + for (int32_t j = 0; j < i->args.translucent.count; j++) + add_obj_list(rctx, i->args.translucent.sub_mesh[j]); + break; + } + + if (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, storage_buffer_offset_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, uniform_buffer_offset_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 (config_shared_storage_uniform_buffer) { + if (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::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; @@ -730,6 +976,30 @@ 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::set_batch_alpha_threshold(const float_t value) { render_data* data = &this->data; data->buffer_batch_data.g_max_alpha.z = value; diff --git a/src/DivaGL/render_context.hpp b/src/DivaGL/render_context.hpp index f125346..09b3713 100644 --- a/src/DivaGL/render_context.hpp +++ b/src/DivaGL/render_context.hpp @@ -404,6 +404,36 @@ struct render_context { float_t end; }; + struct shared_storage_buffer { + void* data; + size_t offset; + size_t size; + GL::ShaderStorageBuffer buffer; + + bool can_fill_data(render_context* rctx, size_t size); + void create(size_t size); + void destroy(); + size_t fill_data(render_context* rctx, const void* data, size_t size); + }; + + struct shared_uniform_buffer { + void* data; + size_t offset; + size_t size; + GL::UniformBuffer buffer; + + bool can_fill_data(render_context* rctx, size_t size); + void create(size_t size); + void destroy(); + size_t fill_data(render_context* rctx, const void* data, size_t size); + }; + + struct shared_buffer_entry { + GLuint buffer; + size_t offset; + size_t size; + }; + mat4 view_mat; mat4 proj_mat; mat4 vp_mat; @@ -454,6 +484,17 @@ struct render_context { mdl::ObjList obj_local[mdl::OBJ_TYPE_LOCAL_MAX]; mdl::ObjList obj_reflect[mdl::OBJ_TYPE_REFLECT_MAX]; + uint32_t max_uniform_block_size = 0; + uint32_t uniform_buffer_offset_alignment = 0; + + uint32_t max_storage_block_size = 0; + uint32_t storage_buffer_offset_alignment = 0; + + prj::vector shared_storage_buffers; + std::unordered_map shared_storage_buffer_entries; + prj::vector shared_uniform_buffers; + std::unordered_map shared_uniform_buffer_entries; + render_context(); ~render_context(); @@ -461,10 +502,16 @@ struct render_context { void free(); void init(); + void add_shared_storage_uniform_buffer_data(size_t index, + const void* data, size_t size, size_t max_size, bool storage = false); + void post_proc(); + void pre_proc(); void get_scene_fog_params(render_context::fog_params& value); void get_scene_light(vec4* light_env_stage_diffuse, vec4* light_env_stage_specular, vec4* light_chara_dir, vec4* light_chara_luce, vec4* light_env_chara_diffuse, vec4* light_env_chara_specular); + bool get_shared_storage_uniform_buffer_data(size_t index, + GLuint& buffer, size_t& offset, size_t& size, bool storage = false); void set_batch_alpha_threshold(const float_t value); void set_batch_blend_color(const vec4& blend_color); void set_batch_blend_color_offset_color(const vec4& blend_color, const vec4& offset_color); diff --git a/src/DivaGL/shader.cpp b/src/DivaGL/shader.cpp index a6232ce..035939a 100644 --- a/src/DivaGL/shader.cpp +++ b/src/DivaGL/shader.cpp @@ -565,6 +565,11 @@ void shader_set_data::load(farc* f, bool ignore_cache, if (FAILED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA, 0, 0, temp_buf))) return; + const bool apple = !!strstr((const char*)glGetStringGLUT(GL_VENDOR), "Apple"); + + if (strstr((const char*)glGetStringGLUT(GL_VERSION), "Mesa")) + ignore_cache = true; + wcscat_s(temp_buf, sizeof(temp_buf) / sizeof(wchar_t), L"\\PDAFT"); path_create_directory(temp_buf); @@ -578,8 +583,6 @@ void shader_set_data::load(farc* f, bool ignore_cache, if (!ignore_cache && path_check_file_exists(buf)) shader_cache_farc.read(buf, true, false); - const bool apple = !!strstr((const char*)glGetStringGLUT(GL_VENDOR), "Apple"); - char vert_buf[MAX_PATH]; char frag_buf[MAX_PATH]; char vert_file_buf[MAX_PATH];