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);
92 if (!a_buffer_prog.build_program(ctx, "a_buffer.glpr", true, defines))
93 return false;
94 last_defines = defines;
95 return true;
96 }
98 {
99 clear_ssbo_prog.destruct(ctx);
100 a_buffer_prog.destruct(ctx);
101 depth_tex.destruct(ctx);
102 destruct_buffers(ctx);
103 }
105 {
106 // Ensure depth texture and node buffers of correct size
107 if (depth_tex.is_created() && (ctx.get_width() != depth_tex.get_width() || ctx.get_height() != depth_tex.get_height())) {
108 depth_tex.destruct(ctx);
109 destruct_buffer(head_pointer_buffer);
110 destruct_buffer(node_buffer);
111 }
112 if (!depth_tex.is_created())
113 depth_tex.create(ctx, TT_2D, ctx.get_width(), ctx.get_height());
114 ensure_buffers(ctx);
115
116 // Clear the atomic counter
117 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, node_buffer_counter);
118 GLuint* ptr = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
119 memset(ptr, 0, sizeof(GLuint));
120 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
121 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
122
123 // Clear the head pointer buffer
124 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, head_pointer_buffer);
125 unsigned buffer_size = ctx.get_width() * ctx.get_height();
126 clear_ssbo_prog.enable(ctx);
127 clear_ssbo_prog.set_uniform(ctx, "size", buffer_size);
128 clear_ssbo_prog.set_uniform(ctx, "clear_value", -1);
129 glDispatchCompute(GLuint(ceil(buffer_size / 4)), 1, 1);
130 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
131 clear_ssbo_prog.disable(ctx);
132 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
133
134 // check for rebuild of program
135 update_defines(defines, false);
136 if (defines != last_defines) {
137 if (a_buffer_prog.is_created())
138 a_buffer_prog.destruct(ctx);
139 if (a_buffer_prog.build_program(ctx, "a_buffer.glpr", true, defines)) {
140 last_defines = defines;
141 std::cout << "a_buffer: rebuilt shader program" << std::endl;
142 }
143 }
144 init_frame_called = true;
145 }
146 bool a_buffer::enable(context& ctx, shader_program& prog, int tex_unit)
147 {
148 // in first call after init_frame, copy depth buffer to depth texture
149 if (init_frame_called) {
150 depth_tex.replace_from_buffer(ctx, 0, 0, 0, 0, ctx.get_width(), ctx.get_height());
151 init_frame_called = false;
152 }
153 // set program uniforms
154 if (!prog.set_uniform(ctx, "viewport_dims", ivec2(ctx.get_width(), ctx.get_height()))) {
155 std::cerr << "ERROR in a_buffer::enable(): uniform ivec2 viewport_dims not found in program." << std::endl;
156 return false;
157 }
158 if (!prog.set_uniform(ctx, "nodes_per_pixel", (int)nodes_per_pixel)) {
159 std::cerr << "ERROR in a_buffer::enable(): uniform int nodes_per_pixel not found in program." << std::endl;
160 return false;
161 }
162 // enable depth texture
163 if (tex_unit == -1)
164 tex_unit = depth_tex_unit;
165 depth_tex.enable(ctx, tex_unit);
166 if (!prog.set_uniform(ctx, "depth_tex", tex_unit)) {
167 std::cerr << "ERROR in a_buffer::enable(): uniform sampler2D depth_tex not found in program." << std::endl;
168 return false;
169 }
170 // Bind buffers for first a-buffer pass
171 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, node_counter_binding_point, node_buffer_counter);
172 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, head_pointers_binding_point, head_pointer_buffer);
173 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, nodes_binding_point, node_buffer);
174 return true;
175 }
176 // return current number of nodes in node buffer
178 {
179 // Unbind texture and buffers
180 depth_tex.disable(ctx);
181 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, node_counter_binding_point, 0);
182 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, head_pointers_binding_point, 0);
183 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, nodes_binding_point, 0);
184
185 // Clear atomic counter, read it back and use it as return value
186 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, node_buffer_counter);
187 GLuint* ptr = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
188 GLuint node_cnt = *ptr;
189 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
190 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
191 return node_cnt;
192 }
194 {
195 glEnable(GL_BLEND);
196 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
197
198 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, head_pointer_buffer);
199 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, node_buffer);
200
201 a_buffer_prog.enable(ctx);
202 a_buffer_prog.set_uniform(ctx, "viewport_dims", ivec2(ctx.get_width(), ctx.get_height()));
203 a_buffer_prog.set_uniform(ctx, "nodes_per_pixel", nodes_per_pixel);
204 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
205 a_buffer_prog.disable(ctx);
206
207 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
208 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
209
210 glDisable(GL_BLEND);
211 }
212 }
213}
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:97
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:146
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:104
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:193
size_t disable(context &ctx)
finish writing fragments to a_buffer and return current number of nodes in node buffer
Definition a_buffer.cxx:177
base class for all drawables, which is independent of the used rendering API.
Definition context.h:621
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:2046
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_files(const context &ctx, const std::string &base_name, bool show_error=false, const shader_define_map &defines=shader_define_map())
successively calls create, attach_files and link.
bool build_program(const context &ctx, const std::string &file_name, bool show_error=false, const shader_define_map &defines=shader_define_map())
successively calls create, attach_program 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:694