Compilable and runnable example

This commit is contained in:
Andrew Golovashevich 2024-12-10 01:35:36 +03:00
parent 08ced011c6
commit 52561c8004
18 changed files with 459 additions and 177 deletions

View File

@ -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($<$<COMPILE_LANGUAGE:CXX>:/arch:AVX2>)
endif ()
endif ()
add_executable(
cg1
@ -28,3 +38,4 @@ qt5_use_modules(cg1 Widgets)
add_subdirectory(renderer-api)
add_subdirectory(utilities)
add_subdirectory(qt-utilities)
add_subdirectory(programs/lab1)

View File

@ -0,0 +1,2 @@
add_executable(lab1 src/main.cpp)
target_link_libraries(lab1 PRIVATE Qt5::Core Qt5::Widgets renderer_api utilities qt_utilities)

View File

@ -0,0 +1,19 @@
#include <iostream>
#include <QApplication>
#include <QMainWindow>
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/color.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
#include <bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp>
int main(int argc, char **argv) {
QApplication qApplication{argc, argv};
QMainWindow w{};
BGTU::ComputerGraphicsLabWork::QtUtilities::SeparateThreadedDefaultRendererLinear<void> renderer{};
BGTU::ComputerGraphicsLabWork::QtUtilities::RendererWidget<void> canvas{&renderer, &w};
w.setCentralWidget(&canvas);
w.show();
QApplication::exec();
}

View File

@ -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)

View File

@ -0,0 +1,37 @@
#pragma once
#include <utility>
#include <Qt>
#include <QObject>
#include <QWidget>
#include <QMutex>
#include <QPainter>
#include <QBrush>
#include <QApplication>
#include <QPalette>
#include <QStyle>
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
#include "owned_qimage.hpp"
#include "separate_threaded_renderer.hpp"
namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
template<class sprite_data_t>
class RendererWidget;
class _RendererWidget_Slots : public QWidget {
template<class>
friend
class RendererWidget;
Q_OBJECT
private:
inline _RendererWidget_Slots(QWidget *owner) : QWidget{owner} {}
private slots:
virtual void receive_image(OwnedQImage<void> img) = 0;
};
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <utility>
#include <algorithm>
#include <Qt>
#include <QDebug>
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QElapsedTimer>
#include <bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp>
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
#include "owned_qimage.hpp"
namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
class SeparateThreadedRenderer;
class _SeparateThreadedRenderer_Signals : public QObject {
Q_OBJECT
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *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<void> img);
};
}

View File

@ -4,6 +4,9 @@
#include <Qt>
#include <QObject>
#include <QImage>
#include <QColor>
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
#include <bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp>
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
@ -11,15 +14,18 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
template<class sprite_data_t>
class OwnedQImage : public QImage, public RendererApi::VoxelDrawer::Exporter<sprite_data_t> {
private:
RendererApi::Sprite<sprite_data_t> const *owners;
RendererApi::Sprite<sprite_data_t> const **owners;
public:
OwnedQImage(unsigned width, unsigned height) : QImage(width, height, QImage::Format_ARGB32), owners{new RendererApi::Sprite<sprite_data_t> const *[width * height]} {
for (RendererApi::Sprite<sprite_data_t> const *&e: this->owners) {
e = nullptr;
for (RendererApi::Sprite<sprite_data_t> const **p = this->owners - 1; p-- >= this->owners;) {
*p = nullptr;
}
}
OwnedQImage() : QImage(), owners{nullptr} {}
void setPixelOwner(unsigned x, unsigned y, RendererApi::Sprite<sprite_data_t> 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<sprite_data_t> 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;
}
};
}

View File

