Voxels sort optimization

This commit is contained in:
Andrew Golovashevich 2024-12-10 06:34:24 +03:00
parent 003ba2b290
commit 93da247ccc
2 changed files with 118 additions and 53 deletions

View File

@ -103,7 +103,6 @@ namespace BGTU::ComputerGraphicsLabWork {
ZElement *voxels;
};
template<class sprite_data_t>
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<ZElement *> sorter;
ZElementAllocationBuffer pixel_trace_elements_allocator;
public:
DefaultVoxelDrawerCache();
private:
static ZElement *sort_zelements_desc(DefaultVoxelDrawerCache::ZElement *start) noexcept;
public:
template<class sprite_data_t>
void render(
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w,
@ -157,19 +159,6 @@ namespace BGTU::ComputerGraphicsLabWork {
~DefaultVoxelDrawerCache();
};
template<class sprite_data_t>
DefaultVoxelDrawerCache::VoxelDrawerImpl<sprite_data_t>::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<class... args_t>
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<class sprite_data_t>
void DefaultVoxelDrawerCache::VoxelDrawerImpl<sprite_data_t>::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<class sprite_data_t>
void DefaultVoxelDrawerCache::render(
@ -226,7 +194,7 @@ namespace BGTU::ComputerGraphicsLabWork {
}
this->pixel_trace_elements_allocator.reset_allocations();
VoxelDrawerImpl<sprite_data_t> 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++;

View File

@ -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<std::size_t>::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);
}
}