/
object_context.hpp
275 lines (190 loc) · 6.63 KB
/
object_context.hpp
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#ifndef OBJECT_CONTEXT_HPP_INCLUDED
#define OBJECT_CONTEXT_HPP_INCLUDED
#include <cl/cl.h>
#include <gl/glew.h>
#include <boost/compute/system.hpp>
#include <boost/compute/interop/opengl.hpp>
#include <set>
#include <mutex>
#include <atomic>
#include "texture_context.hpp"
#include <thread>
#include <SFML/System.hpp>
#include "cl_gl_interop_texture.hpp"
#include "async_read.hpp"
namespace compute = boost::compute;
struct objects_container;
struct obj_g_descriptor;
extern std::map<std::string, objects_container> object_cache;
template<typename T, int N>
struct n_buffer
{
T buffers[N];
///lets default initialise all the things, I hate uninitialised shit
n_buffer()
{
for(int i=0; i<N; i++)
{
buffers[i] = T();
}
}
int c = 0;
void flip()
{
c++;
c = c % N;
}
///I think this may be wrong, should it be idx + N - c?
T& operator[](std::size_t idx)
{
///0 is always the front buffer, 1 is always the next
return buffers[(idx + c) % N];
}
const T& operator[](std::size_t idx) const
{
return buffers[(idx + c) % N];
}
n_buffer& operator=(const n_buffer& other)
{
if(this == &other)
return *this;
for(int i=0; i<N; i++)
{
buffers[i] = other.buffers[i];
}
c = other.c;
return *this;
}
};
struct object_context;
struct object_context_data
{
cl_uint tri_num;
cl_uint obj_num;
cl_uint frame_id = 0; ///increase monotonically
cl_uint use_linear_rendering = 1;
cl_float4 c_pos_old{{0}};
cl_float4 c_rot_old{{0}};
compute::buffer g_tri_mem;
compute::buffer g_tri_num;
compute::buffer g_obj_desc;
compute::buffer g_obj_num;
///light memory is 100% not this classes responsibility, get light manager to handle that
compute::buffer g_light_mem;
compute::buffer g_light_num;
compute::buffer g_cut_tri_mem;
compute::buffer g_cut_tri_num;
//texture_gpu tex_gpu;
texture_context_data tex_gpu_ctx;
compute::buffer g_tid_buf_atomic_count;
compute::buffer g_tid_lightbuf_atomic_count;
n_buffer<cl_gl_interop_texture, 2> gl_screen;
n_buffer<compute::buffer, 2> depth_buffer;
compute::image2d g_id_screen_tex;
compute::buffer g_screen_normals_optional;
cl_float4 g_clear_col = (cl_float4){0};
cl_uint* cpu_id_num = nullptr;
cl_uint current_cpu_id_num = 0;
compute::buffer g_reflection_data;
//int dbuf = 0;
//int sbuf = 0;
/*compute::buffer pos[3];
compute::buffer vt[3];
compute::buffer norm[3];
compute::buffer object_ids;*/
///we want to use atomics for this really
volatile bool gpu_data_finished = false;
///necessary for stuff to know that the object context has changed
///and so to reflush its data to the gpu
static cl_uint gid;
cl_uint id = gid++;
int s_w = 0;
int s_h = 0;
unsigned int gl_framebuffer_id = -1;
int depth_buffer_width = 1;
int last_depth_buffer_width = 1;
bool has_valid_texture_data = false;
void ensure_screen_buffers(int _w, int _h, bool force = false);
void destroy_screen_buffers();
void swap_buffers();
void update_cpu_id_num();
///Warning: Dependent on the internal type of g_id_screen_tex
async_read<cl_int> read_id_tex(int x, int y);
bool use_experimental_reflections = false;
///see object_context
///this is going to get messy if all info that needs passing from object context to data
///goes like this, it might be better to scrap the external distinction... but then it is somewhat helpful
object_context* blend_render_context = nullptr;
};
struct object_temporaries
{
cl_uint object_g_id;
cl_uint gpu_tri_start;
cl_uint gpu_tri_end;
};
struct container_temporaries
{
cl_uint gpu_descriptor_id;
std::vector<object_temporaries> new_object_data;
int object_id;
};
///does not fill in texture data
///at the moment, manipulation container's object data (ie the subobjects) can result in incorrect behaviour
///if the order of the objects is swapped around, or a middle one is deleted etc
struct object_context
{
///we assume that this render context renders before us, and then we use its alpha information
///to blend with ourselves, thus skipping a kernel
object_context* blend_render_context = nullptr;
texture_context tex_ctx;
std::atomic_int rebuilding_async{0};
std::mutex rebuild_mutex;
std::deque<compute::event> rebuild_organise;
std::set<cl_uint> last_builds_tids;
std::vector<objects_container*> containers;
std::vector<container_temporaries> new_container_data;
std::thread build_async;
float future_time_ms = 20;
sf::Clock future_clock;
objects_container* make_new();
void destroy(objects_container* obj);
void load_active();
///this causes a gpu reallocation
void build(bool force = false, bool async = false, compute::event* async_render_event = nullptr);
void build_request();
void build_tick(bool async = false, compute::event* async_render_event = nullptr);
///this fetches the internal context data
object_context_data* fetch();
void set_clear_colour(const cl_float4& col);
void flush_locations(bool force = false, compute::event* render_event = nullptr); ///render event only necessarily for pipelining
///this is currently useless, as we'are always using a pointer to gpu_dat
///we're just duplicating the data ;_;
object_context_data gpu_dat;
object_context_data new_gpu_dat;
std::atomic<bool> ready_to_flip{false};
void flip();
int frames_since_flipped = 0;
static cl_uint gid;
void destroy_context_unrenewables();
void increment_context_id();
int get_context_id();
///if the context id has changed, everyone needs to reallocate their shit
int context_id = 0;
bool request_dirty = false;
///sets the number of depth buffers in one depth buffer plane
///ie if n == 2, we have two front buffers and two back buffers
void set_depth_buffer_width(int n);
int depth_buffer_width = 1;
int translate_gpu_o_id_to_container_offset(int o_id);
void enable_experimental_reflections();
void set_blend_render_context(object_context& other_ctx);
int get_approx_debug_cpu_memory_size();
void set_use_linear_rendering(cl_uint use_linaer);
cl_uint use_linear_rendering = 1;
private:
///so we can use write async
std::vector<obj_g_descriptor> object_descriptors;
bool use_experimental_reflections = false;
std::map<std::string, objects_container> object_cache;
};
#endif // OBJECT_CONTEXT_HPP_INCLUDED