diff --git a/game/graphics/opengl_renderer/BucketRenderer.h b/game/graphics/opengl_renderer/BucketRenderer.h index 3493c42f92..77d9aea1f6 100644 --- a/game/graphics/opengl_renderer/BucketRenderer.h +++ b/game/graphics/opengl_renderer/BucketRenderer.h @@ -42,6 +42,7 @@ struct SharedRenderState { bool use_generic2 = true; math::Vector fog_color; float fog_intensity = 1.f; + bool no_multidraw = false; void reset(); bool has_camera_planes = false; diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 340201051f..e73ee673cd 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -366,6 +366,7 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) { void OpenGLRenderer::draw_renderer_selection_window() { ImGui::Begin("Renderer Debug"); + ImGui::Checkbox("Use old single-draw", &m_render_state.no_multidraw); ImGui::SliderFloat("Fog Adjust", &m_render_state.fog_intensity, 0, 10); ImGui::Checkbox("Sky CPU", &m_render_state.use_sky_cpu); ImGui::Checkbox("Occlusion Cull", &m_render_state.use_occlusion_culling); diff --git a/game/graphics/opengl_renderer/background/Shrub.cpp b/game/graphics/opengl_renderer/background/Shrub.cpp index f1eee8a0b2..38f5d06d40 100644 --- a/game/graphics/opengl_renderer/background/Shrub.cpp +++ b/game/graphics/opengl_renderer/background/Shrub.cpp @@ -70,6 +70,7 @@ void Shrub::update_load(const Loader::LevelData* loader_data) { size_t max_draws = 0; size_t time_of_day_count = 0; size_t max_num_grps = 0; + size_t max_inds = 0; for (u32 l_tree = 0; l_tree < lev_data->shrub_trees.size(); l_tree++) { size_t num_grps = 0; @@ -84,6 +85,7 @@ void Shrub::update_load(const Loader::LevelData* loader_data) { max_num_grps = std::max(max_num_grps, num_grps); time_of_day_count = std::max(tree.time_of_day_colors.size(), time_of_day_count); + max_inds = std::max(tree.indices.size(), max_inds); u32 verts = tree.unpacked.vertices.size(); glGenVertexArrays(1, &m_trees[l_tree].vao); glBindVertexArray(m_trees[l_tree].vao); @@ -91,6 +93,7 @@ void Shrub::update_load(const Loader::LevelData* loader_data) { m_trees[l_tree].vert_count = verts; m_trees[l_tree].draws = &tree.static_draws; m_trees[l_tree].colors = &tree.time_of_day_colors; + m_trees[l_tree].index_data = tree.indices.data(); m_trees[l_tree].tod_cache = swizzle_time_of_day(tree.time_of_day_colors); glBindBuffer(GL_ARRAY_BUFFER, m_trees[l_tree].vertex_buffer); glEnableVertexAttribArray(0); @@ -129,6 +132,7 @@ void Shrub::update_load(const Loader::LevelData* loader_data) { (void*)offsetof(tfrag3::ShrubGpuVertex, color_index) // offset (0) ); + glGenBuffers(1, &m_trees[l_tree].single_draw_index_buffer); glGenBuffers(1, &m_trees[l_tree].index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_trees[l_tree].index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, tree.indices.size() * sizeof(u32), tree.indices.data(), @@ -148,6 +152,8 @@ void Shrub::update_load(const Loader::LevelData* loader_data) { m_cache.multidraw_offset_per_stripdraw.resize(max_draws); m_cache.multidraw_count_buffer.resize(max_num_grps); m_cache.multidraw_index_offset_buffer.resize(max_num_grps); + m_cache.draw_idx_temp.resize(max_draws); + m_cache.index_temp.resize(max_inds); ASSERT(time_of_day_count <= TIME_OF_DAY_COLOR_COUNT); } @@ -185,6 +191,7 @@ void Shrub::discard_tree_cache() { glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture); glDeleteTextures(1, &tree.time_of_day_texture); glDeleteBuffers(1, &tree.index_buffer); + glDeleteBuffers(1, &tree.single_draw_index_buffer); glDeleteVertexArrays(1, &tree.vao); } @@ -206,7 +213,6 @@ void Shrub::render_tree(int idx, Timer tree_timer; auto& tree = m_trees.at(idx); tree.perf.draws = 0; - tree.perf.verts = 0; tree.perf.wind_draws = 0; if (!m_has_level) { return; @@ -230,7 +236,8 @@ void Shrub::render_tree(int idx, glBindVertexArray(tree.vao); glBindBuffer(GL_ARRAY_BUFFER, tree.vertex_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tree.index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, + render_state->no_multidraw ? tree.single_draw_index_buffer : tree.index_buffer); glActiveTexture(GL_TEXTURE0); glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(UINT32_MAX); @@ -240,9 +247,16 @@ void Shrub::render_tree(int idx, tree.perf.cull_time.add(0); Timer index_timer; - make_all_visible_multidraws(m_cache.multidraw_offset_per_stripdraw.data(), - m_cache.multidraw_count_buffer.data(), - m_cache.multidraw_index_offset_buffer.data(), *tree.draws); + if (render_state->no_multidraw) { + u32 idx_buffer_size = make_all_visible_index_list( + m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, tree.index_data); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size * sizeof(u32), m_cache.index_temp.data(), + GL_STREAM_DRAW); + } else { + make_all_visible_multidraws(m_cache.multidraw_offset_per_stripdraw.data(), + m_cache.multidraw_count_buffer.data(), + m_cache.multidraw_index_offset_buffer.data(), *tree.draws); + } tree.perf.index_time.add(index_timer.getSeconds()); @@ -250,10 +264,17 @@ void Shrub::render_tree(int idx, for (size_t draw_idx = 0; draw_idx < tree.draws->size(); draw_idx++) { const auto& draw = tree.draws->operator[](draw_idx); - const auto& indices = m_cache.multidraw_offset_per_stripdraw[draw_idx]; + const auto& multidraw_indices = m_cache.multidraw_offset_per_stripdraw[draw_idx]; + const auto& singledraw_indices = m_cache.draw_idx_temp[draw_idx]; - if (indices.second == 0) { - continue; + if (render_state->no_multidraw) { + if (singledraw_indices.second == 0) { + continue; + } + } else { + if (multidraw_indices.second == 0) { + continue; + } } if ((int)draw.tree_tex_id != last_texture) { @@ -262,34 +283,42 @@ void Shrub::render_tree(int idx, } auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::SHRUB); - int draw_size = indices.second - indices.first; prof.add_draw_call(); prof.add_tri(draw.num_triangles); tree.perf.draws++; - tree.perf.verts += draw_size; - glMultiDrawElements(GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[indices.first], - GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[indices.first], - indices.second); + if (render_state->no_multidraw) { + glDrawElements(GL_TRIANGLE_STRIP, singledraw_indices.second, GL_UNSIGNED_INT, + (void*)(singledraw_indices.first * sizeof(u32))); + } else { + glMultiDrawElements(GL_TRIANGLE_STRIP, + &m_cache.multidraw_count_buffer[multidraw_indices.first], GL_UNSIGNED_INT, + &m_cache.multidraw_index_offset_buffer[multidraw_indices.first], + multidraw_indices.second); + } switch (double_draw.kind) { case DoubleDrawKind::NONE: break; case DoubleDrawKind::AFAIL_NO_DEPTH_WRITE: tree.perf.draws++; - tree.perf.verts += draw_size; prof.add_draw_call(); - prof.add_tri(draw_size); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SHRUB].id(), "alpha_min"), -10.f); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SHRUB].id(), "alpha_max"), double_draw.aref_second); glDepthMask(GL_FALSE); - glMultiDrawElements(GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[indices.first], - GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[indices.first], - indices.second); + if (render_state->no_multidraw) { + glDrawElements(GL_TRIANGLE_STRIP, singledraw_indices.second, GL_UNSIGNED_INT, + (void*)(singledraw_indices.first * sizeof(u32))); + } else { + glMultiDrawElements( + GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[multidraw_indices.first], + GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[multidraw_indices.first], + multidraw_indices.second); + } break; default: ASSERT(false); diff --git a/game/graphics/opengl_renderer/background/Shrub.h b/game/graphics/opengl_renderer/background/Shrub.h index d330fbb76b..5da8fc17df 100644 --- a/game/graphics/opengl_renderer/background/Shrub.h +++ b/game/graphics/opengl_renderer/background/Shrub.h @@ -30,16 +30,17 @@ class Shrub : public BucketRenderer { struct Tree { GLuint vertex_buffer; GLuint index_buffer; + GLuint single_draw_index_buffer; GLuint time_of_day_texture; GLuint vao; u32 vert_count; const std::vector* draws = nullptr; const std::vector* instance_info = nullptr; const std::vector* colors = nullptr; + const u32* index_data = nullptr; SwizzledTimeOfDay tod_cache; struct { - u32 verts = 0; u32 draws = 0; u32 wind_draws = 0; Filtered cull_time; @@ -62,6 +63,8 @@ class Shrub : public BucketRenderer { bool m_has_level = false; struct Cache { + std::vector> draw_idx_temp; + std::vector index_temp; std::vector> multidraw_offset_per_stripdraw; std::vector multidraw_count_buffer; std::vector multidraw_index_offset_buffer; diff --git a/game/graphics/opengl_renderer/background/Tfrag3.cpp b/game/graphics/opengl_renderer/background/Tfrag3.cpp index 6835fef3df..01906e2156 100644 --- a/game/graphics/opengl_renderer/background/Tfrag3.cpp +++ b/game/graphics/opengl_renderer/background/Tfrag3.cpp @@ -50,6 +50,7 @@ void Tfrag3::update_load(const std::vector& tree_kind size_t vis_temp_len = 0; size_t max_draws = 0; size_t max_num_grps = 0; + size_t max_inds = 0; for (int geom = 0; geom < GEOM_MAX; ++geom) { for (size_t tree_idx = 0; tree_idx < lev_data->tfrag_trees[geom].size(); tree_idx++) { @@ -65,7 +66,7 @@ void Tfrag3::update_load(const std::vector& tree_kind num_grps += draw.vis_groups.size(); } max_num_grps = std::max(max_num_grps, num_grps); - + max_inds = std::max(tree.unpacked.indices.size(), max_inds); time_of_day_count = std::max(tree.colors.size(), time_of_day_count); u32 verts = tree.packed_vertices.vertices.size(); glGenVertexArrays(1, &tree_cache.vao); @@ -76,6 +77,7 @@ void Tfrag3::update_load(const std::vector& tree_kind tree_cache.draws = &tree.draws; // todo - should we just copy this? tree_cache.colors = &tree.colors; tree_cache.vis = &tree.bvh; + tree_cache.index_data = tree.unpacked.indices.data(); tree_cache.tod_cache = swizzle_time_of_day(tree.colors); vis_temp_len = std::max(vis_temp_len, tree.bvh.vis_nodes.size()); glBindBuffer(GL_ARRAY_BUFFER, tree_cache.vertex_buffer); @@ -108,7 +110,7 @@ void Tfrag3::update_load(const std::vector& tree_kind sizeof(tfrag3::PreloadedVertex), // stride (void*)offsetof(tfrag3::PreloadedVertex, color_index) // offset (0) ); - + glGenBuffers(1, &tree_cache.single_draw_index_buffer); glGenBuffers(1, &tree_cache.index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tree_cache.index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, tree.unpacked.indices.size() * sizeof(u32), @@ -129,7 +131,8 @@ void Tfrag3::update_load(const std::vector& tree_kind m_cache.multidraw_offset_per_stripdraw.resize(max_draws); m_cache.multidraw_count_buffer.resize(max_num_grps); m_cache.multidraw_index_offset_buffer.resize(max_num_grps); - + m_cache.draw_idx_temp.resize(max_draws); + m_cache.index_temp.resize(max_inds); ASSERT(time_of_day_count <= TIME_OF_DAY_COLOR_COUNT); } @@ -191,7 +194,8 @@ void Tfrag3::render_tree(int geom, glBindVertexArray(tree.vao); glBindBuffer(GL_ARRAY_BUFFER, tree.vertex_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tree.index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, + render_state->no_multidraw ? tree.single_draw_index_buffer : tree.index_buffer); glActiveTexture(GL_TEXTURE0); glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(UINT32_MAX); @@ -199,18 +203,34 @@ void Tfrag3::render_tree(int geom, cull_check_all_slow(settings.planes, tree.vis->vis_nodes, settings.occlusion_culling, m_cache.vis_temp.data()); - u32 total_tris = make_multidraws_from_vis_string( - m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), - m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp); + u32 total_tris; + if (render_state->no_multidraw) { + u32 idx_buffer_size = make_index_list_from_vis_string( + m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp, + tree.index_data, &total_tris); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size * sizeof(u32), m_cache.index_temp.data(), + GL_STREAM_DRAW); + } else { + total_tris = make_multidraws_from_vis_string( + m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), + m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp); + } prof.add_tri(total_tris); for (size_t draw_idx = 0; draw_idx < tree.draws->size(); draw_idx++) { const auto& draw = tree.draws->operator[](draw_idx); - const auto& indices = m_cache.multidraw_offset_per_stripdraw[draw_idx]; + const auto& multidraw_indices = m_cache.multidraw_offset_per_stripdraw[draw_idx]; + const auto& singledraw_indices = m_cache.draw_idx_temp[draw_idx]; - if (indices.second == 0) { - continue; + if (render_state->no_multidraw) { + if (singledraw_indices.second == 0) { + continue; + } + } else { + if (multidraw_indices.second == 0) { + continue; + } } ASSERT(m_textures); @@ -218,31 +238,37 @@ void Tfrag3::render_tree(int geom, auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3); tree.tris_this_frame += draw.num_triangles; tree.draws_this_frame++; - int draw_size = 0; - for (int i = 0; i < indices.second; i++) { - draw_size += m_cache.multidraw_count_buffer[indices.first + i]; - } prof.add_draw_call(); - - glMultiDrawElements(GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[indices.first], - GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[indices.first], - indices.second); + if (render_state->no_multidraw) { + glDrawElements(GL_TRIANGLE_STRIP, singledraw_indices.second, GL_UNSIGNED_INT, + (void*)(singledraw_indices.first * sizeof(u32))); + } else { + glMultiDrawElements(GL_TRIANGLE_STRIP, + &m_cache.multidraw_count_buffer[multidraw_indices.first], GL_UNSIGNED_INT, + &m_cache.multidraw_index_offset_buffer[multidraw_indices.first], + multidraw_indices.second); + } switch (double_draw.kind) { case DoubleDrawKind::NONE: break; case DoubleDrawKind::AFAIL_NO_DEPTH_WRITE: prof.add_draw_call(); - prof.add_tri(draw_size); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "alpha_min"), -10.f); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "alpha_max"), double_draw.aref_second); glDepthMask(GL_FALSE); - glMultiDrawElements(GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[indices.first], - GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[indices.first], - indices.second); + if (render_state->no_multidraw) { + glDrawElements(GL_TRIANGLE_STRIP, singledraw_indices.second, GL_UNSIGNED_INT, + (void*)(singledraw_indices.first * sizeof(u32))); + } else { + glMultiDrawElements( + GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[multidraw_indices.first], + GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[multidraw_indices.first], + multidraw_indices.second); + } break; default: ASSERT(false); @@ -344,7 +370,7 @@ void Tfrag3::discard_tree_cache() { if (tree.kind != tfrag3::TFragmentTreeKind::INVALID) { glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture); glDeleteTextures(1, &tree.time_of_day_texture); - // glDeleteBuffers(1, &tree.vertex_buffer); + glDeleteBuffers(1, &tree.single_draw_index_buffer); glDeleteBuffers(1, &tree.index_buffer); glDeleteVertexArrays(1, &tree.vao); } diff --git a/game/graphics/opengl_renderer/background/Tfrag3.h b/game/graphics/opengl_renderer/background/Tfrag3.h index e79aad3301..c259342f8f 100644 --- a/game/graphics/opengl_renderer/background/Tfrag3.h +++ b/game/graphics/opengl_renderer/background/Tfrag3.h @@ -60,12 +60,14 @@ class Tfrag3 { tfrag3::TFragmentTreeKind kind; GLuint vertex_buffer = -1; GLuint index_buffer = -1; - GLuint time_of_day_texture; - GLuint vao; + GLuint single_draw_index_buffer = -1; + GLuint time_of_day_texture = -1; + GLuint vao = -1; u32 vert_count = 0; const std::vector* draws = nullptr; const std::vector* colors = nullptr; const tfrag3::BVH* vis = nullptr; + const u32* index_data = nullptr; SwizzledTimeOfDay tod_cache; void reset_stats() { @@ -83,6 +85,8 @@ class Tfrag3 { struct Cache { std::vector vis_temp; + std::vector> draw_idx_temp; + std::vector index_temp; std::vector> multidraw_offset_per_stripdraw; std::vector multidraw_count_buffer; std::vector multidraw_index_offset_buffer; diff --git a/game/graphics/opengl_renderer/background/Tie3.cpp b/game/graphics/opengl_renderer/background/Tie3.cpp index 868bd2f141..5590bf6577 100644 --- a/game/graphics/opengl_renderer/background/Tie3.cpp +++ b/game/graphics/opengl_renderer/background/Tie3.cpp @@ -28,6 +28,7 @@ void Tie3::update_load(const Loader::LevelData* loader_data) { size_t max_num_grps = 0; u16 max_wind_idx = 0; size_t time_of_day_count = 0; + size_t max_inds = 0; for (u32 l_geo = 0; l_geo < tfrag3::TIE_GEOS; l_geo++) { for (u32 l_tree = 0; l_tree < lev_data->tie_trees[l_geo].size(); l_tree++) { size_t wind_idx_buffer_len = 0; @@ -45,6 +46,7 @@ void Tie3::update_load(const Loader::LevelData* loader_data) { max_wind_idx = std::max(max_wind_idx, inst.wind_idx); } time_of_day_count = std::max(tree.colors.size(), time_of_day_count); + max_inds = std::max(tree.unpacked.indices.size(), max_inds); u32 verts = tree.packed_vertices.color_indices.size(); auto& lod_tree = m_trees.at(l_geo); glGenVertexArrays(1, &lod_tree[l_tree].vao); @@ -54,6 +56,7 @@ void Tie3::update_load(const Loader::LevelData* loader_data) { lod_tree[l_tree].draws = &tree.static_draws; lod_tree[l_tree].colors = &tree.colors; lod_tree[l_tree].vis = &tree.bvh; + lod_tree[l_tree].index_data = tree.unpacked.indices.data(); lod_tree[l_tree].instance_info = &tree.wind_instance_info; lod_tree[l_tree].wind_draws = &tree.instanced_wind_draws; vis_temp_len = std::max(vis_temp_len, tree.bvh.vis_nodes.size()); @@ -86,6 +89,7 @@ void Tie3::update_load(const Loader::LevelData* loader_data) { (void*)offsetof(tfrag3::PreloadedVertex, color_index) // offset (0) ); + glGenBuffers(1, &lod_tree[l_tree].single_draw_index_buffer); glGenBuffers(1, &lod_tree[l_tree].index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lod_tree[l_tree].index_buffer); // todo: move to loader, this will probably be quite slow. @@ -121,6 +125,8 @@ void Tie3::update_load(const Loader::LevelData* loader_data) { m_cache.multidraw_count_buffer.resize(max_num_grps); m_cache.multidraw_index_offset_buffer.resize(max_num_grps); m_wind_vectors.resize(4 * max_wind_idx + 4); // 4x u32's per wind. + m_cache.draw_idx_temp.resize(max_draws); + m_cache.index_temp.resize(max_inds); ASSERT(time_of_day_count <= TIME_OF_DAY_COLOR_COUNT); } @@ -273,6 +279,7 @@ void Tie3::discard_tree_cache() { glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture); glDeleteTextures(1, &tree.time_of_day_texture); glDeleteBuffers(1, &tree.index_buffer); + glDeleteBuffers(1, &tree.single_draw_index_buffer); glDeleteVertexArrays(1, &tree.vao); } @@ -465,7 +472,6 @@ void Tie3::render_tree_wind(int idx, tree.perf.draws++; tree.perf.wind_draws++; - tree.perf.verts += grp.num; glDrawElements(GL_TRIANGLE_STRIP, grp.num, GL_UNSIGNED_INT, (void*)((off + tree.wind_vertex_index_offsets.at(draw_idx)) * sizeof(u32))); @@ -477,7 +483,6 @@ void Tie3::render_tree_wind(int idx, case DoubleDrawKind::AFAIL_NO_DEPTH_WRITE: tree.perf.draws++; tree.perf.wind_draws++; - tree.perf.verts += grp.num; prof.add_draw_call(); prof.add_tri(grp.num); glUniform1f( @@ -502,15 +507,18 @@ void Tie3::render_tree(int idx, const TfragRenderSettings& settings, SharedRenderState* render_state, ScopedProfilerNode& prof) { + // reset perf Timer tree_timer; auto& tree = m_trees.at(geom).at(idx); tree.perf.draws = 0; - tree.perf.verts = 0; tree.perf.wind_draws = 0; + + // don't render if we haven't loaded if (!m_has_level) { return; } + // update time of day if (m_color_result.size() < tree.colors->size()) { m_color_result.resize(tree.colors->size()); } @@ -529,11 +537,13 @@ void Tie3::render_tree(int idx, glTexSubImage1D(GL_TEXTURE_1D, 0, 0, tree.colors->size(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, m_color_result.data()); + // setup OpenGL shader first_tfrag_draw_setup(settings, render_state, ShaderId::TFRAG3); glBindVertexArray(tree.vao); glBindBuffer(GL_ARRAY_BUFFER, tree.vertex_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tree.index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, + render_state->no_multidraw ? tree.single_draw_index_buffer : tree.index_buffer); glActiveTexture(GL_TEXTURE0); glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(UINT32_MAX); @@ -541,25 +551,49 @@ void Tie3::render_tree(int idx, int last_texture = -1; - u32 num_tris; - if (m_debug_all_visible) { - tree.perf.cull_time.add(0); - Timer index_timer; - num_tris = make_all_visible_multidraws( - m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), - m_cache.multidraw_index_offset_buffer.data(), *tree.draws); - tree.perf.index_time.add(index_timer.getSeconds()); - } else { + if (!m_debug_all_visible) { + // need culling data Timer cull_timer; cull_check_all_slow(settings.planes, tree.vis->vis_nodes, settings.occlusion_culling, m_cache.vis_temp.data()); tree.perf.cull_time.add(cull_timer.getSeconds()); + } else { + // no culling. + tree.perf.cull_time.add(0); + } + u32 num_tris; + if (render_state->no_multidraw) { Timer index_timer; - num_tris = make_multidraws_from_vis_string( - m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), - m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp); + u32 idx_buffer_size; + if (m_debug_all_visible) { + idx_buffer_size = + make_all_visible_index_list(m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), + *tree.draws, tree.index_data, &num_tris); + } else { + idx_buffer_size = make_index_list_from_vis_string( + m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp, + tree.index_data, &num_tris); + } + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size * sizeof(u32), m_cache.index_temp.data(), + GL_STREAM_DRAW); tree.perf.index_time.add(index_timer.getSeconds()); + + } else { + if (m_debug_all_visible) { + Timer index_timer; + num_tris = make_all_visible_multidraws( + m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), + m_cache.multidraw_index_offset_buffer.data(), *tree.draws); + tree.perf.index_time.add(index_timer.getSeconds()); + } else { + Timer index_timer; + num_tris = make_multidraws_from_vis_string( + m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), + m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp); + tree.perf.index_time.add(index_timer.getSeconds()); + } } Timer draw_timer; @@ -567,10 +601,17 @@ void Tie3::render_tree(int idx, for (size_t draw_idx = 0; draw_idx < tree.draws->size(); draw_idx++) { const auto& draw = tree.draws->operator[](draw_idx); - const auto& indices = m_cache.multidraw_offset_per_stripdraw[draw_idx]; + const auto& multidraw_indices = m_cache.multidraw_offset_per_stripdraw[draw_idx]; + const auto& singledraw_indices = m_cache.draw_idx_temp[draw_idx]; - if (indices.second == 0) { - continue; + if (render_state->no_multidraw) { + if (singledraw_indices.second == 0) { + continue; + } + } else { + if (multidraw_indices.second == 0) { + continue; + } } if ((int)draw.tree_tex_id != last_texture) { @@ -579,42 +620,47 @@ void Tie3::render_tree(int idx, } auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3); - int draw_size = 0; - for (int i = 0; i < indices.second; i++) { - draw_size += m_cache.multidraw_count_buffer[indices.first + i]; - } prof.add_draw_call(); tree.perf.draws++; - tree.perf.verts += draw_size; - glMultiDrawElements(GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[indices.first], - GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[indices.first], - indices.second); + if (render_state->no_multidraw) { + glDrawElements(GL_TRIANGLE_STRIP, singledraw_indices.second, GL_UNSIGNED_INT, + (void*)(singledraw_indices.first * sizeof(u32))); + } else { + glMultiDrawElements(GL_TRIANGLE_STRIP, + &m_cache.multidraw_count_buffer[multidraw_indices.first], GL_UNSIGNED_INT, + &m_cache.multidraw_index_offset_buffer[multidraw_indices.first], + multidraw_indices.second); + } switch (double_draw.kind) { case DoubleDrawKind::NONE: break; case DoubleDrawKind::AFAIL_NO_DEPTH_WRITE: tree.perf.draws++; - tree.perf.verts += draw_size; prof.add_draw_call(); - prof.add_tri(draw_size); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "alpha_min"), -10.f); glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "alpha_max"), double_draw.aref_second); glDepthMask(GL_FALSE); - glMultiDrawElements(GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[indices.first], - GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[indices.first], - indices.second); + if (render_state->no_multidraw) { + glDrawElements(GL_TRIANGLE_STRIP, singledraw_indices.second, GL_UNSIGNED_INT, + (void*)(singledraw_indices.first * sizeof(u32))); + } else { + glMultiDrawElements( + GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[multidraw_indices.first], + GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[multidraw_indices.first], + multidraw_indices.second); + } break; default: ASSERT(false); } - if (m_debug_wireframe) { + if (m_debug_wireframe && !render_state->no_multidraw) { render_state->shaders[ShaderId::TFRAG3_NO_TEX].activate(); glUniformMatrix4fv( glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3_NO_TEX].id(), "camera"), 1, @@ -628,12 +674,12 @@ void Tie3::render_tree(int idx, settings.fog.x()); glDisable(GL_BLEND); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glMultiDrawElements(GL_TRIANGLE_STRIP, &m_cache.multidraw_count_buffer[indices.first], - GL_UNSIGNED_INT, &m_cache.multidraw_index_offset_buffer[indices.first], - indices.second); + glMultiDrawElements(GL_TRIANGLE_STRIP, + &m_cache.multidraw_count_buffer[multidraw_indices.first], GL_UNSIGNED_INT, + &m_cache.multidraw_index_offset_buffer[multidraw_indices.first], + multidraw_indices.second); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); prof.add_draw_call(); - prof.add_tri(draw_size); render_state->shaders[ShaderId::TFRAG3].activate(); } } @@ -665,7 +711,7 @@ void Tie3::draw_debug_window() { auto& perf = m_trees[lod()][i].perf; ImGui::Text("Tree: %d", i); ImGui::Text("time of days: %d", (int)m_trees[lod()][i].colors->size()); - ImGui::Text("draw: %d, verts: %d", perf.draws, perf.verts); + ImGui::Text("draw: %d", perf.draws); ImGui::Text("wind draw: %d", perf.wind_draws); ImGui::Text("total: %.2f", perf.tree_time.get()); ImGui::Text("cull: %.2f index: %.2f tod: %.2f setup: %.2f draw: %.2f", diff --git a/game/graphics/opengl_renderer/background/Tie3.h b/game/graphics/opengl_renderer/background/Tie3.h index ede3d5ec68..7da1bc1752 100644 --- a/game/graphics/opengl_renderer/background/Tie3.h +++ b/game/graphics/opengl_renderer/background/Tie3.h @@ -51,6 +51,7 @@ class Tie3 : public BucketRenderer { struct Tree { GLuint vertex_buffer; GLuint index_buffer; + GLuint single_draw_index_buffer; GLuint time_of_day_texture; GLuint vao; u32 vert_count; @@ -59,6 +60,7 @@ class Tie3 : public BucketRenderer { const std::vector* instance_info = nullptr; const std::vector* colors = nullptr; const tfrag3::BVH* vis = nullptr; + const u32* index_data = nullptr; SwizzledTimeOfDay tod_cache; std::vector> wind_matrix_cache; @@ -68,7 +70,6 @@ class Tie3 : public BucketRenderer { std::vector wind_vertex_index_offsets; struct { - u32 verts = 0; u32 draws = 0; u32 wind_draws = 0; Filtered cull_time; @@ -86,6 +87,8 @@ class Tie3 : public BucketRenderer { u64 m_load_id = -1; struct Cache { + std::vector> draw_idx_temp; + std::vector index_temp; std::vector vis_temp; std::vector> multidraw_offset_per_stripdraw; std::vector multidraw_count_buffer; diff --git a/game/graphics/opengl_renderer/background/background_common.cpp b/game/graphics/opengl_renderer/background/background_common.cpp index 0802524176..7326d9863f 100644 --- a/game/graphics/opengl_renderer/background/background_common.cpp +++ b/game/graphics/opengl_renderer/background/background_common.cpp @@ -501,36 +501,6 @@ void make_all_visible_multidraws(std::pair* draw_ptrs_out, } } -u32 make_multidraws_from_vis_string(std::pair* draw_ptrs_out, - GLsizei* counts_out, - void** index_offsets_out, - const std::vector& draws, - const std::vector& vis_data) { - u64 md_idx = 0; - u32 num_tris = 0; - for (size_t i = 0; i < draws.size(); i++) { - const auto& draw = draws[i]; - u64 iidx = draw.unpacked.idx_of_first_idx_in_full_buffer; - std::pair ds; - ds.first = md_idx; - ds.second = 0; - for (auto& grp : draw.vis_groups) { - if (grp.vis_idx_in_pc_bvh == 0xffffffff || vis_data[grp.vis_idx_in_pc_bvh]) { - // visible! - // let's use a multidraw - counts_out[md_idx] = grp.num_inds; - index_offsets_out[md_idx] = (void*)(iidx * sizeof(u32)); - ds.second++; - md_idx++; - num_tris += grp.num_tris; - } - iidx += grp.num_inds; - } - draw_ptrs_out[i] = ds; - } - return num_tris; -} - u32 make_all_visible_multidraws(std::pair* draw_ptrs_out, GLsizei* counts_out, void** index_offsets_out, @@ -557,3 +527,135 @@ u32 make_all_visible_multidraws(std::pair* draw_ptrs_out, } return num_tris; } + +u32 make_all_visible_index_list(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const u32* idx_in) { + int idx_buffer_ptr = 0; + for (size_t i = 0; i < draws.size(); i++) { + const auto& draw = draws[i]; + std::pair ds; + ds.first = idx_buffer_ptr; + memcpy(&idx_out[idx_buffer_ptr], idx_in + draw.first_index_index, + draw.num_indices * sizeof(u32)); + idx_buffer_ptr += draw.num_indices; + ds.second = idx_buffer_ptr - ds.first; + group_out[i] = ds; + } + return idx_buffer_ptr; +} + +u32 make_multidraws_from_vis_string(std::pair* draw_ptrs_out, + GLsizei* counts_out, + void** index_offsets_out, + const std::vector& draws, + const std::vector& vis_data) { + u64 md_idx = 0; + u32 num_tris = 0; + u32 sanity_check = 0; + for (size_t i = 0; i < draws.size(); i++) { + const auto& draw = draws[i]; + u64 iidx = draw.unpacked.idx_of_first_idx_in_full_buffer; + ASSERT(sanity_check == iidx); + std::pair ds; + ds.first = md_idx; + ds.second = 0; + for (auto& grp : draw.vis_groups) { + sanity_check += grp.num_inds; + if (grp.vis_idx_in_pc_bvh == 0xffffffff || vis_data[grp.vis_idx_in_pc_bvh]) { + // visible! + // let's use a multidraw + counts_out[md_idx] = grp.num_inds; + index_offsets_out[md_idx] = (void*)(iidx * sizeof(u32)); + ds.second++; + md_idx++; + num_tris += grp.num_tris; + } + iidx += grp.num_inds; + } + draw_ptrs_out[i] = ds; + } + return num_tris; +} + +u32 make_index_list_from_vis_string(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const std::vector& vis_data, + const u32* idx_in, + u32* num_tris_out) { + int idx_buffer_ptr = 0; + u32 num_tris = 0; + for (size_t i = 0; i < draws.size(); i++) { + const auto& draw = draws[i]; + int vtx_idx = 0; + std::pair ds; + ds.first = idx_buffer_ptr; + bool building_run = false; + int run_start_out = 0; + int run_start_in = 0; + for (auto& grp : draw.vis_groups) { + bool vis = grp.vis_idx_in_pc_bvh == 0xffffffff || vis_data[grp.vis_idx_in_pc_bvh]; + if (vis) { + num_tris += grp.num_tris; + } + + if (building_run) { + if (vis) { + idx_buffer_ptr += grp.num_inds; + } else { + building_run = false; + memcpy(&idx_out[run_start_out], + idx_in + draw.unpacked.idx_of_first_idx_in_full_buffer + run_start_in, + (idx_buffer_ptr - run_start_out) * sizeof(u32)); + } + } else { + if (vis) { + building_run = true; + run_start_out = idx_buffer_ptr; + run_start_in = vtx_idx; + idx_buffer_ptr += grp.num_inds; + } + } + vtx_idx += grp.num_inds; + } + + if (building_run) { + memcpy(&idx_out[run_start_out], + idx_in + draw.unpacked.idx_of_first_idx_in_full_buffer + run_start_in, + (idx_buffer_ptr - run_start_out) * sizeof(u32)); + } + + ds.second = idx_buffer_ptr - ds.first; + group_out[i] = ds; + } + *num_tris_out = num_tris; + return idx_buffer_ptr; +} + +u32 make_all_visible_index_list(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const u32* idx_in, + u32* num_tris_out) { + int idx_buffer_ptr = 0; + u32 num_tris = 0; + for (size_t i = 0; i < draws.size(); i++) { + const auto& draw = draws[i]; + std::pair ds; + ds.first = idx_buffer_ptr; + u32 num_inds = 0; + for (auto& grp : draw.vis_groups) { + num_inds += grp.num_inds; + num_tris += grp.num_tris; + } + memcpy(&idx_out[idx_buffer_ptr], idx_in + draw.unpacked.idx_of_first_idx_in_full_buffer, + num_inds * sizeof(u32)); + idx_buffer_ptr += num_inds; + ds.second = idx_buffer_ptr - ds.first; + group_out[i] = ds; + } + *num_tris_out = num_tris; + return idx_buffer_ptr; +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/background/background_common.h b/game/graphics/opengl_renderer/background/background_common.h index a648ebe43c..908386dc3f 100644 --- a/game/graphics/opengl_renderer/background/background_common.h +++ b/game/graphics/opengl_renderer/background/background_common.h @@ -74,4 +74,22 @@ u32 make_multidraws_from_vis_string(std::pair* draw_ptrs_out, GLsizei* counts_out, void** index_offsets_out, const std::vector& draws, - const std::vector& vis_data); \ No newline at end of file + const std::vector& vis_data); + +u32 make_all_visible_index_list(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const u32* idx_in, + u32* num_tris_out); + +u32 make_index_list_from_vis_string(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const std::vector& vis_data, + const u32* idx_in, + u32* num_tris_out); + +u32 make_all_visible_index_list(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const u32* idx_in); \ No newline at end of file