Fps calculator

This commit is contained in:
Andrew Golovashevich 2024-12-10 05:13:55 +03:00
parent 15c715ad21
commit 003ba2b290
9 changed files with 151 additions and 50 deletions

3
.gitignore vendored
View File

@ -7,4 +7,5 @@
*.exe
/.idea/
/*build*/
/*build*/
/.vs/

View File

@ -1,8 +1,7 @@
#include <iostream>
#include <QApplication>
#include <QMainWindow>
#include <QTimer>
#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>
#include <bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp>
@ -10,10 +9,36 @@
int main(int argc, char **argv) {
QApplication qApplication{argc, argv};
qRegisterMetaType<BGTU::ComputerGraphicsLabWork::QtUtilities::OwnedQImage>("OwnedQImage");
// qRegisterMetaType<BGTU::ComputerGraphicsLabWork::QtUtilities::OwnedQImage>("OwnedQImage");
QTimer fps_timeout;
unsigned frames = 0;
fps_timeout.callOnTimeout([&] {
qCritical() << (frames * 4) << "\n";
qDebug() << (frames * 4) << "\n";
frames = 0;
});
fps_timeout.setInterval(250);
fps_timeout.start();
QMainWindow w{};
class o : public QObject {
public:
unsigned *frames;
explicit o(unsigned *f) : QObject{}, frames{f} {}
public slots:
void hit() {
(*this->frames)++;
}
};
o oo{&frames};
BGTU::ComputerGraphicsLabWork::QtUtilities::SeparateThreadedDefaultRendererLinear<void> renderer{};
QObject::connect(&renderer, &BGTU::ComputerGraphicsLabWork::QtUtilities::_SeparateThreadedRenderer_Signals::frame_rendered, &oo, &o::hit);
renderer.set_background(BGTU::ComputerGraphicsLabWork::RendererApi::Color{0, 0, 0});
BGTU::ComputerGraphicsLabWork::QtUtilities::RendererWidget<void> canvas{&renderer, &w};
w.setCentralWidget(&canvas);

View File

@ -31,7 +31,7 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
private slots:
virtual void receive_image(OwnedQImage img) = 0;
virtual void receive_image(OwnedQImage *img) = 0;
};
}

View File

@ -13,13 +13,16 @@
#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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t>
using _SeparateThreadedRenderer_RenderProcedureType = void (renderer_context_t::*)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *);
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t>>
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t>>
friend
class SeparateThreadedRenderer;
@ -27,6 +30,16 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
explicit _SeparateThreadedRenderer_Signals(QObject *owner = nullptr) : QObject{owner} {}
signals:
void frame_rendered(OwnedQImage img);
void frame_rendered(OwnedQImage *img);
public slots:
virtual void set_frame_size(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height) = 0;
virtual void set_ms_per_frame(std::uint_fast64_t ms) = 0;
virtual void set_background(RendererApi::Color) = 0;
};
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <cassert>
#include <cstring>
#include <Qt>
#include <QObject>
#include <QImage>
@ -30,6 +31,31 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
OwnedQImage() : QImage(), owners{nullptr} {}
OwnedQImage &operator=(OwnedQImage const &copy) {
if (this == &copy)
return *this;
if (this->owners != nullptr)
delete[] this->owners;
if (copy.owners == nullptr) {
this->owners = nullptr;
} else {
this->owners = new RendererApi::SpriteMetadata const *[copy.width() * copy.height()];
std::memcpy(this->owners, copy.owners, copy.width() * copy.height() * sizeof(RendererApi::SpriteMetadata const *));
}
return *this;
}
OwnedQImage(OwnedQImage const &copy) : QImage{copy} {
*this = copy;
}
OwnedQImage(OwnedQImage &&move) noexcept : QImage{std::move(move)} {
if (this->owners != nullptr)
delete[] this->owners;
this->owners = move.owners;
move.owners = nullptr;
}
void setPixelOwner(unsigned x, unsigned y, RendererApi::SpriteMetadata const *o) {
assert(x < this->width());
@ -51,8 +77,10 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
}
~OwnedQImage() override {
if (this->owners != nullptr)
if (this->owners != nullptr) {
delete[] this->owners;
this->owners = nullptr;
}
}
};
}