@ -1,22 +1,57 @@
#pragma once
#include <utility>
#include <Qt>
#include <QObject>
#include <QWidget>
#include <QMutex>
#include <QPainter>
#include <QBrush>
#include <QApplication>
#include <QPalette>
#include <QStyle>
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
#include "owned_qimage.hpp"
#include "separate_threaded_renderer.hpp"
#include "_renderer_widget.hpp"
namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
template<class sprite_data_t>
class RendererWidget : public QWidget {
Q_OBJECT
class RendererWidget : public _RendererWidget_Slots {
private:
QMutex sync;
OwnedQImage <sprite_data_t> *next_image;
OwnedQImage <sprite_data_t> *current_image;
SeparateThreadedRenderer
OwnedQImage<void> next_image;
OwnedQImage<void> current_image;
_SeparateThreadedRenderer_Signals *renderer;
private slots:
void receive_image(OwnedQImage<void> 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();
}
};
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <utility>
#include <algorithm>
#include <Qt>
#include <QDebug>
#include <QObject>
@ -9,10 +11,11 @@
#include <bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp>
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
#include "owned_qimage.hpp"
#include "_separate_threaded_renderer.hpp"
namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
class SeparateThreadedRenderer : public QObject {
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *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<sprite_data_t> *const *sprites, std::size_t sprites_count, sprite_data_t const *data);
signals:
void frame_rendered(OwnedQImage<sprite_data_t> *img);
void set_background(RendererApi::Color);
};
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::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<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::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<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_ms_per_frame(std::uint_fast64_t ms) {
this->sync.lock();
this->next_data.ms_per_frame = ms;
this->sync.unlock();
}
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_sprites(RendererApi::Sprite<sprite_data_t> *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<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_sprite_data(sprite_data_t const *data) {
this->sync.lock();
this->next_data.sprite_data = data;
this->sync.unlock();
}
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_sprites_and_data(RendererApi::Sprite<sprite_data_t> *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<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_background(RendererApi::Color c) {
this->sync.lock();
this->next_data.bg = c;
this->sync.unlock();
}
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::RendererThread::run() {
try {
QElapsedTimer timer;
while (true) {
timer.start();
this->owner->sync.lock();
data cached = this->owner->next_data;
data cached = *const_cast<data *>(&this->owner->next_data);
this->owner->sync.unlock();
auto img = new OwnedQImage<sprite_data_t>(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<sprite_data_t> 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<OwnedQImage<void> *>(&img)));
QThread::msleep(std::max<std::uint_fast64_t>(cached.ms_per_frame - static_cast<std::uint_fast64_t>(timer.elapsed()), 0));
}
} catch (std::exception const &e) {
qCritical() << typeid(e).name() << ": " << e.what() << "\n" << "Renderer thread died" << "\n";

View File

@ -1,4 +0,0 @@
#include <bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp>
#include <bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp>
#include <bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>

View File

@ -7,7 +7,7 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi {
template<class data_t>
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() {};
};

View File

@ -33,6 +33,7 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi {
template<class sprite_data_t>
class Exporter {
public:
virtual void set_pixel(PointI<2>::component_t x, PointI<2>::component_t y, Color c, Sprite<sprite_data_t> const* owner) = 0;
};
};

View File

@ -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)

View File

@ -1,13 +1,24 @@
#pragma once
#include <climits>
// #include <emmintrin.h>
#include <emmintrin.h>
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
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<RendererApi::Color::component_fast_t>(((static_cast<std::uint_fast16_t>(fg.red) * static_cast<std::uint_fast16_t>(fg.alpha) + static_cast<std::uint_fast16_t>(bg.red) * (static_cast<std::uint_fast16_t>(255) - static_cast<std::uint_fast16_t>(fg.alpha))) / 255)),
static_cast<RendererApi::Color::component_fast_t>(((static_cast<std::uint_fast16_t>(fg.green) * static_cast<std::uint_fast16_t>(fg.alpha) + static_cast<std::uint_fast16_t>(bg.green) * (static_cast<std::uint_fast16_t>(255) - static_cast<std::uint_fast16_t>(fg.alpha))) / 255)),
static_cast<RendererApi::Color::component_fast_t>(((static_cast<std::uint_fast16_t>(fg.blue) * static_cast<std::uint_fast16_t>(fg.alpha) + static_cast<std::uint_fast16_t>(bg.blue) * (static_cast<std::uint_fast16_t>(255) - static_cast<std::uint_fast16_t>(fg.alpha))) / 255)),
};
#elif 1
static auto calc = [&](RendererApi::Color::component_fast_t s, RendererApi::Color::component_fast_t o) {
auto oo = static_cast<std::uint_fast16_t>(o) * static_cast<std::uint_fast16_t>(fg.alpha);
auto ss = static_cast<std::uint_fast16_t>(s) * (static_cast<std::uint_fast16_t>(255) - static_cast<std::uint_fast16_t>(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<std::uint_fast64_t>(_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<RendererApi::Color::component_compact_t>(raw.unpacked[0]),
static_cast<RendererApi::Color::component_compact_t>(raw.unpacked[1]),
static_cast<RendererApi::Color::component_compact_t>(raw.unpacked[2])
};
#endif
#endif
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <cstddef>
#include <cstdlib>
#include <limits>
#include <new>
#include <vector>
@ -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<double>::max()}, voxels{nullptr} {};
double nearest_z;
ZElement *voxels;
} *pixels_metadata;
ZElementAllocationBuffer allocator;
RendererApi::Sprite<void> *current_artist;
public:
inline DefaultVoxelDrawerLinear(std::uint_fast16_t width, std::uint_fast16_t height);
~DefaultVoxelDrawerLinear();
template<class data_t>
void set_current_artist(RendererApi::Sprite<data_t> *sprite) {
this->current_artist = reinterpret_cast<RendererApi::Sprite<void> *>(sprite);
}
[[nodiscard]] inline std::uint_fast16_t height() const final {
return this->_height;
};
[[nodiscard]] inline std::uint_fast16_t width() const final {
template<class sprite_data_t>
class VoxelDrawerImpl : public RendererApi::VoxelDrawer {
public:
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;
RendererApi::Sprite<sprite_data_t> *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;
}
private:
[[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]);
}
public:
void add_voxel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, double z, RendererApi::Color::Transparent c) final;
private:
public:
template<class sdata_t>
void export_(RendererApi::Color background, RendererApi::VoxelDrawer::Exporter<sdata_t> *receiver);
void release_resources();
void add_voxel(long long x, long long y, double z, RendererApi::Color::Transparent c) final;
};
DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Cell *DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Page::try_allocate() {
if (this->initialized < this->capacity) {
Cell *cell = &(this->buffer[this->initialized++]);
return cell;
}
return nullptr;
}
struct {
pixel_trace_metadata *buffer;
std::size_t size;
} pixel_metadata_cache;
std::vector<ZElement *> sorter;
ZElementAllocationBuffer pixel_trace_elements_allocator;
public:
DefaultVoxelDrawerCache();
template<class sprite_data_t>
void render(
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w,
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h,
RendererApi::VoxelDrawer::Exporter<sprite_data_t> *frame,
RendererApi::Color bg,
RendererApi::Projection const *projection,
RendererApi::Sprite<sprite_data_t> *const *sprites,
std::size_t sprites_count,
sprite_data_t const *sprite_data
);
~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>
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<Cell *>(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<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;
@ -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<class sprite_data_t>
void DefaultVoxelDrawerCache::render(
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w,
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h,
RendererApi::VoxelDrawer::Exporter<sprite_data_t> *frame,
RendererApi::Color bg,
RendererApi::Projection const *projection,
RendererApi::Sprite<sprite_data_t> *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<pixel_trace_metadata *>(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<sprite_data_t> 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<class sdata_t>
void DefaultVoxelDrawerLinear::export_(RendererApi::Color background, RendererApi::VoxelDrawer::Exporter<sdata_t> *receiver) {
std::vector<ZElement *> 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<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
class SeparateThreadedRenderer;
#if 0
template<class sprite_data_t, bool _private_param>
class _SeparateThreadedDefaultRendererLinear {
};
template<class sprite_data_t>
class _SeparateThreadedDefaultRendererLinear<sprite_data_t, false> {
template<class, bool>
friend
class _SeparateThreadedDefaultRendererLinear;
class SeparateThreadedDefaultRendererLinear : public SeparateThreadedRenderer<sprite_data_t, Utilities::DefaultVoxelDrawerCache, &Utilities::DefaultVoxelDrawerCache::render<sprite_data_t>> {
private:
_SeparateThreadedDefaultRendererLinear() = delete;
class Context : public Utilities::DefaultVoxelDrawerLinear<sprite_data_t> {
};
};
class _SeparateThreadedDefaultRendererLinear : public SeparateThreadedRenderer<sprite_data_t, SeparateThreadedDefaultRendererLinear < sprite_data_t>, &SeparateThreadedDefaultRendererLinear<sprite_data_t>::render
> {
Utilities::DefaultVoxelDrawerCache context;
public:
void render(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t) {
}
explicit SeparateThreadedDefaultRendererLinear(QObject *owner = nullptr) : SeparateThreadedRenderer<sprite_data_t, Utilities::DefaultVoxelDrawerCache, &Utilities::DefaultVoxelDrawerCache::render<sprite_data_t>>{&this->context, owner} {};
};
#endif
}
}

81
utilities/src/color.asm Normal file
View File

@ -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__

View File

@ -0,0 +1,53 @@
#include <cstdlib>
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
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<Cell *>(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;
}
}

View File

@ -1,14 +1,14 @@
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
#if defined(_WIN32)
#include <cstdlib>
#include <cassert>
#include <new>
#if defined(_WIN32)
#include <Windows.h>
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);
}
}