diff --git a/CMakeLists.txt b/CMakeLists.txt index 890d8e6..1cc2189 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,16 @@ set(CMAKE_CXX_STANDARD 20) find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui) set(CMAKE_AUTOMOC ON) +enable_language(ASM_NASM) + +option(__AVX2__ "Tells compiler to use AVX2 extension if possible" OFF) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + if (__AVX2__) + add_compile_options($<$:/arch:AVX2>) + endif () +endif () + add_executable( cg1 @@ -27,4 +37,5 @@ qt5_use_modules(cg1 Widgets) add_subdirectory(renderer-api) add_subdirectory(utilities) -add_subdirectory(qt-utilities) \ No newline at end of file +add_subdirectory(qt-utilities) +add_subdirectory(programs/lab1) \ No newline at end of file diff --git a/programs/lab1/CMakeLists.txt b/programs/lab1/CMakeLists.txt new file mode 100644 index 0000000..0c557dd --- /dev/null +++ b/programs/lab1/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(lab1 src/main.cpp) +target_link_libraries(lab1 PRIVATE Qt5::Core Qt5::Widgets renderer_api utilities qt_utilities) diff --git a/programs/lab1/src/main.cpp b/programs/lab1/src/main.cpp new file mode 100644 index 0000000..0d17f62 --- /dev/null +++ b/programs/lab1/src/main.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + + QApplication qApplication{argc, argv}; + QMainWindow w{}; + + BGTU::ComputerGraphicsLabWork::QtUtilities::SeparateThreadedDefaultRendererLinear renderer{}; + BGTU::ComputerGraphicsLabWork::QtUtilities::RendererWidget canvas{&renderer, &w}; + w.setCentralWidget(&canvas); + w.show(); + QApplication::exec(); +} \ No newline at end of file diff --git a/qt-utilities/CMakeLists.txt b/qt-utilities/CMakeLists.txt index f805a15..8f4cccc 100644 --- a/qt-utilities/CMakeLists.txt +++ b/qt-utilities/CMakeLists.txt @@ -1,3 +1,3 @@ -add_library(qt_utilities OBJECT src/separate_threaded_renderer.cpp) +add_library(qt_utilities OBJECT include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp) target_include_directories(qt_utilities PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(qt_utilities PUBLIC Qt5::Core Qt5::Widgets Qt5::Gui renderer_api utilities) \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp new file mode 100644 index 0000000..1640bd4 --- /dev/null +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "owned_qimage.hpp" +#include "separate_threaded_renderer.hpp" + + +namespace BGTU::ComputerGraphicsLabWork::QtUtilities { + template + class RendererWidget; + + class _RendererWidget_Slots : public QWidget { + template + friend + class RendererWidget; + + Q_OBJECT + + private: + inline _RendererWidget_Slots(QWidget *owner) : QWidget{owner} {} + + private slots: + + virtual void receive_image(OwnedQImage img) = 0; + + }; +} \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp new file mode 100644 index 0000000..e7dccd8 --- /dev/null +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "owned_qimage.hpp" + +namespace BGTU::ComputerGraphicsLabWork::QtUtilities { + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + class SeparateThreadedRenderer; + + class _SeparateThreadedRenderer_Signals : public QObject { + Q_OBJECT + + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + friend + class SeparateThreadedRenderer; + + private: + explicit _SeparateThreadedRenderer_Signals(QObject *owner = nullptr) : QObject{owner} {} + + signals: + void frame_rendered(OwnedQImage img); + }; +} \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp index c9a7af0..1dba855 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include #include @@ -11,15 +14,18 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { template class OwnedQImage : public QImage, public RendererApi::VoxelDrawer::Exporter { private: - RendererApi::Sprite const *owners; + RendererApi::Sprite const **owners; public: OwnedQImage(unsigned width, unsigned height) : QImage(width, height, QImage::Format_ARGB32), owners{new RendererApi::Sprite const *[width * height]} { - for (RendererApi::Sprite const *&e: this->owners) { - e = nullptr; + for (RendererApi::Sprite const **p = this->owners - 1; p-- >= this->owners;) { + *p = nullptr; } } + OwnedQImage() : QImage(), owners{nullptr} {} + + void setPixelOwner(unsigned x, unsigned y, RendererApi::Sprite const *o) { assert(x < this->width()); assert(y < this->height()); @@ -33,5 +39,15 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { return this->owners[y * this->width() + x]; } + + void set_pixel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, RendererApi::Color c, RendererApi::Sprite const *owner) final { + this->setPixelColor(x, y, QColor{c.red, c.green, c.blue}); + this->setPixelOwner(x, y, owner); + } + + ~OwnedQImage() override { + if (this->owners != nullptr) + delete[] this->owners; + } }; } \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp index 30c6f5b..959c983 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp @@ -1,22 +1,57 @@ #pragma once +#include #include #include #include #include +#include +#include +#include +#include +#include +#include #include "owned_qimage.hpp" #include "separate_threaded_renderer.hpp" +#include "_renderer_widget.hpp" namespace BGTU::ComputerGraphicsLabWork::QtUtilities { template - class RendererWidget : public QWidget { - Q_OBJECT - + class RendererWidget : public _RendererWidget_Slots { private: QMutex sync; - OwnedQImage *next_image; - OwnedQImage *current_image; - SeparateThreadedRenderer + OwnedQImage next_image; + OwnedQImage current_image; + _SeparateThreadedRenderer_Signals *renderer; + + private slots: + + void receive_image(OwnedQImage img) { + this->sync.lock(); + std::swap(this->next_image, img); + this->sync.unlock(); + this->update(); + } + + + public: + explicit RendererWidget(_SeparateThreadedRenderer_Signals *renderer, QWidget *owner = nullptr) : _RendererWidget_Slots{owner}, sync{}, next_image{}, current_image{}, renderer{renderer} { + connect(this->renderer, &_SeparateThreadedRenderer_Signals::frame_rendered, this, &_RendererWidget_Slots::receive_image); + } + + protected: + void paintEvent(QPaintEvent *event) final { + this->sync.lock(); + this->current_image = std::move(this->next_image); + this->sync.unlock(); + + QPainter painter; + painter.begin(this); + painter.setBrush(QApplication::style()->standardPalette().brush(QPalette::Background)); + painter.drawRect(this->rect()); + painter.drawImage(this->current_image.rect(), this->current_image); + painter.end(); + } }; } \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp index 42d5b61..14dcb41 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp @@ -1,5 +1,7 @@ #pragma once +#include +#include #include #include #include @@ -9,10 +11,11 @@ #include #include #include "owned_qimage.hpp" +#include "_separate_threaded_renderer.hpp" namespace BGTU::ComputerGraphicsLabWork::QtUtilities { - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> - class SeparateThreadedRenderer : public QObject { + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + class SeparateThreadedRenderer : public _SeparateThreadedRenderer_Signals { private: struct data { public: @@ -22,10 +25,10 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { std::uint_fast64_t ms_per_frame; RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, height; RendererApi::Projection *projection; + RendererApi::Color bg; }; class RendererThread : public QThread { - Q_OBJECT private: SeparateThreadedRenderer *owner; @@ -58,14 +61,13 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { void set_sprites_and_data(RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *data); - signals: - - void frame_rendered(OwnedQImage *img); + void set_background(RendererApi::Color); }; - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> SeparateThreadedRenderer::SeparateThreadedRenderer(renderer_context_t *renderer_context, QObject *owner): - QObject{owner}, + _SeparateThreadedRenderer_Signals{owner}, sync{}, renderer_context{renderer_context}, sentinel_img{new QImage(0, 0, QImage::Format_ARGB32)}, @@ -81,7 +83,7 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { } { } - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_frame_size(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height) { this->sync.lock(); this->next_data.width = width; @@ -89,14 +91,14 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { this->sync.unlock(); } - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_ms_per_frame(std::uint_fast64_t ms) { this->sync.lock(); this->next_data.ms_per_frame = ms; this->sync.unlock(); } - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_sprites(RendererApi::Sprite *const *sprites, std::size_t sprites_count) { this->sync.lock(); this->next_data.sprites = sprites; @@ -104,14 +106,14 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { this->sync.unlock(); } - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_sprite_data(sprite_data_t const *data) { this->sync.lock(); this->next_data.sprite_data = data; this->sync.unlock(); } - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_sprites_and_data(RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *data) { this->sync.lock(); this->next_data.sprites = sprites; @@ -120,20 +122,35 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { this->sync.unlock(); } - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + void SeparateThreadedRenderer::set_background(RendererApi::Color c) { + this->sync.lock(); + this->next_data.bg = c; + this->sync.unlock(); + } + + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::RendererThread::run() { try { QElapsedTimer timer; while (true) { timer.start(); this->owner->sync.lock(); - data cached = this->owner->next_data; + data cached = *const_cast(&this->owner->next_data); this->owner->sync.unlock(); - auto img = new OwnedQImage(cached.width, cached.height); - (this->owner->renderer_context->*renderer_procedure)(img, cached.sprite_data, cached.sprites, cached.sprites_count); - emit this->owner->frame_rendered(img); - QThread::msleep(std::max(cached.ms_per_frame - timer.elapsed(), 0)); + OwnedQImage img{cached.width, cached.height}; + (this->owner->renderer_context->*renderer_procedure)( + cached.width, cached.height, + &img, + cached.bg, + cached.projection, + cached.sprites, cached.sprites_count, + cached.sprite_data + ); + emit this->owner->frame_rendered(std::move(*reinterpret_cast *>(&img))); + QThread::msleep(std::max(cached.ms_per_frame - static_cast(timer.elapsed()), 0)); } } catch (std::exception const &e) { qCritical() << typeid(e).name() << ": " << e.what() << "\n" << "Renderer thread died" << "\n"; diff --git a/qt-utilities/src/separate_threaded_renderer.cpp b/qt-utilities/src/separate_threaded_renderer.cpp deleted file mode 100644 index 77ce9d9..0000000 --- a/qt-utilities/src/separate_threaded_renderer.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include -#include -#include -#include diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp index 81a5859..83bfdc2 100644 --- a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp @@ -7,7 +7,7 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi { template class Sprite { public: - virtual void draw(VoxelDrawer *frame, Projection *projection, data_t *data) const = 0; + virtual void draw(VoxelDrawer *frame, Projection const *projection, data_t const *data) const = 0; virtual void clicked() {}; }; diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp index 65ed5d5..a30c532 100644 --- a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp @@ -33,6 +33,7 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi { template class Exporter { + public: virtual void set_pixel(PointI<2>::component_t x, PointI<2>::component_t y, Color c, Sprite const* owner) = 0; }; }; diff --git a/utilities/CMakeLists.txt b/utilities/CMakeLists.txt index 8a34f63..a5e9718 100644 --- a/utilities/CMakeLists.txt +++ b/utilities/CMakeLists.txt @@ -1,3 +1,3 @@ -add_library(utilities OBJECT src/shader.cpp src/memory_pages_managment.cpp) +add_library(utilities OBJECT src/shader.cpp src/memory_pages_management.cpp src/default_renderer_linear.cpp src/color.asm) target_include_directories(utilities PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(utilities PUBLIC renderer_api) \ No newline at end of file diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp index f8c2371..9b9cf68 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/color.hpp @@ -1,13 +1,24 @@ #pragma once #include -// #include +#include #include namespace BGTU::ComputerGraphicsLabWork::Utilities { - RendererApi::Color apply_transparent_color(RendererApi::Color bg, RendererApi::Color::Transparent fg) { + inline RendererApi::Color apply_transparent_color(RendererApi::Color bg, RendererApi::Color::Transparent fg) { +#if defined(__AVX512F__) + return _apply_transparent_color_avx512(bg, fg); +#elif 0 && defined(__AVX2__) + return _apply_transparent_color_avx2(bg, fg); +#else #if 1 + return RendererApi::Color{ + static_cast(((static_cast(fg.red) * static_cast(fg.alpha) + static_cast(bg.red) * (static_cast(255) - static_cast(fg.alpha))) / 255)), + static_cast(((static_cast(fg.green) * static_cast(fg.alpha) + static_cast(bg.green) * (static_cast(255) - static_cast(fg.alpha))) / 255)), + static_cast(((static_cast(fg.blue) * static_cast(fg.alpha) + static_cast(bg.blue) * (static_cast(255) - static_cast(fg.alpha))) / 255)), + }; +#elif 1 static auto calc = [&](RendererApi::Color::component_fast_t s, RendererApi::Color::component_fast_t o) { auto oo = static_cast(o) * static_cast(fg.alpha); auto ss = static_cast(s) * (static_cast(255) - static_cast(fg.alpha)); @@ -25,14 +36,16 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { __m128i vec_alpha = _mm_set_epi16(fg.alpha, fg.alpha, fg.alpha, 0, 0, 0, 0, 0); union { - std::uint_fast64_t packed = static_cast(_mm_cvtsi128_si64(_mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(vec_fg, vec_alpha), _mm_mullo_epi16(vec_bg, _mm_sub_epi16(vec_256, vec_alpha))), 8))); + __m128i packed; std::uint16_t unpacked[3]; } raw; + _mm_storel_epi64(&raw.packed, _mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(vec_fg, vec_alpha), _mm_mullo_epi16(vec_bg, _mm_sub_epi16(vec_256, vec_alpha))), 8)); return RendererApi::Color{ static_cast(raw.unpacked[0]), static_cast(raw.unpacked[1]), static_cast(raw.unpacked[2]) }; +#endif #endif } } \ No newline at end of file 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 7ad53e5..3a061b0 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 @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -12,10 +13,11 @@ #include "color.hpp" #include "matrix.hpp" +class QObject; namespace BGTU::ComputerGraphicsLabWork { namespace Utilities { - class DefaultVoxelDrawerLinear : public RendererApi::VoxelDrawer { + class DefaultVoxelDrawerCache { private: class ZElement { public: @@ -53,7 +55,7 @@ namespace BGTU::ComputerGraphicsLabWork { Cell buffer[0]; public: - explicit Page(Page *next, std::size_t capacity) : next{next}, initialized{0}, capacity{capacity} {}; + explicit Page(Page *next, std::size_t capacity) : next{next}, initialized{0}, capacity{capacity}, buffer{} {}; Cell *try_allocate(); @@ -93,70 +95,84 @@ namespace BGTU::ComputerGraphicsLabWork { ~ZElementAllocationBuffer(); }; - - RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t _width; - RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t _height; - struct pixel_trace_metadata { public: pixel_trace_metadata() : nearest_z{std::numeric_limits::max()}, voxels{nullptr} {}; double nearest_z; ZElement *voxels; - } *pixels_metadata; - - ZElementAllocationBuffer allocator; - RendererApi::Sprite *current_artist; - public: - inline DefaultVoxelDrawerLinear(std::uint_fast16_t width, std::uint_fast16_t height); - - ~DefaultVoxelDrawerLinear(); - - template - void set_current_artist(RendererApi::Sprite *sprite) { - this->current_artist = reinterpret_cast *>(sprite); - } - - [[nodiscard]] inline std::uint_fast16_t height() const final { - return this->_height; }; - [[nodiscard]] inline std::uint_fast16_t width() const final { - return this->_width; - } + template + class VoxelDrawerImpl : public RendererApi::VoxelDrawer { + public: + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t _width; + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t _height; - private: + pixel_trace_metadata *pixels_metadata; - pixel_trace_metadata *at(std::uint_fast16_t x, std::uint_fast16_t y) { - return &(this->pixels_metadata[y * this->_width + x]); - } + ZElementAllocationBuffer *pixel_trace_elements_allocator; + RendererApi::Sprite *current_artist; + + 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 { + return this->_width; + } + + [[nodiscard]] 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) { + return &(this->pixels_metadata[y * this->_width + x]); + } + + void add_voxel(long long x, long long y, double z, RendererApi::Color::Transparent c) final; + }; + + + struct { + pixel_trace_metadata *buffer; + std::size_t size; + } pixel_metadata_cache; + std::vector sorter; + ZElementAllocationBuffer pixel_trace_elements_allocator; public: + DefaultVoxelDrawerCache(); - void add_voxel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, double z, RendererApi::Color::Transparent c) final; + template + void render( + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h, + RendererApi::VoxelDrawer::Exporter *frame, + RendererApi::Color bg, + RendererApi::Projection const *projection, + RendererApi::Sprite *const *sprites, + std::size_t sprites_count, + sprite_data_t const *sprite_data + ); - - private: - - - public: - - template - void export_(RendererApi::Color background, RendererApi::VoxelDrawer::Exporter *receiver); - - void release_resources(); + ~DefaultVoxelDrawerCache(); }; - DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Cell *DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Page::try_allocate() { - if (this->initialized < this->capacity) { - Cell *cell = &(this->buffer[this->initialized++]); - return cell; - } - return nullptr; - } + 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 - DefaultVoxelDrawerLinear::ZElement *DefaultVoxelDrawerLinear::ZElementAllocationBuffer::alloc_elem(args_t... args) { + DefaultVoxelDrawerCache::ZElement *DefaultVoxelDrawerCache::ZElementAllocationBuffer::alloc_elem(args_t... args) { auto cell = this->next_unallocated; if (cell != nullptr) { this->next_unallocated = cell->empty.next_empty; @@ -169,49 +185,8 @@ namespace BGTU::ComputerGraphicsLabWork { return new(&(cell->allocated)) ZElement{args...}; } - - void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::free_elem(DefaultVoxelDrawerLinear::ZElement *e) { - Cell *cell = reinterpret_cast(e); - cell->empty.next_empty = this->next_unallocated; - this->next_unallocated = cell; - } - - void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::release_resources() { - Page *p; - while (this->last_page != nullptr) { - p = this->last_page; - this->last_page = p->next; - this->_native_free_page(p); - } - this->next_unallocated = nullptr; - } - - void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::reset_allocations() { - Page *p = this->last_page; - while (p != nullptr) { - p->reset_allocations(); - p = p->next; - } - this->next_unallocated = nullptr; - } - - DefaultVoxelDrawerLinear::ZElementAllocationBuffer::~ZElementAllocationBuffer() { - this->release_resources(); - } - - - DefaultVoxelDrawerLinear::DefaultVoxelDrawerLinear(std::uint_fast16_t width, std::uint_fast16_t height) : - _width{width}, - _height{height}, - pixels_metadata{new pixel_trace_metadata[sizeof(ZElement) * width * height]{}}, - allocator{}, - current_artist{nullptr} {} - - DefaultVoxelDrawerLinear::~DefaultVoxelDrawerLinear() { - delete[] this->pixels_metadata; - } - - void DefaultVoxelDrawerLinear::add_voxel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, double z, RendererApi::Color::Transparent c) { + 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; @@ -224,35 +199,53 @@ namespace BGTU::ComputerGraphicsLabWork { while (p->voxels != nullptr) { e = p->voxels; p->voxels = e->next; - this->allocator.free_elem(e); + this->pixel_trace_elements_allocator->free_elem(e); } } #endif } - p->voxels = this->allocator.alloc_elem(p->voxels, z, c, this->current_artist); + p->voxels = this->pixel_trace_elements_allocator->alloc_elem(p->voxels, z, c, this->current_artist); } - void DefaultVoxelDrawerLinear::release_resources() { - this->allocator.release_resources(); - } + template + void DefaultVoxelDrawerCache::render( + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h, + RendererApi::VoxelDrawer::Exporter *frame, + RendererApi::Color bg, + RendererApi::Projection const *projection, + RendererApi::Sprite *const *sprites, + std::size_t sprites_count, + sprite_data_t const *sprite_data + ) { + if (this->pixel_metadata_cache.buffer == nullptr || this->pixel_metadata_cache.size < w * h) { + this->pixel_metadata_cache.buffer = static_cast(std::realloc(this->pixel_metadata_cache.buffer, w * h * sizeof(pixel_trace_metadata))); + this->pixel_metadata_cache.size = w * h; + } + + this->pixel_trace_elements_allocator.reset_allocations(); + VoxelDrawerImpl painter{w, h, this->pixel_metadata_cache.buffer, &this->pixel_trace_elements_allocator}; + + for (; sprites_count-- > 0; sprites++) { + painter.current_artist = *sprites; + (*sprites)->draw(&painter, projection, sprite_data); + } - template - void DefaultVoxelDrawerLinear::export_(RendererApi::Color background, RendererApi::VoxelDrawer::Exporter *receiver) { - std::vector sorter; std::uint_fast16_t y = 0; std::uint_fast16_t x = 0; - for (std::int_fast64_t i = this->_width * this->_height - 1; i >= 0; i--) { - for (ZElement *e = this->pixels_metadata[i].voxels; e != nullptr; e = e->next) { + for (std::int_fast64_t i = w * h - 1; i >= 0; i--) { + for (ZElement *e = this->pixel_metadata_cache.buffer[i].voxels; e != nullptr; e = e->next) { sorter.push_back(e); } std::sort(sorter.rbegin(), sorter.rend(), [](ZElement *l, ZElement *r) { return l->z < r->z; }); - RendererApi::Color p = background; + RendererApi::Color p = bg; for (auto a: sorter) { p = apply_transparent_color(p, a->color); } - receiver->export_pixel(x, y, p, sorter[sorter.size() - 1]->owner); - if (++x >= this->_width) { + frame->set_pixel(x, y, p, sorter[sorter.size() - 1]->owner); + + if (++x >= w) { y++; x = 0; } @@ -261,40 +254,16 @@ namespace BGTU::ComputerGraphicsLabWork { } namespace QtUtilities { - template *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t)> + template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> class SeparateThreadedRenderer; -#if 0 - template - class _SeparateThreadedDefaultRendererLinear { - }; template - class _SeparateThreadedDefaultRendererLinear { - template - friend - class _SeparateThreadedDefaultRendererLinear; - - + class SeparateThreadedDefaultRendererLinear : public SeparateThreadedRenderer> { private: - _SeparateThreadedDefaultRendererLinear() = delete; - - class Context : public Utilities::DefaultVoxelDrawerLinear { - - }; - - }; - - - class _SeparateThreadedDefaultRendererLinear : public SeparateThreadedRenderer, &SeparateThreadedDefaultRendererLinear::render - - > { + Utilities::DefaultVoxelDrawerCache context; public: - - void render(RendererApi::VoxelDrawer::Exporter *, sprite_data_t *, RendererApi::Sprite *const *, std::size_t) { - - } - }; -#endif + explicit SeparateThreadedDefaultRendererLinear(QObject *owner = nullptr) : SeparateThreadedRenderer>{&this->context, owner} {}; + }; } } \ No newline at end of file diff --git a/utilities/src/color.asm b/utilities/src/color.asm new file mode 100644 index 0000000..009f917 --- /dev/null +++ b/utilities/src/color.asm @@ -0,0 +1,81 @@ +%define __MMX__ 1 +%define __SSE__ 2 +%define __SSE2__ 3 +%define __SSE3__ 4 +%define __SSSE3__ 5 +%define __SSE4_1__ 6 +%define __SSE4_2__ 7 +%define __AVX__ 8 +%define __AVX2__ 9 +%define __FMA3__ 10 +%define __AVX512F__ 11 +%define __AMX__ 12 + + +%macro impl_body 1 +%ifidn __OUTPUT_FORMAT__, elf64 + movd xmm0, edi + movd xmm1, esi + mov r8d, esi +%elifidn __OUTPUT_FORMAT__, win64 +; movzx r9d, WORD [rdx] +; movzx r10d, BYTE [rdx+2] +; shl r10d, 16 +; or r9d, r10d + movd xmm0, DWORD [rdx] + movd xmm1, r8d +%else +%error "Unsupported output format" +%endif + + pmovzxbd xmm0, xmm0 ; 0-extend 8bit->32bit + pmovzxbd xmm1, xmm1 ; 0-extend 8bit->32bit + shr r8d, 24 +%if %1 >= __AVX512F__ + vpbroadcastd xmm2, r8d ; fill vector with 32bit values +%elif %1 >= __AVX2__ + movd xmm2, r8d + vpbroadcastd xmm2, xmm2 +%endif + mov r8d, 255 +%if %1 >= __AVX512F__ + vpbroadcastd xmm3, r8d ; fill vector with 32bit values +%elif %1 >= __AVX2__ + movd xmm3, r8d + vpbroadcastd xmm3, xmm3 +%endif + + psubd xmm3, xmm2 ; sub 32bit integers + pmuludq xmm0, xmm3 ; mul unsigned 32bit integers + pmuludq xmm1, xmm2 ; mul unsigned 32bit integers + paddd xmm0, xmm1 ; add 32bit integers + psrld xmm0, 8 ; 0-shift 32bit integers right + + pextrd r9d, xmm0, 0 ; extracts 32 bit integer + pextrd r10d, xmm0, 1 ; extracts 32 bit integer + pextrd r11d, xmm0, 2 ; extracts 32 bit integer + shl r10d, 8 + shl r11d, 16 + or r9d, r10d + or r9d, r11d + +%ifidn __OUTPUT_FORMAT__, elf64 + mov eax, r9d +%elifidn __OUTPUT_FORMAT__, win64 + mov DWORD [rcx], r9d +%else +%error "Unsupported output format" +%endif + ret +%endmacro + + +section .text + + +; avx2 + +global ?_apply_transparent_color_avx2@Utilities@ComputerGraphicsLabWork@BGTU@@YA?AVColor@RendererApi@23@V4523@VTransparent@4523@@Z ; msvc + +?_apply_transparent_color_avx2@Utilities@ComputerGraphicsLabWork@BGTU@@YA?AVColor@RendererApi@23@V4523@VTransparent@4523@@Z: +impl_body __AVX2__ \ No newline at end of file diff --git a/utilities/src/default_renderer_linear.cpp b/utilities/src/default_renderer_linear.cpp new file mode 100644 index 0000000..2f15217 --- /dev/null +++ b/utilities/src/default_renderer_linear.cpp @@ -0,0 +1,53 @@ +#include +#include + +namespace BGTU::ComputerGraphicsLabWork::Utilities { + + DefaultVoxelDrawerCache::ZElementAllocationBuffer::Cell *DefaultVoxelDrawerCache::ZElementAllocationBuffer::Page::try_allocate() { + if (this->initialized < this->capacity) { + Cell *cell = &(this->buffer[this->initialized++]); + return cell; + } + return nullptr; + } + + void DefaultVoxelDrawerCache::ZElementAllocationBuffer::free_elem(DefaultVoxelDrawerCache::ZElement *e) { + Cell *cell = reinterpret_cast(e); + cell->empty.next_empty = this->next_unallocated; + this->next_unallocated = cell; + } + + void DefaultVoxelDrawerCache::ZElementAllocationBuffer::release_resources() { + Page *p; + while (this->last_page != nullptr) { + p = this->last_page; + this->last_page = p->next; + this->_native_free_page(p); + } + this->next_unallocated = nullptr; + } + + void DefaultVoxelDrawerCache::ZElementAllocationBuffer::reset_allocations() { + Page *p = this->last_page; + while (p != nullptr) { + p->reset_allocations(); + p = p->next; + } + this->next_unallocated = nullptr; + } + + DefaultVoxelDrawerCache::ZElementAllocationBuffer::~ZElementAllocationBuffer() { + this->release_resources(); + } + + DefaultVoxelDrawerCache::DefaultVoxelDrawerCache() : pixel_trace_elements_allocator{}, pixel_metadata_cache{.buffer = nullptr, .size = 0}, sorter{} {} + + DefaultVoxelDrawerCache::~DefaultVoxelDrawerCache() { + if (this->pixel_metadata_cache.buffer != nullptr) { + std::free(this->pixel_metadata_cache.buffer); + this->pixel_metadata_cache.buffer = nullptr; + } + this->pixel_metadata_cache.size = 0; + } + +} \ No newline at end of file diff --git a/utilities/src/memory_pages_managment.cpp b/utilities/src/memory_pages_management.cpp similarity index 71% rename from utilities/src/memory_pages_managment.cpp rename to utilities/src/memory_pages_management.cpp index d929a60..bd7f49a 100644 --- a/utilities/src/memory_pages_managment.cpp +++ b/utilities/src/memory_pages_management.cpp @@ -1,14 +1,14 @@ #include - -#if defined(_WIN32) - #include #include #include + +#if defined(_WIN32) + #include namespace BGTU::ComputerGraphicsLabWork::Utilities { - DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Page *DefaultVoxelDrawerLinear::ZElementAllocationBuffer::_native_extend() { + DefaultVoxelDrawerCache::ZElementAllocationBuffer::Page *DefaultVoxelDrawerCache::ZElementAllocationBuffer::_native_extend() { SYSTEM_INFO si; GetSystemInfo(&si); @@ -20,7 +20,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities { } - void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::_native_free_page(DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Page *p) { + void DefaultVoxelDrawerCache::ZElementAllocationBuffer::_native_free_page(DefaultVoxelDrawerCache::ZElementAllocationBuffer::Page *p) { VirtualFree(p, 0, MEM_DECOMMIT | MEM_RELEASE); } }