1 | #include <fastuidraw/gl_backend/gl_get.hpp> |
2 | #include <fastuidraw/text/glyph_generate_params.hpp> |
3 | #include <fastuidraw/text/glyph_render_data_restricted_rays.hpp> |
4 | #include "sdl_painter_demo.hpp" |
5 | #include "text_helper.hpp" |
6 | |
7 | namespace |
8 | { |
9 | template<typename T> |
10 | class enum_wrapper |
11 | { |
12 | public: |
13 | explicit |
14 | enum_wrapper(T v): |
15 | m_v(v) |
16 | {} |
17 | |
18 | T m_v; |
19 | }; |
20 | |
21 | template<typename T> |
22 | enum_wrapper<T> |
23 | make_enum_wrapper(T v) |
24 | { |
25 | return enum_wrapper<T>(v); |
26 | } |
27 | |
28 | std::ostream& |
29 | operator<<(std::ostream &str, enum_wrapper<bool> b) |
30 | { |
31 | if (b.m_v) |
32 | { |
33 | str << "true" ; |
34 | } |
35 | else |
36 | { |
37 | str << "false" ; |
38 | } |
39 | return str; |
40 | } |
41 | |
42 | std::ostream& |
43 | operator<<(std::ostream &str, |
44 | enum_wrapper<enum fastuidraw::gl::PainterEngineGL::data_store_backing_t> v) |
45 | { |
46 | switch(v.m_v) |
47 | { |
48 | case fastuidraw::gl::PainterEngineGL::data_store_tbo: |
49 | str << "tbo" ; |
50 | break; |
51 | |
52 | case fastuidraw::gl::PainterEngineGL::data_store_ubo: |
53 | str << "ubo" ; |
54 | break; |
55 | |
56 | case fastuidraw::gl::PainterEngineGL::data_store_ssbo: |
57 | str << "ssbo" ; |
58 | break; |
59 | |
60 | default: |
61 | str << "invalid value" ; |
62 | } |
63 | |
64 | return str; |
65 | } |
66 | |
67 | std::ostream& |
68 | operator<<(std::ostream &str, |
69 | enum_wrapper<enum fastuidraw::gl::PainterEngineGL::clipping_type_t> v) |
70 | { |
71 | switch(v.m_v) |
72 | { |
73 | case fastuidraw::gl::PainterEngineGL::clipping_via_gl_clip_distance: |
74 | str << "on" ; |
75 | break; |
76 | |
77 | case fastuidraw::gl::PainterEngineGL::clipping_via_discard: |
78 | str << "off" ; |
79 | break; |
80 | |
81 | case fastuidraw::gl::PainterEngineGL::clipping_via_skip_color_write: |
82 | str << "emulate_skip_color_write" ; |
83 | break; |
84 | |
85 | default: |
86 | str << "invalid value" ; |
87 | } |
88 | |
89 | return str; |
90 | } |
91 | |
92 | std::ostream& |
93 | operator<<(std::ostream &str, |
94 | enum_wrapper<enum fastuidraw::glsl::PainterShaderRegistrarGLSL::fbf_blending_type_t> v) |
95 | { |
96 | switch(v.m_v) |
97 | { |
98 | case fastuidraw::glsl::PainterShaderRegistrarGLSL::fbf_blending_framebuffer_fetch: |
99 | str << "framebuffer_fetch" ; |
100 | break; |
101 | |
102 | case fastuidraw::glsl::PainterShaderRegistrarGLSL::fbf_blending_interlock: |
103 | str << "interlock" ; |
104 | break; |
105 | |
106 | case fastuidraw::glsl::PainterShaderRegistrarGLSL::fbf_blending_not_supported: |
107 | str << "none" ; |
108 | break; |
109 | |
110 | default: |
111 | str << "invalid value" ; |
112 | } |
113 | |
114 | return str; |
115 | } |
116 | |
117 | std::ostream& |
118 | operator<<(std::ostream &str, |
119 | enum_wrapper<enum fastuidraw::PainterBlendShader::shader_type> v) |
120 | { |
121 | switch (v.m_v) |
122 | { |
123 | case fastuidraw::PainterBlendShader::single_src: |
124 | str << "single_src" ; |
125 | break; |
126 | |
127 | case fastuidraw::PainterBlendShader::dual_src: |
128 | str << "dual_src" ; |
129 | break; |
130 | |
131 | case fastuidraw::PainterBlendShader::framebuffer_fetch: |
132 | str << "framebuffer_fetch" ; |
133 | break; |
134 | |
135 | default: |
136 | str << "invalid value" ; |
137 | } |
138 | return str; |
139 | } |
140 | |
141 | std::ostream& |
142 | operator<<(std::ostream &ostr, const fastuidraw::PainterShader::Tag &tag) |
143 | { |
144 | ostr << "(ID=" << tag.m_ID << ", group=" << tag.m_group << ")" ; |
145 | return ostr; |
146 | } |
147 | |
148 | void |
149 | print_glyph_shader_ids(const fastuidraw::PainterShaderRegistrar &rp, |
150 | const fastuidraw::PainterGlyphShader &sh) |
151 | { |
152 | for(unsigned int i = 0; i < sh.shader_count(); ++i) |
153 | { |
154 | enum fastuidraw::glyph_type tp; |
155 | tp = static_cast<enum fastuidraw::glyph_type>(i); |
156 | std::cout << "\t\t#" << i << ": " << sh.shader(tp)->tag(rp) << "\n" ; |
157 | } |
158 | } |
159 | |
160 | void |
161 | print_stroke_shader_ids(const fastuidraw::PainterShaderRegistrar &rp, |
162 | const fastuidraw::PainterStrokeShader &shader, |
163 | const std::string &prefix = "\t\t" ) |
164 | { |
165 | using namespace fastuidraw; |
166 | vecN<c_string, PainterStrokeShader::number_shader_types> shader_type_labels; |
167 | |
168 | shader_type_labels[PainterStrokeShader::non_aa_shader] = "non_aa_shader" ; |
169 | shader_type_labels[PainterStrokeShader::aa_shader] = "aa_shader" ; |
170 | |
171 | for (unsigned int tp = 0; tp < PainterEnums::stroking_method_number_precise_choices; ++tp) |
172 | { |
173 | enum PainterEnums::stroking_method_t e_tp; |
174 | |
175 | e_tp = static_cast<enum PainterEnums::stroking_method_t>(tp); |
176 | for (unsigned int sh = 0; sh < PainterStrokeShader::number_shader_types; ++sh) |
177 | { |
178 | enum PainterStrokeShader::shader_type_t e_sh; |
179 | |
180 | e_sh = static_cast<enum PainterStrokeShader::shader_type_t>(sh); |
181 | std::cout << prefix << "(" << PainterEnums::label(e_tp) |
182 | << ", " << shader_type_labels[e_sh] << "): " ; |
183 | |
184 | if (shader.shader(e_tp, e_sh)) |
185 | { |
186 | std::cout << shader.shader(e_tp, e_sh)->tag(rp); |
187 | } |
188 | else |
189 | { |
190 | std::cout << "null-shader" ; |
191 | } |
192 | std::cout << "\n" ; |
193 | } |
194 | } |
195 | } |
196 | |
197 | void |
198 | print_dashed_stroke_shader_ids(const fastuidraw::PainterShaderRegistrar &rp, |
199 | const fastuidraw::PainterDashedStrokeShaderSet &sh) |
200 | { |
201 | std::cout << "\t\tflat_caps:\n" ; |
202 | print_stroke_shader_ids(rp, sh.shader(fastuidraw::Painter::flat_caps), "\t\t\t" ); |
203 | |
204 | std::cout << "\t\trounded_caps:\n" ; |
205 | print_stroke_shader_ids(rp, sh.shader(fastuidraw::Painter::rounded_caps), "\t\t\t" ); |
206 | |
207 | std::cout << "\t\tsquare_caps:\n" ; |
208 | print_stroke_shader_ids(rp, sh.shader(fastuidraw::Painter::square_caps), "\t\t\t" ); |
209 | } |
210 | |
211 | GLuint |
212 | ready_pixel_counter_ssbo(unsigned int binding_index) |
213 | { |
214 | GLuint return_value(0); |
215 | uint32_t zero[2] = {0, 0}; |
216 | |
217 | fastuidraw_glGenBuffers(1, &return_value); |
218 | fastuidraw_glBindBuffer(GL_SHADER_STORAGE_BUFFER, return_value); |
219 | fastuidraw_glBufferData(GL_SHADER_STORAGE_BUFFER, 2 * sizeof(uint32_t), zero, GL_STREAM_READ); |
220 | fastuidraw_glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
221 | fastuidraw_glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding_index, return_value); |
222 | |
223 | return return_value; |
224 | } |
225 | |
226 | void |
227 | update_pixel_counts(GLuint bo, fastuidraw::vecN<uint64_t, 4> &dst) |
228 | { |
229 | const uint32_t *p; |
230 | |
231 | fastuidraw_glBindBuffer(GL_SHADER_STORAGE_BUFFER, bo); |
232 | p = (const uint32_t*)fastuidraw_glMapBufferRange(GL_SHADER_STORAGE_BUFFER, |
233 | 0, 2 * sizeof(uint32_t), GL_MAP_READ_BIT); |
234 | dst[sdl_painter_demo::frame_number_pixels] = p[0]; |
235 | dst[sdl_painter_demo::frame_number_pixels_that_neighbor_helper] = p[1]; |
236 | fastuidraw_glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
237 | fastuidraw_glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
238 | fastuidraw_glDeleteBuffers(1, &bo); |
239 | |
240 | dst[sdl_painter_demo::total_number_pixels] += dst[sdl_painter_demo::frame_number_pixels]; |
241 | dst[sdl_painter_demo::total_number_pixels_that_neighbor_helper] += dst[sdl_painter_demo::frame_number_pixels_that_neighbor_helper]; |
242 | } |
243 | } |
244 | |
245 | sdl_painter_demo:: |
246 | sdl_painter_demo(const std::string &about_text, |
247 | bool default_value_for_print_painter): |
248 | sdl_demo(about_text), |
249 | |
250 | m_image_atlas_options("Image Atlas Options" , *this), |
251 | m_log2_color_tile_size(m_image_atlas_params.log2_color_tile_size(), "log2_color_tile_size" , |
252 | "Specifies the log2 of the width and height of each color tile." , |
253 | *this), |
254 | m_log2_num_color_tiles_per_row_per_col(m_image_atlas_params.log2_num_color_tiles_per_row_per_col(), |
255 | "log2_num_color_tiles_per_row_per_col" , |
256 | "Specifies the log2 of the number of color tiles " |
257 | "in each row and column of each layer. Note that " |
258 | "then the total number of color tiles available " |
259 | "is given as num_color_layers*pow(2, 2*log2_num_color_tiles_per_row_per_col)" , |
260 | *this), |
261 | m_num_color_layers(m_image_atlas_params.num_color_layers(), "num_color_layers" , |
262 | "Specifies the number of layers in the color texture. Note that " |
263 | "then the total number of color tiles available is given as " |
264 | "num_color_layers*pow(2, 2*log2_num_color_tiles_per_row_per_col)" |
265 | "The number of layers grows to accomodate more images at the cost " |
266 | "of needing to move color data to new GL textures" , |
267 | *this), |
268 | m_log2_index_tile_size(m_image_atlas_params.log2_index_tile_size(), "log2_index_tile_size" , |
269 | "Specifies the log2 of the width and height of each index tile. " |
270 | "A negative value disables image atlasing" , |
271 | *this), |
272 | m_log2_num_index_tiles_per_row_per_col(m_image_atlas_params.log2_num_index_tiles_per_row_per_col(), |
273 | "log2_num_index_tiles_per_row_per_col" , |
274 | "Specifies the log2 of the number of index tiles " |
275 | "in each row and column of each layer; note that " |
276 | "then the total number of index tiles available " |
277 | "is given as num_index_layers*pow(2, 2*log2_num_index_tiles_per_row_per_col)" , |
278 | *this), |
279 | m_num_index_layers(m_image_atlas_params.num_index_layers(), "num_index_layers" , |
280 | "Specifies the intial number of layers in the index texture; " |
281 | "note that then the total number of index tiles initially available " |
282 | "is given as num_index_layers*pow(2, 2*log2_num_index_tiles_per_row_per_col) " |
283 | "The number of layers grows to accomodate more images at the cost " |
284 | "of needing to move index data to new GL textures" , |
285 | *this), |
286 | m_support_image_on_atlas(m_image_atlas_params.support_image_on_atlas(), |
287 | "enabled_image_atlas" , |
288 | "Specifies if image atlasing is enabled. When atlasing is disabled, " |
289 | "then a draw-call break is made on each different image used unless " |
290 | "bindless texturing is supported" , |
291 | *this), |
292 | |
293 | m_glyph_atlas_options("Glyph Atlas options" , *this), |
294 | m_glyph_atlas_size(m_glyph_atlas_params.number_floats(), |
295 | "glyph_atlas_size" , "size of glyph store in floats" , *this), |
296 | m_glyph_backing_store_type(glyph_backing_store_auto, |
297 | enumerated_string_type<enum glyph_backing_store_t>() |
298 | .add_entry("texture_buffer" , |
299 | glyph_backing_store_texture_buffer, |
300 | "use a texture buffer, feature is core in GL but for GLES requires version 3.2, " |
301 | "for GLES version pre-3.2, requires the extension GL_OES_texture_buffer or the " |
302 | "extension GL_EXT_texture_buffer" ) |
303 | .add_entry("texture_array" , |
304 | glyph_backing_store_texture_array, |
305 | "use a 2D texture array to store the glyph data, " |
306 | "GL and GLES have feature in core" ) |
307 | .add_entry("storage_buffer" , |
308 | glyph_backing_store_ssbo, |
309 | "use a shader storage buffer, feature is core starting in GLES 3.1 and available " |
310 | "in GL starting at version 4.2 or via the extension GL_ARB_shader_storage_buffer" ) |
311 | .add_entry("auto" , |
312 | glyph_backing_store_auto, |
313 | "query context and decide optimal value" ), |
314 | "geometry_backing_store_type" , |
315 | "Determines how the glyph store is backed." , |
316 | *this), |
317 | m_glyph_backing_texture_log2_w(10, "glyph_backing_texture_log2_w" , |
318 | "If glyph_backing_store_type is set to texture_array, then " |
319 | "this gives the log2 of the width of the texture array" , *this), |
320 | m_glyph_backing_texture_log2_h(10, "glyph_backing_texture_log2_h" , |
321 | "If glyph_backing_store_type is set to texture_array, then " |
322 | "this gives the log2 of the height of the texture array" , *this), |
323 | |
324 | m_colorstop_atlas_options("ColorStop Atlas options" , *this), |
325 | m_color_stop_atlas_width(m_colorstop_atlas_params.width(), |
326 | "colorstop_atlas_width" , |
327 | "width for color stop atlas" , *this), |
328 | m_color_stop_atlas_layers(m_colorstop_atlas_params.num_layers(), |
329 | "colorstop_atlas_layers" , |
330 | "number of layers for the color stop atlas" , |
331 | *this), |
332 | |
333 | m_painter_options("PainterBackendGL Options" , *this), |
334 | m_painter_attributes_per_buffer(m_painter_params.attributes_per_buffer(), |
335 | "painter_verts_per_buffer" , |
336 | "Number of vertices a single API draw can hold" , |
337 | *this), |
338 | m_painter_indices_per_buffer(m_painter_params.indices_per_buffer(), |
339 | "painter_indices_per_buffer" , |
340 | "Number of indices a single API draw can hold" , |
341 | *this), |
342 | m_painter_number_pools(m_painter_params.number_pools(), "painter_number_pools" , |
343 | "Number of GL object pools used by the painter" , *this), |
344 | m_painter_break_on_shader_change(m_painter_params.break_on_shader_change(), |
345 | "painter_break_on_shader_change" , |
346 | "If true, different shadings are placed into different " |
347 | "entries of a call to glMultiDrawElements" , *this), |
348 | m_uber_vert_use_switch(m_painter_params.vert_shader_use_switch(), |
349 | "painter_uber_vert_use_switch" , |
350 | "If true, use a switch statement in uber vertex shader dispatch" , |
351 | *this), |
352 | m_uber_frag_use_switch(m_painter_params.frag_shader_use_switch(), |
353 | "painter_uber_frag_use_switch" , |
354 | "If true, use a switch statement in uber fragment shader dispatch" , |
355 | *this), |
356 | m_use_uber_item_shader(m_painter_params.use_uber_item_shader(), |
357 | "painter_use_uber_item_shader" , |
358 | "If true, use an uber-shader for all item shaders" , |
359 | *this), |
360 | m_uber_blend_use_switch(m_painter_params.blend_shader_use_switch(), |
361 | "painter_uber_blend_use_switch" , |
362 | "If true, use a switch statement in uber blend shader dispatch" , |
363 | *this), |
364 | m_separate_program_for_discard(m_painter_params.separate_program_for_discard(), |
365 | "separate_program_for_discard" , |
366 | "if true, there are two GLSL programs active when drawing: " |
367 | "one for those item shaders that have discard and one for " |
368 | "those that do not" , |
369 | *this), |
370 | m_allow_bindless_texture_from_surface(m_painter_params.allow_bindless_texture_from_surface(), |
371 | "allow_bindless_texture_from_surface" , |
372 | "if both this is true and the GL/GLES driver supports " |
373 | "bindless texturing, the the textures of the surfaces " |
374 | "rendered to will be textured with bindless texturing" , |
375 | *this), |
376 | m_painter_options_affected_by_context("PainterBackendGL Options that can be overridden " |
377 | "by version and extension supported by GL/GLES context" , |
378 | *this), |
379 | m_use_hw_clip_planes(m_painter_params.clipping_type(), |
380 | enumerated_string_type<clipping_type_t>() |
381 | .add_entry("on" , fastuidraw::gl::PainterEngineGL::clipping_via_gl_clip_distance, |
382 | "Use HW clip planes via gl_ClipDistance for clipping" ) |
383 | .add_entry_alias("true" , fastuidraw::gl::PainterEngineGL::clipping_via_gl_clip_distance) |
384 | .add_entry("off" , fastuidraw::gl::PainterEngineGL::clipping_via_discard, |
385 | "Use discard in fragment shader for clipping" ) |
386 | .add_entry_alias("false" , fastuidraw::gl::PainterEngineGL::clipping_via_discard) |
387 | .add_entry("emulate_skip_color_write" , |
388 | fastuidraw::gl::PainterEngineGL::clipping_via_skip_color_write, |
389 | "Emulate by (virtually) skipping color writes, painter_blend_type " |
390 | "must be framebuffer_fetch" ), |
391 | "painter_use_hw_clip_planes" , |
392 | "" , |
393 | *this), |
394 | m_painter_data_blocks_per_buffer(m_painter_params.data_blocks_per_store_buffer(), |
395 | "painter_blocks_per_buffer" , |
396 | "Number of data blocks a single API draw can hold" , |
397 | *this), |
398 | m_data_store_backing(m_painter_params.data_store_backing(), |
399 | enumerated_string_type<data_store_backing_t>() |
400 | .add_entry("tbo" , |
401 | fastuidraw::gl::PainterEngineGL::data_store_tbo, |
402 | "use a texture buffer (if available) to back the data store. " |
403 | "A texture buffer can have a very large maximum size" ) |
404 | .add_entry("ubo" , |
405 | fastuidraw::gl::PainterEngineGL::data_store_ubo, |
406 | "use a uniform buffer object to back the data store. " |
407 | "A uniform buffer object's maximum size is much smaller than that " |
408 | "of a texture buffer object usually" ) |
409 | .add_entry("ssbo" , |
410 | fastuidraw::gl::PainterEngineGL::data_store_ssbo, |
411 | "use a shader storage buffer object to back the data store. " |
412 | "A shader storage buffer can have a very large maximum size" ), |
413 | "painter_data_store_backing_type" , |
414 | "specifies how the data store buffer is backed" , |
415 | *this), |
416 | m_assign_layout_to_vertex_shader_inputs(m_painter_params.assign_layout_to_vertex_shader_inputs(), |
417 | "painter_assign_layout_to_vertex_shader_inputs" , |
418 | "If true, use layout(location=) in GLSL shader for vertex shader inputs" , |
419 | *this), |
420 | m_assign_layout_to_varyings(m_painter_params.assign_layout_to_varyings(), |
421 | "painter_assign_layout_to_varyings" , |
422 | "If true, use layout(location=) in GLSL shader for varyings" , *this), |
423 | m_assign_binding_points(m_painter_params.assign_binding_points(), |
424 | "painter_assign_binding_points" , |
425 | "If true, use layout(binding=) in GLSL shader on samplers and buffers" , *this), |
426 | m_support_dual_src_blend_shaders(m_painter_params.support_dual_src_blend_shaders(), |
427 | "painter_support_dual_src_blending" , |
428 | "If true allow the painter to support dual src blend shaders" , *this), |
429 | m_preferred_blend_type(m_painter_params.preferred_blend_type(), |
430 | enumerated_string_type<shader_blend_type>() |
431 | .add_entry("single_src" , |
432 | fastuidraw::PainterBlendShader::single_src, |
433 | "Use single-source blending" ) |
434 | .add_entry("dual_src" , |
435 | fastuidraw::PainterBlendShader::dual_src, |
436 | "Use dual-source blending" ) |
437 | .add_entry("framebuffer_fetch" , |
438 | fastuidraw::PainterBlendShader::framebuffer_fetch, |
439 | "Use framebuffer-fetch or interlock, depending on the value of painter_fbf_blending_type" ), |
440 | "painter_preferred_blend_type" , |
441 | "Specifies how to implement all blend shader mode for all those except those " |
442 | "that cannot be performed with 3D API blending" , |
443 | *this), |
444 | m_fbf_blending_type(m_painter_params.fbf_blending_type(), |
445 | enumerated_string_type<fbf_blending_type_t>() |
446 | .add_entry("framebuffer_fetch" , |
447 | fastuidraw::glsl::PainterShaderRegistrarGLSL::fbf_blending_framebuffer_fetch, |
448 | "use a framebuffer fetch (if available) to perform blending, " |
449 | "that cannot be performed with 3D API blending" ) |
450 | .add_entry("interlock" , |
451 | fastuidraw::glsl::PainterShaderRegistrarGLSL::fbf_blending_interlock, |
452 | "use image-load store together with interlock (if both available) " |
453 | "to perform blending that cannot be performed with 3D API blending" ) |
454 | .add_entry("none" , |
455 | fastuidraw::glsl::PainterShaderRegistrarGLSL::fbf_blending_not_supported, |
456 | "Do not support the blend shaders that cannot be performed with 3D API blending" ), |
457 | "painter_fbf_blending_type" , |
458 | "specifies if/how the painter will perform blending for those blend shaders " |
459 | "that cannot be performed with 3D API blending" , |
460 | *this), |
461 | m_painter_optimal(painter_optimal_rendering, |
462 | enumerated_string_type<enum painter_optimal_t>() |
463 | .add_entry("painter_no_optimal" , |
464 | painter_no_optimal, |
465 | "Do not query GL/GLES context to configure options and rely " |
466 | "on the values passed to the command line. Values not possible " |
467 | "to do by the GL/GLES context will be overriden" ) |
468 | .add_entry("painter_optimal_performance" , |
469 | painter_optimal_performance, |
470 | "Query the GL/GLES context to configure options for optimal " |
471 | "performance. Additional options set by command line will " |
472 | "override the values" ) |
473 | .add_entry("painter_optimal_rendering" , |
474 | painter_optimal_rendering, |
475 | "Query the GL/GLES context to configure options for optimal " |
476 | "rendering quality. Additional options set by command line will " |
477 | "override the values" ), |
478 | "painter_optimal_auto" , |
479 | "Decide how to initially configure the Painter" , |
480 | *this), |
481 | m_demo_options("Demo Options" , *this), |
482 | m_print_painter_config(default_value_for_print_painter, |
483 | "print_painter_config" , |
484 | "Print PainterBackendGL config" , *this), |
485 | m_print_painter_shader_ids(default_value_for_print_painter, |
486 | "print_painter_shader_ids" , |
487 | "Print PainterBackendGL shader IDs" , *this), |
488 | m_pixel_counter_stack(-1, "pixel_counter_latency" , |
489 | "If non-negative, will add code to the painter ubder- shader " |
490 | "to count number of helper and non-helper pixels. The value " |
491 | "is how many frames to wait before reading the values from the " |
492 | "atomic buffers that are updated" , *this), |
493 | m_distance_field_pixel_size(fastuidraw::GlyphGenerateParams::distance_field_pixel_size(), |
494 | "glyph_distance_field_pixel_size" , |
495 | "Pixel size at which to generate distance field glyphs" , |
496 | *this), |
497 | m_distance_field_max_distance(fastuidraw::GlyphGenerateParams::distance_field_max_distance(), |
498 | "glyph_distance_field_max_distance" , |
499 | "Max distance value in pixels to use when generating " |
500 | "distance field glyphs; the texels of a distance field " |
501 | "glyph are always stored in fixed point 8-bits normalized " |
502 | "to [0,1]. This field gives the clamping and conversion " |
503 | "to [0,1]" , *this), |
504 | m_restricted_rays_max_recursion(fastuidraw::GlyphGenerateParams::restricted_rays_max_recursion(), |
505 | "glyph_restricted_rays_max_recursion" , |
506 | "Maximum level of recursion used when creating restricted rays glyphs" , |
507 | *this), |
508 | m_restricted_rays_split_thresh(fastuidraw::GlyphGenerateParams::restricted_rays_split_thresh(), |
509 | "glyph_restricted_rays_split_thresh" , |
510 | "Splitting threshhold used when creating restricted rays glyphs" , |
511 | *this), |
512 | m_restricted_rays_expected_min_render_size(fastuidraw::GlyphGenerateParams::restricted_rays_minimum_render_size(), |
513 | "glyph_restricted_rays_expected_min_render_size" , |
514 | "" , |
515 | *this), |
516 | m_banded_rays_max_recursion(fastuidraw::GlyphGenerateParams::banded_rays_max_recursion(), |
517 | "glyph_banded_rays_max_recursion" , |
518 | "Maximum level of recursion to use when generating banded-ray glyphs" , |
519 | *this), |
520 | m_banded_rays_average_number_curves_thresh(fastuidraw::GlyphGenerateParams::banded_rays_average_number_curves_thresh(), |
521 | "glyph_banded_rays_average_number_curves_thresh" , |
522 | "Threshhold to aim for number of curves per band when generating " |
523 | "banded-ray glyphs" , |
524 | *this), |
525 | m_num_pixel_counter_buffers(0), |
526 | m_pixel_counts(0, 0, 0, 0), |
527 | m_painter_stats(fastuidraw::Painter::number_stats(), 0) |
528 | {} |
529 | |
530 | sdl_painter_demo:: |
531 | ~sdl_painter_demo() |
532 | { |
533 | for (GLuint bo : m_pixel_counter_buffers) |
534 | { |
535 | fastuidraw_glDeleteBuffers(1, &bo); |
536 | } |
537 | } |
538 | |
539 | void |
540 | sdl_painter_demo:: |
541 | init_gl(int w, int h) |
542 | { |
543 | int max_layers(0); |
544 | |
545 | max_layers = fastuidraw::gl::context_get<GLint>(GL_MAX_ARRAY_TEXTURE_LAYERS); |
546 | if (max_layers < m_num_color_layers.value()) |
547 | { |
548 | std::cout << "num_color_layers exceeds max number texture layers (" << max_layers |
549 | << "), num_color_layers set to that value.\n" ; |
550 | m_num_color_layers.value() = max_layers; |
551 | } |
552 | |
553 | if (max_layers < m_color_stop_atlas_layers.value()) |
554 | { |
555 | std::cout << "atlas_layers exceeds max number texture layers (" << max_layers |
556 | << "), atlas_layers set to that value.\n" ; |
557 | m_color_stop_atlas_layers.value() = max_layers; |
558 | } |
559 | |
560 | if (m_painter_optimal.value() != painter_no_optimal) |
561 | { |
562 | m_painter_params.configure_from_context(m_painter_optimal.value() == painter_optimal_rendering); |
563 | } |
564 | |
565 | #define APPLY_PARAM(X, Y) do { \ |
566 | if (Y.set_by_command_line()) \ |
567 | { \ |
568 | std::cout << "Apply: "#X": " << Y.value() \ |
569 | << "\n"; m_painter_params.X(Y.value()); \ |
570 | } \ |
571 | } while (0) |
572 | |
573 | APPLY_PARAM(attributes_per_buffer, m_painter_attributes_per_buffer); |
574 | APPLY_PARAM(indices_per_buffer, m_painter_indices_per_buffer); |
575 | APPLY_PARAM(data_blocks_per_store_buffer, m_painter_data_blocks_per_buffer); |
576 | APPLY_PARAM(number_pools, m_painter_number_pools); |
577 | APPLY_PARAM(break_on_shader_change, m_painter_break_on_shader_change); |
578 | APPLY_PARAM(clipping_type, m_use_hw_clip_planes); |
579 | APPLY_PARAM(vert_shader_use_switch, m_uber_vert_use_switch); |
580 | APPLY_PARAM(frag_shader_use_switch, m_uber_frag_use_switch); |
581 | APPLY_PARAM(blend_shader_use_switch, m_uber_blend_use_switch); |
582 | APPLY_PARAM(data_store_backing, m_data_store_backing); |
583 | APPLY_PARAM(assign_layout_to_vertex_shader_inputs, m_assign_layout_to_vertex_shader_inputs); |
584 | APPLY_PARAM(assign_layout_to_varyings, m_assign_layout_to_varyings); |
585 | APPLY_PARAM(assign_binding_points, m_assign_binding_points); |
586 | APPLY_PARAM(separate_program_for_discard, m_separate_program_for_discard); |
587 | APPLY_PARAM(allow_bindless_texture_from_surface, m_allow_bindless_texture_from_surface); |
588 | APPLY_PARAM(preferred_blend_type, m_preferred_blend_type); |
589 | APPLY_PARAM(fbf_blending_type, m_fbf_blending_type); |
590 | APPLY_PARAM(support_dual_src_blend_shaders, m_support_dual_src_blend_shaders); |
591 | APPLY_PARAM(use_uber_item_shader, m_use_uber_item_shader); |
592 | |
593 | #undef APPLY_PARAM |
594 | |
595 | #define APPLY_IMAGE_PARAM(X, Y) do { \ |
596 | if (Y.set_by_command_line()) \ |
597 | { \ |
598 | std::cout << "Apply: "#X": " << Y.value() \ |
599 | << "\n"; m_image_atlas_params.X(Y.value()); \ |
600 | } \ |
601 | } while (0) |
602 | |
603 | m_image_atlas_params = m_painter_params.image_atlas_params(); |
604 | APPLY_IMAGE_PARAM(log2_color_tile_size, m_log2_color_tile_size); |
605 | APPLY_IMAGE_PARAM(log2_num_color_tiles_per_row_per_col, m_log2_num_color_tiles_per_row_per_col); |
606 | APPLY_IMAGE_PARAM(num_color_layers, m_num_color_layers); |
607 | APPLY_IMAGE_PARAM(log2_index_tile_size, m_log2_index_tile_size); |
608 | APPLY_IMAGE_PARAM(log2_num_index_tiles_per_row_per_col, m_log2_num_index_tiles_per_row_per_col); |
609 | APPLY_IMAGE_PARAM(num_index_layers, m_num_index_layers); |
610 | APPLY_IMAGE_PARAM(support_image_on_atlas, m_support_image_on_atlas); |
611 | |
612 | #undef APPLY_IMAGE_PARAM |
613 | |
614 | m_glyph_atlas_params = m_painter_params.glyph_atlas_params(); |
615 | m_glyph_atlas_params.number_floats(m_glyph_atlas_size.value()); |
616 | switch(m_glyph_backing_store_type.value()) |
617 | { |
618 | case glyph_backing_store_texture_buffer: |
619 | m_glyph_atlas_params.use_texture_buffer_store(); |
620 | break; |
621 | |
622 | case glyph_backing_store_texture_array: |
623 | m_glyph_atlas_params.use_texture_2d_array_store(m_glyph_backing_texture_log2_w.value(), |
624 | m_glyph_backing_texture_log2_h.value()); |
625 | break; |
626 | |
627 | case glyph_backing_store_ssbo: |
628 | m_glyph_atlas_params.use_storage_buffer_store(); |
629 | break; |
630 | |
631 | default: |
632 | m_glyph_atlas_params.use_optimal_store_backing(); |
633 | switch(m_glyph_atlas_params.glyph_data_backing_store_type()) |
634 | { |
635 | case fastuidraw::glsl::PainterShaderRegistrarGLSL::glyph_data_tbo: |
636 | { |
637 | std::cout << "Glyph Store: auto selected texture buffer\n" ; |
638 | } |
639 | break; |
640 | |
641 | case fastuidraw::glsl::PainterShaderRegistrarGLSL::glyph_data_ssbo: |
642 | { |
643 | std::cout << "Glyph Store: auto selected storage buffer\n" ; |
644 | } |
645 | break; |
646 | |
647 | case fastuidraw::glsl::PainterShaderRegistrarGLSL::glyph_data_texture_array: |
648 | { |
649 | fastuidraw::ivec2 log2_dims(m_glyph_atlas_params.texture_2d_array_store_log2_dims()); |
650 | std::cout << "Glyph Store: auto selected texture with dimensions: (2^" |
651 | << log2_dims.x() << ", 2^" << log2_dims.y() << ") = " |
652 | << fastuidraw::ivec2(1 << log2_dims.x(), 1 << log2_dims.y()) |
653 | << "\n" ; |
654 | } |
655 | break; |
656 | } |
657 | } |
658 | |
659 | m_colorstop_atlas_params = m_painter_params.colorstop_atlas_params(); |
660 | m_colorstop_atlas_params |
661 | .width(m_color_stop_atlas_width.value()) |
662 | .num_layers(m_color_stop_atlas_layers.value()); |
663 | |
664 | if (!m_color_stop_atlas_width.set_by_command_line()) |
665 | { |
666 | m_colorstop_atlas_params.optimal_width(); |
667 | std::cout << "Colorstop Atlas optimal width selected to be " |
668 | << m_colorstop_atlas_params.width() << "\n" ; |
669 | } |
670 | |
671 | m_painter_params |
672 | .image_atlas_params(m_image_atlas_params) |
673 | .glyph_atlas_params(m_glyph_atlas_params) |
674 | .colorstop_atlas_params(m_colorstop_atlas_params); |
675 | |
676 | if (m_pixel_counter_stack.value() >= 0) |
677 | { |
678 | fastuidraw::c_string version; |
679 | #ifdef FASTUIDRAW_GL_USE_GLES |
680 | { |
681 | version = "310 es" ; |
682 | } |
683 | #else |
684 | { |
685 | version = "450" ; |
686 | } |
687 | #endif |
688 | m_painter_params.glsl_version_override(version); |
689 | } |
690 | |
691 | m_backend = fastuidraw::gl::PainterEngineGL::create(m_painter_params); |
692 | |
693 | fastuidraw::GlyphGenerateParams::distance_field_max_distance(m_distance_field_max_distance.value()); |
694 | fastuidraw::GlyphGenerateParams::distance_field_pixel_size(m_distance_field_pixel_size.value()); |
695 | fastuidraw::GlyphGenerateParams::restricted_rays_max_recursion(m_restricted_rays_max_recursion.value()); |
696 | fastuidraw::GlyphGenerateParams::restricted_rays_split_thresh(m_restricted_rays_split_thresh.value()); |
697 | fastuidraw::GlyphGenerateParams::restricted_rays_minimum_render_size(m_restricted_rays_expected_min_render_size.value()); |
698 | fastuidraw::GlyphGenerateParams::banded_rays_max_recursion(m_banded_rays_max_recursion.value()); |
699 | fastuidraw::GlyphGenerateParams::banded_rays_average_number_curves_thresh(m_banded_rays_average_number_curves_thresh.value()); |
700 | |
701 | m_painter = FASTUIDRAWnew fastuidraw::Painter(m_backend); |
702 | m_font_database = FASTUIDRAWnew fastuidraw::FontDatabase(); |
703 | m_ft_lib = FASTUIDRAWnew fastuidraw::FreeTypeLib(); |
704 | |
705 | if (m_pixel_counter_stack.value() >= 0) |
706 | { |
707 | fastuidraw::c_string code; |
708 | fastuidraw::reference_counted_ptr<fastuidraw::glsl::PainterShaderRegistrarGLSL> R; |
709 | |
710 | m_pixel_counter_buffer_binding_index = fastuidraw::gl::context_get<GLint>(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS) - 1; |
711 | code = |
712 | "layout(binding = PIXEL_COUNTER_BINDING) buffer pixel_counter_buffer\n" |
713 | "{\n" |
714 | "\tuint num_pixels;\n" |
715 | "\tuint num_neighbor_helper_pixels;\n" |
716 | "};\n" |
717 | "void real_main(void);\n" |
718 | "void main(void)\n" |
719 | "{\n" |
720 | "\tfloat f;\n" |
721 | "\tf = float(gl_HelperInvocation);\n" |
722 | "\tatomicAdd(num_pixels, 1u);\n" |
723 | "\tif(abs(dFdxFine(f)) > 0.0 || abs(dFdyFine(f)) > 0.0)\n" |
724 | "\t\tatomicAdd(num_neighbor_helper_pixels, 1u);\n" |
725 | "\treal_main();\n" |
726 | "}\n" ; |
727 | |
728 | R = static_cast<fastuidraw::glsl::PainterShaderRegistrarGLSL*>(&m_painter->painter_shader_registrar()); |
729 | R->add_fragment_shader_util(fastuidraw::glsl::ShaderSource() |
730 | .add_macro("PIXEL_COUNTER_BINDING" , m_pixel_counter_buffer_binding_index) |
731 | .add_source(code, fastuidraw::glsl::ShaderSource::from_string) |
732 | .add_macro("main" , "real_main" )); |
733 | } |
734 | |
735 | if (m_print_painter_config.value()) |
736 | { |
737 | std::cout << "\nPainterBackendGL configuration:\n" ; |
738 | |
739 | #define LAZY_PARAM(X, Y) do { \ |
740 | std::cout << std::setw(40) << Y.name() << ": " << std::setw(8) \ |
741 | << m_backend->configuration_gl().X() \ |
742 | << " (requested " << m_painter_params.X() << ")\n"; \ |
743 | } while(0) |
744 | |
745 | #define LAZY_IMAGE_PARAM(X, Y) do { \ |
746 | std::cout << std::setw(40) << Y.name() << ": " << std::setw(8) \ |
747 | << m_backend->configuration_gl().image_atlas_params().X() \ |
748 | << " (requested " << m_painter_params.image_atlas_params().X() << ")\n"; \ |
749 | } while(0) |
750 | |
751 | #define LAZY_PARAM_ENUM(X, Y) do { \ |
752 | std::cout << std::setw(40) << Y.name() <<": " << std::setw(8) \ |
753 | << make_enum_wrapper(m_backend->configuration_gl().X()) \ |
754 | << " (requested " << make_enum_wrapper(m_painter_params.X()) \ |
755 | << ")\n"; \ |
756 | } while(0) |
757 | |
758 | #define LAZY_IMAGE_PARAM_ENUM(X, Y) do { \ |
759 | std::cout << std::setw(40) << Y.name() <<": " << std::setw(8) \ |
760 | << make_enum_wrapper(m_backend->configuration_gl().image_atlas_params().X()) \ |
761 | << " (requested " << make_enum_wrapper(m_painter_params.image_atlas_params().X()) \ |
762 | << ")\n"; \ |
763 | } while(0) |
764 | |
765 | LAZY_PARAM(attributes_per_buffer, m_painter_attributes_per_buffer); |
766 | LAZY_PARAM(indices_per_buffer, m_painter_indices_per_buffer); |
767 | LAZY_PARAM(data_blocks_per_store_buffer, m_painter_data_blocks_per_buffer); |
768 | LAZY_PARAM(number_pools, m_painter_number_pools); |
769 | LAZY_PARAM_ENUM(break_on_shader_change, m_painter_break_on_shader_change); |
770 | LAZY_PARAM_ENUM(clipping_type, m_use_hw_clip_planes); |
771 | LAZY_PARAM_ENUM(vert_shader_use_switch, m_uber_vert_use_switch); |
772 | LAZY_PARAM_ENUM(frag_shader_use_switch, m_uber_frag_use_switch); |
773 | LAZY_PARAM(use_uber_item_shader, m_use_uber_item_shader); |
774 | LAZY_PARAM_ENUM(blend_shader_use_switch, m_uber_blend_use_switch); |
775 | LAZY_PARAM_ENUM(data_store_backing, m_data_store_backing); |
776 | LAZY_PARAM_ENUM(assign_layout_to_vertex_shader_inputs, m_assign_layout_to_vertex_shader_inputs); |
777 | LAZY_PARAM_ENUM(assign_layout_to_varyings, m_assign_layout_to_varyings); |
778 | LAZY_PARAM_ENUM(assign_binding_points, m_assign_binding_points); |
779 | LAZY_PARAM_ENUM(separate_program_for_discard, m_separate_program_for_discard); |
780 | LAZY_PARAM_ENUM(allow_bindless_texture_from_surface, m_allow_bindless_texture_from_surface); |
781 | LAZY_PARAM_ENUM(preferred_blend_type, m_preferred_blend_type); |
782 | LAZY_PARAM_ENUM(fbf_blending_type, m_fbf_blending_type); |
783 | LAZY_PARAM_ENUM(support_dual_src_blend_shaders, m_support_dual_src_blend_shaders); |
784 | std::cout << std::setw(40) << "geometry_backing_store_type:" |
785 | << std::setw(8) << m_painter_params.glyph_atlas_params().glyph_data_backing_store_type() |
786 | << "\n" ; |
787 | LAZY_IMAGE_PARAM_ENUM(support_image_on_atlas, m_support_image_on_atlas); |
788 | if (m_backend->configuration_gl().image_atlas_params().support_image_on_atlas()) |
789 | { |
790 | LAZY_IMAGE_PARAM(log2_color_tile_size, m_log2_color_tile_size); |
791 | LAZY_IMAGE_PARAM(log2_num_color_tiles_per_row_per_col, m_log2_num_color_tiles_per_row_per_col); |
792 | LAZY_IMAGE_PARAM(num_color_layers, m_num_color_layers); |
793 | LAZY_IMAGE_PARAM(log2_index_tile_size, m_log2_index_tile_size); |
794 | LAZY_IMAGE_PARAM(log2_num_index_tiles_per_row_per_col, m_log2_num_index_tiles_per_row_per_col); |
795 | LAZY_IMAGE_PARAM(num_index_layers, m_num_index_layers); |
796 | } |
797 | |
798 | #undef LAZY_PARAM |
799 | #undef LAZY_IMAGE_PARAM |
800 | #undef LAZY_ENUM_PARAM |
801 | } |
802 | |
803 | if (m_print_painter_shader_ids.value()) |
804 | { |
805 | const fastuidraw::PainterShaderSet &sh(m_painter->default_shaders()); |
806 | const fastuidraw::PainterShaderRegistrar &rp(m_backend->painter_shader_registrar()); |
807 | std::cout << "Default shader IDs:\n" ; |
808 | |
809 | std::cout << "\tGlyph Shaders:\n" ; |
810 | print_glyph_shader_ids(rp, sh.glyph_shader()); |
811 | |
812 | std::cout << "\tSolid StrokeShaders:\n" ; |
813 | print_stroke_shader_ids(rp, sh.stroke_shader()); |
814 | |
815 | std::cout << "\tDashed Stroke Shader:\n" ; |
816 | print_dashed_stroke_shader_ids(rp, sh.dashed_stroke_shader()); |
817 | |
818 | std::cout << "\tFill Shader:" |
819 | << sh.fill_shader().item_shader()->tag(rp) << "\n" ; |
820 | } |
821 | |
822 | m_painter_params = m_backend->configuration_gl(); |
823 | on_resize(w, h); |
824 | derived_init(w, h); |
825 | } |
826 | |
827 | void |
828 | sdl_painter_demo:: |
829 | on_resize(int w, int h) |
830 | { |
831 | fastuidraw::ivec2 wh(w, h); |
832 | if (!m_surface || wh != m_surface->dimensions()) |
833 | { |
834 | fastuidraw::PainterSurface::Viewport vwp(0, 0, w, h); |
835 | |
836 | m_surface = FASTUIDRAWnew fastuidraw::gl::PainterSurfaceGL(fastuidraw::ivec2(w, h), *m_backend); |
837 | m_surface->viewport(vwp); |
838 | } |
839 | } |
840 | |
841 | void |
842 | sdl_painter_demo:: |
843 | draw_text(const std::string &text, float pixel_size, |
844 | const fastuidraw::FontBase *font, |
845 | fastuidraw::GlyphRenderer renderer, |
846 | const fastuidraw::PainterData &draw, |
847 | enum fastuidraw::Painter::screen_orientation orientation) |
848 | { |
849 | std::istringstream str(text); |
850 | fastuidraw::GlyphRun run(pixel_size, orientation, m_painter->glyph_cache()); |
851 | |
852 | create_formatted_text(run, orientation, str, font, m_font_database); |
853 | m_painter->draw_glyphs(draw, run, 0, run.number_glyphs(), renderer); |
854 | } |
855 | |
856 | void |
857 | sdl_painter_demo:: |
858 | pre_draw_frame(void) |
859 | { |
860 | if (m_pixel_counter_stack.value() >= 0) |
861 | { |
862 | GLuint bo; |
863 | |
864 | bo = ready_pixel_counter_ssbo(m_pixel_counter_buffer_binding_index); |
865 | m_pixel_counter_buffers.push_back(bo); |
866 | ++m_num_pixel_counter_buffers; |
867 | } |
868 | } |
869 | |
870 | void |
871 | sdl_painter_demo:: |
872 | post_draw_frame(void) |
873 | { |
874 | if (m_pixel_counter_stack.value() >= 0 |
875 | && m_num_pixel_counter_buffers > m_pixel_counter_stack.value()) |
876 | { |
877 | GLuint bo; |
878 | |
879 | bo = m_pixel_counter_buffers.front(); |
880 | update_pixel_counts(bo, m_pixel_counts); |
881 | |
882 | m_pixel_counter_buffers.pop_front(); |
883 | --m_num_pixel_counter_buffers; |
884 | } |
885 | m_painter->query_stats(cast_c_array(m_painter_stats)); |
886 | } |
887 | |