View File

@ -10,6 +10,8 @@
#include <QApplication>
#include <QPalette>
#include <QStyle>
#include <QPaintEvent>
#include <QResizeEvent>
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
#include "owned_qimage.hpp"
#include "separate_threaded_renderer.hpp"
@ -21,15 +23,17 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
class RendererWidget : public _RendererWidget_Slots {
private:
QMutex sync;
OwnedQImage next_image;
OwnedQImage current_image;
OwnedQImage *next_image;
OwnedQImage *current_image;
_SeparateThreadedRenderer_Signals *renderer;
private slots:
void receive_image(OwnedQImage img) {
void receive_image(BGTU::ComputerGraphicsLabWork::QtUtilities::OwnedQImage *img) final {
this->sync.lock();
std::swap(this->next_image, img);
if (this->next_image != nullptr)
delete this->next_image;
this->next_image = img;
this->sync.unlock();
this->update();
}
@ -43,16 +47,26 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
protected:
void paintEvent(QPaintEvent *event) final {
this->sync.lock();
this->current_image = std::move(this->next_image);
if (this->next_image != nullptr) {
if (this->current_image != nullptr)
delete this->current_image;
this->current_image = this->next_image;
this->next_image = nullptr;
}
this->sync.unlock();
QPainter painter;
painter.begin(this);
painter.setPen(Qt::NoPen);
painter.setBrush(QApplication::style()->standardPalette().brush(QPalette::Background));
painter.drawRect(this->rect().x(), this->rect().y(), this->rect().width()-1, this->rect().height()-1);
painter.drawImage(this->current_image.rect(), this->current_image);
painter.drawRect(this->rect().x(), this->rect().y(), this->rect().width() - 1, this->rect().height() - 1);
if (this->current_image != nullptr)
painter.drawImage(this->current_image->rect(), *this->current_image);
painter.end();
}
void resizeEvent(QResizeEvent *event) override {
this->renderer->set_frame_size(event->size().width(), event->size().height());
}
};
}

View File

