cgv
Loading...
Searching...
No Matches
a_buffer.cxx
1#include "a_buffer.h"
2
3namespace cgv {
4 namespace render {
5
6 void a_buffer::ensure_buffer(GLuint& buffer, GLenum target, GLsizeiptr size, const void* data, GLenum usage)
7 {
8 if (buffer == 0) {
9 glGenBuffers(1, &buffer);
10 glBindBuffer(target, buffer);
11 glBufferData(target, size, data, usage);
12 glBindBuffer(target, 0);
13 }
14 }
15
16 void a_buffer::destruct_buffer(GLuint& buffer)
17 {
18 if (buffer != 0) {
19 glDeleteBuffers(1, &buffer);
20 buffer = 0;
21 }
22 }
23 void a_buffer::destruct_buffers(context& ctx)
24 {
25 destruct_buffer(node_buffer_counter);
26 destruct_buffer(head_pointer_buffer);
27 destruct_buffer(node_buffer);
28 }
29 void a_buffer::ensure_buffers(context& ctx)
30 {
31 unsigned num_pixels = ctx.get_width() * ctx.get_height();
32 // Generate buffers for the a-buffer transparency implementation
33 ensure_buffer(node_buffer_counter, GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STATIC_DRAW); // atomic counter variable
34 ensure_buffer(head_pointer_buffer, GL_SHADER_STORAGE_BUFFER, num_pixels * sizeof(GLuint), NULL); // linked list head pointer buffer
35 if (node_buffer != 0 && last_nodes_per_pixel != nodes_per_pixel)
36 destruct_buffer(node_buffer);
37 ensure_buffer(node_buffer, GL_SHADER_STORAGE_BUFFER, nodes_per_pixel * 3 * num_pixels * sizeof(GLuint), NULL); // buffer to store linked list nodes, each with 3 32-bit values; reserve space for as much as 64 fragments per pixel
38 last_nodes_per_pixel = nodes_per_pixel;
39 }
40 void a_buffer::update_defines(shader_define_map& defines, bool include_binding_points)
41 {
42 if (fragments_per_pixel == 32)
43 defines.erase("MAX_FRAGMENTS");
44 else
45 defines["MAX_FRAGMENTS"] = cgv::utils::to_string(fragments_per_pixel);
46
47 if (!include_binding_points)
48 return;
49
51 defines.erase("NODE_COUNTER_BINDING_POINT");
52 else
53 defines["NODE_COUNTER_BINDING_POINT"] = cgv::utils::to_string(node_counter_binding_point);
54 if (head_pointers_binding_point == 0)
55 defines.erase("HEAD_POINTERS_BINDING_POINT");
56 else
57 defines["HEAD_POINTERS_BINDING_POINT"] = cgv::utils::to_string(head_pointers_binding_point);
58 if (nodes_binding_point == 1)
59 defines.erase("NODES_BINDING_POINT");
60 else
61 defines["NODES_BINDING_POINT"] = cgv::utils::to_string(nodes_binding_point);
62 }
63 void a_buffer::update_defines(shader_define_map& defines)
64 {
65 update_defines(defines, true);
66 }
67 a_buffer::a_buffer(unsigned _fragments_per_pixel, unsigned _nodes_per_pixel, int _depth_tex_unit,
68 int _node_counter_binding_point, int _head_pointers_binding_point, int _nodes_binding_point)
69 : depth_tex("[D]")
70 {
71 depth_tex.set_min_filter(TF_NEAREST);
72 depth_tex.set_mag_filter(TF_NEAREST);
73 fragments_per_pixel = _fragments_per_pixel;
74 nodes_per_pixel = _nodes_per_pixel;
75 last_nodes_per_pixel = 0;
77 head_pointer_buffer = 0;
78 node_buffer = 0;
79
80 depth_tex_unit = _depth_tex_unit;
81 node_counter_binding_point = _node_counter_binding_point;
82 head_pointers_binding_point = _head_pointers_binding_point;
83 nodes_binding_point = _nodes_binding_point;
84
85 init_frame_called = false;
86 }
88 {
89 if (!clear_ssbo_prog.build_files(ctx, "a_buffer_clear", true))
90 return false;
91 update_defines(defines, false);
93 options.defines = defines;
94 if (!a_buffer_prog.build_program(ctx, "a_buffer.glpr", options, true))
95 return false;
96 last_defines = defines;
97 return true;
98 }
100 {
101 clear_ssbo_prog.destruct(ctx);
102 a_buffer_prog.destruct(ctx);
103 depth_tex.destruct(ctx);
104 destruct_buffers(ctx);
105 }
107 {
108 // Ensure depth texture and node buffers of correct size
109 if (depth_tex.is_created() && (ctx.get_width() != depth_tex.get_width() || ctx.get_height() != depth_tex.get_height())) {
110 depth_tex.destruct(ctx);
111 destruct_buffer(head_pointer_buffer);
112 destruct_buffer(node_buffer);
113 }
114 if (!depth_tex.is_created())
115 depth_tex.create(ctx, TT_2D, ctx.get_width(), ctx.get_height());
116 ensure_buffers(ctx);
117
118 // Clear the atomic counter
119 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, node_buffer_counter);
120 GLuint* ptr = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
121 memset(ptr, 0, sizeof(GLuint));
122 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
123 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
124
125 // Clear the head pointer buffer
126 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, head_pointer_buffer);
127 unsigned buffer_size = ctx.get_width() * ctx.get_height();
128 clear_ssbo_prog.enable(ctx);
129 clear_ssbo_prog.set_uniform(ctx, "size", buffer_size);
130 clear_ssbo_prog.set_uniform(ctx, "clear_value", -1);
131 glDispatchCompute(GLuint(ceil(buffer_size / 4)), 1, 1);
132 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
133 clear_ssbo_prog.disable(ctx);
134 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
135
136 // check for rebuild of program
137 update_defines(defines, false);
138 if (defines != last_defines) {
139 if (a_buffer_prog.is_created())
140 a_buffer_prog.destruct(ctx);
142 options.defines = defines;
143 if (a_buffer_prog.build_program(ctx, "a_buffer.glpr", options, true)) {
144 last_defines = defines;
145 std::cout << "a_buffer: rebuilt shader program" << std::endl;
146 }
147 }
148 init_frame_called = true;
149 }
150 bool a_buffer::enable(context& ctx, shader_program& prog, int tex_unit)
151 {
152 // in first call after init_frame, copy depth buffer to depth texture
153 if (init_frame_called) {
154 depth_tex.replace_from_buffer(ctx, 0, 0, 0, 0, ctx.get_width(), ctx.get_height());
155 init_frame_called = false;
156 }
157 // set program uniforms
158 if (!prog.set_uniform(ctx, "viewport_dims", ivec2(ctx.get_width(), ctx.get_height()))) {
159 std::cerr << "ERROR in a_buffer::enable(): uniform ivec2 viewport_dims not found in program." << std::endl;
160 return false;
161 }
162 if (!prog.set_uniform(ctx, "nodes_per_pixel", (int)nodes_per_pixel)) {
163 std::cerr << "ERROR in a_buffer::enable(): uniform int nodes_per_pixel not found in program." << std::endl;
164 return false;
165 }
166 // enable depth texture
167 if (tex_unit == -1)
168 tex_unit = depth_tex_unit;
169 depth_tex.enable(ctx, tex_unit);
170 if (!prog.set_uniform(ctx, "depth_tex", tex_unit)) {
171 std::cerr << "ERROR in a_buffer::enable(): uniform sampler2D depth_tex not found in program." << std::endl;
172 return false;
173 }
174 // Bind buffers for first a-buffer pass
175 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, node_counter_binding_point, node_buffer_counter);
176 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, head_pointers_binding_point, head_pointer_buffer);
177 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, nodes_binding_point, node_buffer);
178 return true;
179 }
180 // return current number of nodes in node buffer
182 {
183 // Unbind texture and buffers
184 depth_tex.disable(ctx);
185 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, node_counter_binding_point, 0);
186 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, head_pointers_binding_point, 0);
187 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, nodes_binding_point, 0);
188
189 // Clear atomic counter, read it back and use it as return value
190 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, node_buffer_counter);
191 GLuint* ptr = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
192 GLuint node_cnt = *ptr;
193 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
194 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
195 return node_cnt;
196 }
198 {
199 glEnable(GL_BLEND);
200 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
201
202 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, head_pointer_buffer);
203 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, node_buffer);
204
205 a_buffer_prog.enable(ctx);
206 a_buffer_prog.set_uniform(ctx, "viewport_dims", ivec2(ctx.get_width(), ctx.get_height()));
207 a_buffer_prog.set_uniform(ctx, "nodes_per_pixel", nodes_per_pixel);
208 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
209 a_buffer_prog.disable(ctx);
210
211 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
212 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
213
214 glDisable(GL_BLEND);
215 }
216 }
217}
size_t get_width() const
return the resolution in the first dimension, or 1 if not defined
size_t get_height() const
return the resolution in the second dimension, or 1 if not defined
unsigned node_buffer_counter
Buffers used to store per pixel frament lists.
Definition a_buffer.h:25
unsigned nodes_per_pixel
to be reserved number of fragment nodes per pixel (changes are applied when in init_frame() function)
Definition a_buffer.h:51
unsigned fragments_per_pixel
to be handled fragments per pixel (changes are applied when in init_frame() function)
Definition a_buffer.h:49
a_buffer(unsigned _fragments_per_pixel=32, unsigned _nodes_per_pixel=64, int _depth_tex_unit=0, int _node_counter_binding_point=0, int _head_pointers_binding_point=0, int _nodes_binding_point=1)
construct and configure
Definition a_buffer.cxx:67
void destruct(context &ctx)
destruct all render objects
Definition a_buffer.cxx:99
bool init(context &ctx)
construct internally used programs
Definition a_buffer.cxx:87
texture depth_tex
Depth texture used to emulate depth buffer.
Definition a_buffer.h:23
bool enable(context &ctx, shader_program &prog, int tex_unit=-1)
Enable writing fragments to a_buffer with provided program.
Definition a_buffer.cxx:150
int node_counter_binding_point
Buffer binding point indices.
Definition a_buffer.h:31
void init_frame(context &ctx)
ensure that a_buffer size corresponds to context size
Definition a_buffer.cxx:106
int depth_tex_unit
Default texture unit used for depth texture.
Definition a_buffer.h:29
void finish_frame(context &ctx)
per fragment sort nodes and blend over current framebuffer
Definition a_buffer.cxx:197
size_t disable(context &ctx)
finish writing fragments to a_buffer and return current number of nodes in node buffer
Definition a_buffer.cxx:181
base class for all drawables, which is independent of the used rendering API.
Definition context.h:626
virtual unsigned int get_width() const =0
return the width of the window
virtual unsigned int get_height() const =0
return the height of the window
virtual bool is_created() const
return whether component has been created
Definition context.cxx:2050
a shader program combines several shader code fragments to a complete definition of the shading pipel...
bool enable(context &ctx)
enable the shader program
bool disable(context &ctx)
disable shader program and restore fixed functionality
bool set_uniform(const context &ctx, const std::string &name, const T &value, bool generate_error=false)
Set the value of a uniform by name, where the type can be any of int, unsigned, float,...
void destruct(const context &ctx)
destruct shader program
bool build_program(const context &ctx, const std::string &file_name, bool show_error=false)
successively calls create, attach_program and link.
bool build_files(const context &ctx, const std::string &base_name, bool show_error=false)
successively calls create, attach_files and link.
void set_mag_filter(TextureFilter _mag_filter)
set the magnification filter
Definition texture.cxx:138
bool create(const context &ctx, TextureType _tt=TT_UNDEF, unsigned width=-1, unsigned height=-1, unsigned depth=-1)
create the texture of dimension and resolution specified in the data format base class.
Definition texture.cxx:208
bool replace_from_buffer(const context &ctx, int x, int y, int x_buffer, int y_buffer, int width, int height, int level=-1)
replace a block within a 2d texture from the current read buffer.
Definition texture.cxx:667
bool disable(const context &ctx)
disable texture and restore state from before last enable call
Definition texture.cxx:756
bool enable(const context &ctx, int tex_unit=-1)
enable this texture in the given texture unit, -1 corresponds to the current unit.
Definition texture.cxx:745
bool destruct(const context &ctx)
destruct the texture and free texture memory and handle
Definition texture.cxx:730
void set_min_filter(TextureFilter _min_filter, float _anisotropy=2.0f)
set the minification filters, if minification is set to TF_ANISOTROP, the second floating point param...
Definition texture.cxx:120
std::map< std::string, std::string > shader_define_map
typedef for shader define map data structure
Definition shader_code.h:52
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
the cgv namespace
Definition print.h:11
cgv::math::fvec< int32_t, 2 > ivec2
declare type of 2d 32 bit integer vectors
Definition fvec.h:695
holds options applied before and during shader compilation, such as preprocessor defines and code sni...
Definition shader_code.h:87
shader_define_map defines
map of pre-processor define names to values
Definition shader_code.h:89