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_shader_program_options(shader_compile_options& options, bool include_binding_points)
41 {
42 options.define_macro_if_not_default("MAX_FRAGMENTS", fragments_per_pixel, 32u);
43 if(include_binding_points) {
44 options.define_macro_if_not_default("NODE_COUNTER_BINDING_POINT", node_counter_binding_point, 0);
45 options.define_macro_if_not_default("HEAD_POINTERS_BINDING_POINT", head_pointers_binding_point, 0);
46 options.define_macro_if_not_default("NODES_BINDING_POINT", nodes_binding_point, 1);
47 }
48 }
49 void a_buffer::update_shader_program_options(shader_compile_options& options)
50 {
51 update_shader_program_options(options, true);
52 }
53 a_buffer::a_buffer(unsigned _fragments_per_pixel, unsigned _nodes_per_pixel, int _depth_tex_unit,
54 int _node_counter_binding_point, int _head_pointers_binding_point, int _nodes_binding_point)
55 : depth_tex("[D]")
56 {
57 depth_tex.set_min_filter(TF_NEAREST);
58 depth_tex.set_mag_filter(TF_NEAREST);
59 fragments_per_pixel = _fragments_per_pixel;
60 nodes_per_pixel = _nodes_per_pixel;
61 last_nodes_per_pixel = 0;
63 head_pointer_buffer = 0;
64 node_buffer = 0;
65
66 depth_tex_unit = _depth_tex_unit;
67 node_counter_binding_point = _node_counter_binding_point;
68 head_pointers_binding_point = _head_pointers_binding_point;
69 nodes_binding_point = _nodes_binding_point;
70
71 init_frame_called = false;
72 }
74 {
75 if (!clear_ssbo_prog.build_files(ctx, "a_buffer_clear", true))
76 return false;
77 update_shader_program_options(prog_options, false);
78 if (!a_buffer_prog.build_program(ctx, "a_buffer.glpr", prog_options, true))
79 return false;
80 last_prog_options = prog_options;
81 return true;
82 }
84 {
85 clear_ssbo_prog.destruct(ctx);
86 a_buffer_prog.destruct(ctx);
88 destruct_buffers(ctx);
89 }
91 {
92 // Ensure depth texture and node buffers of correct size
93 if (depth_tex.is_created() && (ctx.get_width() != depth_tex.get_width() || ctx.get_height() != depth_tex.get_height())) {
95 destruct_buffer(head_pointer_buffer);
96 destruct_buffer(node_buffer);
97 }
98 if (!depth_tex.is_created())
99 depth_tex.create(ctx, TT_2D, ctx.get_width(), ctx.get_height());
100 ensure_buffers(ctx);
101
102 // Clear the atomic counter
103 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, node_buffer_counter);
104 GLuint* ptr = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
105 memset(ptr, 0, sizeof(GLuint));
106 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
107 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
108
109 // Clear the head pointer buffer
110 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, head_pointer_buffer);
111 unsigned buffer_size = ctx.get_width() * ctx.get_height();
112 clear_ssbo_prog.enable(ctx);
113 clear_ssbo_prog.set_uniform(ctx, "size", buffer_size);
114 clear_ssbo_prog.set_uniform(ctx, "clear_value", -1);
115 glDispatchCompute(GLuint(ceil(buffer_size / 4)), 1, 1);
116 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
117 clear_ssbo_prog.disable(ctx);
118 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
119
120 // check for rebuild of program
121 update_shader_program_options(prog_options, false);
122 if (prog_options != last_prog_options) {
123 if (a_buffer_prog.is_created())
124 a_buffer_prog.destruct(ctx);
125 if (a_buffer_prog.build_program(ctx, "a_buffer.glpr", prog_options, true)) {
126 last_prog_options = prog_options;
127 std::cout << "a_buffer: rebuilt shader program" << std::endl;
128 }
129 }
130 init_frame_called = true;
131 }
132 bool a_buffer::enable(context& ctx, shader_program& prog, int tex_unit)
133 {
134 // in first call after init_frame, copy depth buffer to depth texture
135 if (init_frame_called) {
136 depth_tex.replace_from_buffer(ctx, 0, 0, 0, 0, ctx.get_width(), ctx.get_height());
137 init_frame_called = false;
138 }
139 // set program uniforms
140 if (!prog.set_uniform(ctx, "viewport_dims", ivec2(ctx.get_width(), ctx.get_height()))) {
141 std::cerr << "ERROR in a_buffer::enable(): uniform ivec2 viewport_dims not found in program." << std::endl;
142 return false;
143 }
144 if (!prog.set_uniform(ctx, "nodes_per_pixel", (int)nodes_per_pixel)) {
145 std::cerr << "ERROR in a_buffer::enable(): uniform int nodes_per_pixel not found in program." << std::endl;
146 return false;
147 }
148 // enable depth texture
149 if (tex_unit == -1)
150 tex_unit = depth_tex_unit;
151 depth_tex.enable(ctx, tex_unit);
152 if (!prog.set_uniform(ctx, "depth_tex", tex_unit)) {
153 std::cerr << "ERROR in a_buffer::enable(): uniform sampler2D depth_tex not found in program." << std::endl;
154 return false;
155 }
156 // Bind buffers for first a-buffer pass
157 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, node_counter_binding_point, node_buffer_counter);
158 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, head_pointers_binding_point, head_pointer_buffer);
159 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, nodes_binding_point, node_buffer);
160 return true;
161 }
162 // return current number of nodes in node buffer
164 {
165 // Unbind texture and buffers
166 depth_tex.disable(ctx);
167 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, node_counter_binding_point, 0);
168 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, head_pointers_binding_point, 0);
169 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, nodes_binding_point, 0);
170
171 // Clear atomic counter, read it back and use it as return value
172 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, node_buffer_counter);
173 GLuint* ptr = (GLuint*)glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
174 GLuint node_cnt = *ptr;
175 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
176 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
177 return node_cnt;
178 }
180 {
181 glEnable(GL_BLEND);
182 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
183
184 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, head_pointer_buffer);
185 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, node_buffer);
186
187 a_buffer_prog.enable(ctx);
188 a_buffer_prog.set_uniform(ctx, "viewport_dims", ivec2(ctx.get_width(), ctx.get_height()));
189 a_buffer_prog.set_uniform(ctx, "nodes_per_pixel", nodes_per_pixel);
190 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
191 a_buffer_prog.disable(ctx);
192
193 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
194 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
195
196 glDisable(GL_BLEND);
197 }
198 }
199}
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:27
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:53
unsigned fragments_per_pixel
to be handled fragments per pixel (changes are applied when in init_frame() function)
Definition a_buffer.h:51
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:53
void destruct(context &ctx)
destruct all render objects
Definition a_buffer.cxx:83
bool init(context &ctx)
construct internally used programs
Definition a_buffer.cxx:73
texture depth_tex
Depth texture used to emulate depth buffer.
Definition a_buffer.h:25
bool enable(context &ctx, shader_program &prog, int tex_unit=-1)
Enable writing fragments to a_buffer with provided program.
Definition a_buffer.cxx:132
int node_counter_binding_point
Buffer binding point indices.
Definition a_buffer.h:33
void init_frame(context &ctx)
ensure that a_buffer size corresponds to context size
Definition a_buffer.cxx:90
int depth_tex_unit
Default texture unit used for depth texture.
Definition a_buffer.h:31
void finish_frame(context &ctx)
per fragment sort nodes and blend over current framebuffer
Definition a_buffer.cxx:179
size_t disable(context &ctx)
finish writing fragments to a_buffer and return current number of nodes in node buffer
Definition a_buffer.cxx:163
base class for all drawables, which is independent of the used rendering API.
Definition context.h:627
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:2065
Stores preprocessor options used for conditionally compiling shader programs.
Definition shader_code.h:73
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
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