From 93da247ccc22dc1aedf3d26526e133b5999c4970 Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Tue, 10 Dec 2024 06:34:24 +0300 Subject: [PATCH] Voxels sort optimization --- .../utilities/default_renderer_linear.hpp | 67 +++-------- utilities/src/default_renderer_linear.cpp | 104 +++++++++++++++++- 2 files changed, 118 insertions(+), 53 deletions(-) diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp index 95732b3..96502b2 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp @@ -103,7 +103,6 @@ namespace BGTU::ComputerGraphicsLabWork { ZElement *voxels; }; - template class VoxelDrawerImpl : public RendererApi::VoxelDrawer { public: RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t _width; @@ -116,15 +115,15 @@ namespace BGTU::ComputerGraphicsLabWork { VoxelDrawerImpl(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height, pixel_trace_metadata *pixels_metadata, ZElementAllocationBuffer *pixel_trace_elements_allocator); - [[nodiscard]] RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width() const final { + [[nodiscard]] inline RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width() const final { return this->_width; } - [[nodiscard]] RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height() const final { + [[nodiscard]] inline RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height() const final { return this->_height; } - pixel_trace_metadata *at(std::uint_fast16_t x, std::uint_fast16_t y) { + inline pixel_trace_metadata *at(std::uint_fast16_t x, std::uint_fast16_t y) { return &(this->pixels_metadata[y * this->_width + x]); } @@ -136,12 +135,15 @@ namespace BGTU::ComputerGraphicsLabWork { pixel_trace_metadata *buffer; std::size_t size; } pixel_metadata_cache; - std::vector sorter; ZElementAllocationBuffer pixel_trace_elements_allocator; public: DefaultVoxelDrawerCache(); + private: + static ZElement *sort_zelements_desc(DefaultVoxelDrawerCache::ZElement *start) noexcept; + + public: template void render( RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, @@ -157,19 +159,6 @@ namespace BGTU::ComputerGraphicsLabWork { ~DefaultVoxelDrawerCache(); }; - template - DefaultVoxelDrawerCache::VoxelDrawerImpl::VoxelDrawerImpl( - RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, - RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height, - DefaultVoxelDrawerCache::pixel_trace_metadata *pixels_metadata, - DefaultVoxelDrawerCache::ZElementAllocationBuffer *pixel_trace_elements_allocator - ): _width{width}, - _height{height}, - pixels_metadata{pixels_metadata}, - pixel_trace_elements_allocator{pixel_trace_elements_allocator}, - current_artist{nullptr} {} - - template DefaultVoxelDrawerCache::ZElement *DefaultVoxelDrawerCache::ZElementAllocationBuffer::alloc_elem(args_t... args) { auto cell = this->next_unallocated; @@ -184,27 +173,6 @@ namespace BGTU::ComputerGraphicsLabWork { return new(&(cell->allocated)) ZElement{args...}; } - template - void DefaultVoxelDrawerCache::VoxelDrawerImpl::add_voxel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, double z, RendererApi::Color::Transparent c) { - if (x < 0 || this->_width <= x) return; - if (y < 0 || this->_height <= y) return; - if (z < 0) return; - auto p = this->at(x, y); - if (z <= p->nearest_z) { - p->nearest_z = z; -#if 1 - if (c.alpha == 255) { - ZElement *e; - while (p->voxels != nullptr) { - e = p->voxels; - p->voxels = e->next; - this->pixel_trace_elements_allocator->free_elem(e); - } - } -#endif - } - p->voxels = this->pixel_trace_elements_allocator->alloc_elem(p->voxels, z, c, this->current_artist); - } template void DefaultVoxelDrawerCache::render( @@ -226,7 +194,7 @@ namespace BGTU::ComputerGraphicsLabWork { } this->pixel_trace_elements_allocator.reset_allocations(); - VoxelDrawerImpl painter{w, h, this->pixel_metadata_cache.buffer, &this->pixel_trace_elements_allocator}; + VoxelDrawerImpl painter{w, h, this->pixel_metadata_cache.buffer, &this->pixel_trace_elements_allocator}; for (std::int_fast64_t i = w * h - 1; i >= 0; i--) { new(&this->pixel_metadata_cache.buffer[i]) pixel_trace_metadata{}; @@ -241,19 +209,14 @@ namespace BGTU::ComputerGraphicsLabWork { std::uint_fast16_t x = 0; for (std::int_fast64_t i = w * h - 1; i >= 0; i--) { - this->sorter.clear(); - for (ZElement *e = this->pixel_metadata_cache.buffer[i].voxels; e != nullptr; e = e->next) { - this->sorter.push_back(e); + this->pixel_metadata_cache.buffer[i].voxels = sort_zelements_desc(this->pixel_metadata_cache.buffer[i].voxels); + RendererApi::Color cc = bg; + RendererApi::SpriteMetadata *owner = nullptr; + for (auto p = this->pixel_metadata_cache.buffer[i].voxels; p != nullptr; p = p->next) { + cc = apply_transparent_color(cc, p->color); + owner = p->owner; } - std::sort(this->sorter.begin(), this->sorter.end(), [](ZElement *l, ZElement *r) { return l->z > r->z; }); - RendererApi::Color p = bg; - for (auto a: this->sorter) { - p = apply_transparent_color(p, a->color); - } - if (this->sorter.empty()) - frame->set_pixel(x, y, p, nullptr); - else - frame->set_pixel(x, y, p, this->sorter[this->sorter.size() - 1]->owner); + frame->set_pixel(x, y, cc, owner); if (++x >= w) { y++; diff --git a/utilities/src/default_renderer_linear.cpp b/utilities/src/default_renderer_linear.cpp index 2f15217..d108d38 100644 --- a/utilities/src/default_renderer_linear.cpp +++ b/utilities/src/default_renderer_linear.cpp @@ -40,7 +40,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { this->release_resources(); } - DefaultVoxelDrawerCache::DefaultVoxelDrawerCache() : pixel_trace_elements_allocator{}, pixel_metadata_cache{.buffer = nullptr, .size = 0}, sorter{} {} + DefaultVoxelDrawerCache::DefaultVoxelDrawerCache() : pixel_trace_elements_allocator{}, pixel_metadata_cache{.buffer = nullptr, .size = 0} {} DefaultVoxelDrawerCache::~DefaultVoxelDrawerCache() { if (this->pixel_metadata_cache.buffer != nullptr) { @@ -50,4 +50,106 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { this->pixel_metadata_cache.size = 0; } + DefaultVoxelDrawerCache::ZElement* DefaultVoxelDrawerCache::sort_zelements_desc(DefaultVoxelDrawerCache::ZElement *start) noexcept { + for (std::size_t frame_size = 1; 0 < frame_size && frame_size < std::numeric_limits::max() / 4; frame_size *= 2) { + ZElement **before_left = &start; + + while (true) { + ZElement **union_ptr = before_left; + ZElement *left_ptr = *before_left; + ZElement *right_ptr; + std::size_t left_counter = frame_size; + std::size_t right_counter = frame_size; + + if (left_ptr == nullptr) + goto ROUND_DONE; + + right_ptr = left_ptr; + while (left_counter-- > 0) { + right_ptr = right_ptr->next; + if (right_ptr == nullptr) + goto ROUND_DONE; + } + left_counter = frame_size; + + while (left_counter > 0 && right_counter > 0) { + if (left_ptr->z >= right_ptr->z) { + *union_ptr = left_ptr; + left_ptr = left_ptr->next; + union_ptr = &((*union_ptr)->next); + if (left_counter-- == 0) + goto RIGHT_TAIL; + } else { + *union_ptr = right_ptr; + right_ptr = right_ptr->next; + union_ptr = &((*union_ptr)->next); + if (right_counter-- == 0) + goto LEFT_TAIL; + + if (right_ptr == nullptr) { + goto LEFT_TAIL; + } + } + } + if (right_counter == 0) { + LEFT_TAIL: + while (right_counter-- > 1) + left_ptr = left_ptr->next; + left_ptr->next = right_ptr; + before_left = &(left_ptr->next); + } + if (left_counter == 0) { + RIGHT_TAIL: + *union_ptr = right_ptr; + while (right_counter-- > 1) { + right_ptr = right_ptr->next; + if (right_ptr == nullptr) { + goto ROUND_DONE; + } + } + before_left = &(right_ptr->next); + } + } + + + ROUND_DONE: + if (before_left == &start) + break; + } + return start; + } + + + DefaultVoxelDrawerCache::VoxelDrawerImpl::VoxelDrawerImpl( + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height, + DefaultVoxelDrawerCache::pixel_trace_metadata *pixels_metadata, + DefaultVoxelDrawerCache::ZElementAllocationBuffer *pixel_trace_elements_allocator + ) : _width{width}, + _height{height}, + pixels_metadata{pixels_metadata}, + pixel_trace_elements_allocator{pixel_trace_elements_allocator}, + current_artist{nullptr} {} + + + void DefaultVoxelDrawerCache::VoxelDrawerImpl::add_voxel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, double z, RendererApi::Color::Transparent c) { + if (x < 0 || this->_width <= x) return; + if (y < 0 || this->_height <= y) return; + if (z < 0) return; + auto p = this->at(x, y); + if (z <= p->nearest_z) { + p->nearest_z = z; +#if 1 + if (c.alpha == 255) { + ZElement *e; + while (p->voxels != nullptr) { + e = p->voxels; + p->voxels = e->next; + this->pixel_trace_elements_allocator->free_elem(e); + } + } +#endif + } + p->voxels = this->pixel_trace_elements_allocator->alloc_elem(p->voxels, z, c, this->current_artist); + } } \ No newline at end of file