@ -15,10 +15,10 @@
#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::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
class SeparateThreadedRenderer : public _SeparateThreadedRenderer_Signals {
private:
struct data {
struct data_t {
public:
RendererApi::Sprite<sprite_data_t> *const *sprites;
std::size_t sprites_count;
@ -44,6 +44,10 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
this->intr.wakeAll();
}
void force_redraw() {
this->intr.wakeAll();
}
protected:
void run() final;
@ -57,7 +61,7 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
};
volatile data next_data;
volatile data_t next_data;
QMutex sync;
RendererThread *thread;
QImage *sentinel_img;
@ -67,9 +71,9 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
public slots:
void set_frame_size(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height);
void set_frame_size(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height) final;
void set_ms_per_frame(std::uint_fast64_t ms);
void set_ms_per_frame(std::uint_fast64_t ms) final;
void set_sprites(RendererApi::Sprite<sprite_data_t> *const *sprites, std::size_t sprites_count);
@ -77,14 +81,14 @@ 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);
void set_background(RendererApi::Color);
void set_background(RendererApi::Color) final;
public:
~SeparateThreadedRenderer();
};
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::SeparateThreadedRenderer(renderer_context_t *renderer_context, QObject *owner):
_SeparateThreadedRenderer_Signals{owner},
sync{},
@ -103,74 +107,81 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
this->thread->start();
}
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
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();
const_cast<data *>(&this->next_data)->width = width;
const_cast<data *>(&this->next_data)->height = height;
const_cast<data_t *>(&this->next_data)->width = width;
const_cast<data_t *>(&this->next_data)->height = height;
this->thread->force_redraw();
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_ms_per_frame(std::uint_fast64_t ms) {
this->sync.lock();
const_cast<data *>(&this->next_data)->ms_per_frame = ms;
const_cast<data_t *>(&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::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
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();
const_cast<data *>(&this->next_data)->sprites = sprites;
const_cast<data *>(&this->next_data)->sprites_count = sprites_count;
const_cast<data_t *>(&this->next_data)->sprites = sprites;
const_cast<data_t *>(&this->next_data)->sprites_count = sprites_count;
this->thread->force_redraw();
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_sprite_data(sprite_data_t const *sprite_data) {
this->sync.lock();
const_cast<data *>(&this->next_data)->sprite_data = sprite_data;
const_cast<data_t *>(&this->next_data)->sprite_data = sprite_data;
this->thread->force_redraw();
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
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 *sprite_data) {
this->sync.lock();
const_cast<data *>(&this->next_data)->sprites = sprites;
const_cast<data *>(&this->next_data)->sprites_count = sprites_count;
const_cast<data *>(&this->next_data)->sprite_data = sprite_data;
const_cast<data_t *>(&this->next_data)->sprites = sprites;
const_cast<data_t *>(&this->next_data)->sprites_count = sprites_count;
const_cast<data_t *>(&this->next_data)->sprite_data = sprite_data;
this->thread->force_redraw();
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_background(RendererApi::Color c) {
this->sync.lock();
const_cast<data *>(&this->next_data)->bg = c;
const_cast<data_t *>(&this->next_data)->bg = c;
this->thread->force_redraw();
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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::RendererThread::run() {
try {
QElapsedTimer timer;
while (!this->isInterruptionRequested()) {
timer.start();
this->owner->sync.lock();
data cached = *const_cast<data *>(&this->owner->next_data);
data_t cached = *const_cast<data_t *>(&this->owner->next_data);
this->owner->sync.unlock();
OwnedQImage img{cached.width, cached.height};
auto img = new OwnedQImage{cached.width, cached.height};
(this->owner->renderer_context->*renderer_procedure)(
cached.width, cached.height,
&img,
img,
cached.bg,
cached.projection,
cached.sprites, cached.sprites_count,
cached.sprite_data
);
emit this->owner->frame_rendered(img);
this->sleepms(std::max<std::uint_fast64_t>(cached.ms_per_frame - static_cast<std::uint_fast64_t>(timer.elapsed()), 0));
auto elapsed = timer.elapsed();
qCritical() << elapsed << "ms";
this->sleepms(std::max<std::int_fast64_t>(static_cast<std::int_fast64_t>(cached.ms_per_frame) - elapsed, 0));
}
} catch (std::exception const &e) {
qCritical() << typeid(e).name() << ": " << e.what() << "\n" << "Renderer thread died" << "\n";
@ -178,7 +189,7 @@ 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 *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t, sprite_data_t const *)>
template<class sprite_data_t, class renderer_context_t, _SeparateThreadedRenderer_RenderProcedureType<sprite_data_t, renderer_context_t> renderer_procedure>
SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::~SeparateThreadedRenderer() {
this->thread->requestInterruption();
this->thread->wait();

View File

@ -228,6 +228,10 @@ 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};
for (std::int_fast64_t i = w * h - 1; i >= 0; i--) {
new(&this->pixel_metadata_cache.buffer[i]) pixel_trace_metadata{};
}
for (; sprites_count-- > 0; sprites++) {
painter.current_artist = *sprites;
(*sprites)->draw(&painter, projection, sprite_data);
@ -237,15 +241,19 @@ 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) {
sorter.push_back(e);
this->sorter.push_back(e);
}
std::sort(sorter.rbegin(), sorter.rend(), [](ZElement *l, ZElement *r) { return l->z < r->z; });
std::sort(this->sorter.begin(), this->sorter.end(), [](ZElement *l, ZElement *r) { return l->z > r->z; });
RendererApi::Color p = bg;
for (auto a: sorter) {
for (auto a: this->sorter) {
p = apply_transparent_color(p, a->color);
}
frame->set_pixel(x, y, p, sorter[sorter.size() - 1]->owner);
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);
if (++x >= w) {
y++;

View File

@ -1,7 +1,8 @@
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
#include <algorithm>
#include <cstdlib>
#include <cassert>
#include <new>
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
#if defined(_WIN32)