-
Notifications
You must be signed in to change notification settings - Fork 1
/
framebuffer.h
104 lines (79 loc) · 3.21 KB
/
framebuffer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#include <vector>
#include <array>
#include <cstdio>
#include <thread>
#include <mutex>
#include <atomic>
#include <OpenGL/gl.h>
#include "types.h"
class Framebuffer
{
public:
Framebuffer();
virtual ~Framebuffer() { };
void Resize(uint width, uint height);
void Draw(uint x, uint y, uint width, uint height);
void SaveToBMP(const char *filename);
void StopRendering() { KillAllWorkerThreads(); }
void StartRendering();
protected:
uint m_width = 1;
uint m_height = 1;
volatile bool m_threads_stop = false; // Stop signal for the worker threads
class Tile
{
public:
Tile();
~Tile() { glDeleteTextures(1, &m_tex); }
// Minimal interface needed by implementors of RenderTile()
void GetPosition(uint& x0, uint& y0, uint& x1, uint& y1) const
{ x0 = m_x0; y0 = m_y0; x1 = m_x1; y1 = m_y1; }
uint GetWidth() const { return m_x1 - m_x0; }
uint GetHeight() const { return m_y1 - m_y0; }
uint32 * GetBuffer() { return &m_bgra[0]; }
protected:
// Hide most accessors from Framebuffer derived classes
friend class Framebuffer;
void SetPosition(uint x0, uint y0, uint x1, uint y1);
void Clear();
bool GetDirty() const { return m_dirty; }
void SetDirty(bool dirty) { m_dirty = dirty; }
GLuint GetTexture() { return m_tex; }
void UpdateTexture();
std::mutex& GetMutex() { return m_mtx; }
private:
std::mutex m_mtx; // Worker threads will lock while writing to buffer
GLuint m_tex = -1;
std::vector<uint32> m_bgra; // Buffer
bool m_dirty; // Does the texture different from the buffer?
uint m_x0;
uint m_y0;
uint m_x1;
uint m_y1;
};
// Override to provide actual rendering functionality
virtual void RenderTile(Tile& tile) = 0;
// Derived class needs to call this in its dtor. It's not enough if we do it, as
// RenderTile() called by the worker threads might access class state, which is
// already destroyed by the time our dtor runs
void KillAllWorkerThreads();
// Conservative, might actually have finished, call KillAllWorkerThreads() to be certain
bool WorkerThreadsRunning() const { return !m_threads.empty(); }
private:
std::vector<uint> m_work_queue; // Indices of tiles left to render
std::mutex m_work_queue_mtx; // Mutex to control work queue access
static const uint m_tiles_x = 12; // Tile layout and number of worker threads fixed
static const uint m_tiles_y = 9; // ...
const uint m_num_cpus; // ...
std::array<Tile, m_tiles_x * m_tiles_y> m_tiles;
Tile * GetNextTileFromQueue(); // Queried by WorkerThread()
void FillWorkQueue();
std::vector<std::thread> m_threads; // Array of worker threads
std::atomic<uint> m_threads_done; // Number of threads done
double m_render_start_time = 0.0; // Time at which the worker threads started rendering
void WorkerThread();
void CreateWorkerThreads();
};
#endif // FRAMEBUFFER_H