1 #include <wayfire/util/log.hpp>
2 #include <map>
3 #include "opengl-priv.hpp"
4 #include "wayfire/output.hpp"
5 #include "core-impl.hpp"
6 #include "config.h"
7 #include <wayfire/nonstd/wlroots-full.hpp>
8
9 #include <glm/gtc/matrix_transform.hpp>
10
11 #include "shaders.tpp"
12
gl_error_string(const GLenum err)13 const char *gl_error_string(const GLenum err)
14 {
15 switch (err)
16 {
17 case GL_INVALID_ENUM:
18 return "GL_INVALID_ENUM";
19
20 case GL_INVALID_VALUE:
21 return "GL_INVALID_VALUE";
22
23 case GL_INVALID_OPERATION:
24 return "GL_INVALID_OPERATION";
25
26 case GL_OUT_OF_MEMORY:
27 return "GL_OUT_OF_MEMORY";
28 }
29
30 return "UNKNOWN GL ERROR";
31 }
32
gl_call(const char * func,uint32_t line,const char * glfunc)33 void gl_call(const char *func, uint32_t line, const char *glfunc)
34 {
35 GLenum err;
36 if ((err = glGetError()) == GL_NO_ERROR)
37 {
38 return;
39 }
40
41 LOGE("gles2: function ", glfunc, " in ", func, " line ", line, ": ",
42 gl_error_string(glGetError()));
43 }
44
45 namespace OpenGL
46 {
47 /*
48 * Different Context is kept for each output
49 * Each of the following functions uses the currently bound context
50 */
51 program_t program, color_program;
compile_shader(std::string source,GLuint type)52 GLuint compile_shader(std::string source, GLuint type)
53 {
54 GLuint shader = GL_CALL(glCreateShader(type));
55
56 const char *c_src = source.c_str();
57 GL_CALL(glShaderSource(shader, 1, &c_src, NULL));
58
59 int s;
60 #define LENGTH 1024 * 128
61 char b1[LENGTH];
62 GL_CALL(glCompileShader(shader));
63 GL_CALL(glGetShaderiv(shader, GL_COMPILE_STATUS, &s));
64 GL_CALL(glGetShaderInfoLog(shader, LENGTH, NULL, b1));
65
66 if (s == GL_FALSE)
67 {
68 LOGE("Failed to load shader:\n", source,
69 "\nCompiler output:\n", b1);
70
71 return -1;
72 }
73
74 return shader;
75 }
76
77 /* Create a very simple gl program from the given shader sources */
compile_program(std::string vertex_source,std::string frag_source)78 GLuint compile_program(std::string vertex_source, std::string frag_source)
79 {
80 auto vertex_shader = compile_shader(vertex_source, GL_VERTEX_SHADER);
81 auto fragment_shader = compile_shader(frag_source, GL_FRAGMENT_SHADER);
82 auto result_program = GL_CALL(glCreateProgram());
83 GL_CALL(glAttachShader(result_program, vertex_shader));
84 GL_CALL(glAttachShader(result_program, fragment_shader));
85 GL_CALL(glLinkProgram(result_program));
86
87 /* won't be really deleted until program is deleted as well */
88 GL_CALL(glDeleteShader(vertex_shader));
89 GL_CALL(glDeleteShader(fragment_shader));
90
91 return result_program;
92 }
93
init()94 void init()
95 {
96 render_begin();
97 // enable_gl_synchronuous_debug()
98 program.compile(default_vertex_shader_source,
99 default_fragment_shader_source);
100
101 color_program.set_simple(compile_program(default_vertex_shader_source,
102 color_rect_fragment_source));
103
104 render_end();
105 }
106
fini()107 void fini()
108 {
109 render_begin();
110 program.free_resources();
111 color_program.free_resources();
112 render_end();
113 }
114
115 namespace
116 {
117 wf::output_t *current_output = NULL;
118 uint32_t current_output_fb = 0;
119 }
120
bind_output(wf::output_t * output,uint32_t fb)121 void bind_output(wf::output_t *output, uint32_t fb)
122 {
123 current_output = output;
124 current_output_fb = fb;
125 }
126
unbind_output(wf::output_t * output)127 void unbind_output(wf::output_t *output)
128 {
129 current_output = NULL;
130 current_output_fb = 0;
131 }
132
render_transformed_texture(wf::texture_t tex,const gl_geometry & g,const gl_geometry & texg,glm::mat4 model,glm::vec4 color,uint32_t bits)133 void render_transformed_texture(wf::texture_t tex,
134 const gl_geometry& g, const gl_geometry& texg,
135 glm::mat4 model, glm::vec4 color, uint32_t bits)
136 {
137 program.use(tex.type);
138
139 GLfloat vertexData[] = {
140 g.x1, g.y2,
141 g.x2, g.y2,
142 g.x2, g.y1,
143 g.x1, g.y1,
144 };
145
146 gl_geometry final_texg = (bits & TEXTURE_USE_TEX_GEOMETRY) ?
147 texg : gl_geometry{0.0f, 0.0f, 1.0f, 1.0f};
148
149 if (bits & TEXTURE_TRANSFORM_INVERT_Y)
150 {
151 final_texg.y1 = 1.0 - final_texg.y1;
152 final_texg.y2 = 1.0 - final_texg.y2;
153 }
154
155 if (bits & TEXTURE_TRANSFORM_INVERT_X)
156 {
157 final_texg.x1 = 1.0 - final_texg.x1;
158 final_texg.x2 = 1.0 - final_texg.x2;
159 }
160
161 GLfloat coordData[] = {
162 final_texg.x1, final_texg.y1,
163 final_texg.x2, final_texg.y1,
164 final_texg.x2, final_texg.y2,
165 final_texg.x1, final_texg.y2,
166 };
167
168 program.set_active_texture(tex);
169 program.attrib_pointer("position", 2, 0, vertexData);
170 program.attrib_pointer("uvPosition", 2, 0, coordData);
171 program.uniformMatrix4f("MVP", model);
172 program.uniform4f("color", color);
173
174 GL_CALL(glEnable(GL_BLEND));
175 GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
176 GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
177
178 program.deactivate();
179 }
180
render_transformed_texture(wf::texture_t texture,const wf::geometry_t & geometry,glm::mat4 transform,glm::vec4 color,uint32_t bits)181 void render_transformed_texture(wf::texture_t texture,
182 const wf::geometry_t& geometry, glm::mat4 transform,
183 glm::vec4 color, uint32_t bits)
184 {
185 bits &= ~TEXTURE_USE_TEX_GEOMETRY;
186
187 gl_geometry gg;
188 gg.x1 = geometry.x;
189 gg.y1 = geometry.y;
190 gg.x2 = gg.x1 + geometry.width;
191 gg.y2 = gg.y1 + geometry.height;
192 render_transformed_texture(texture, gg, {}, transform, color, bits);
193 }
194
render_texture(wf::texture_t texture,const wf::framebuffer_t & framebuffer,const wf::geometry_t & geometry,glm::vec4 color,uint32_t bits)195 void render_texture(wf::texture_t texture,
196 const wf::framebuffer_t& framebuffer,
197 const wf::geometry_t& geometry, glm::vec4 color, uint32_t bits)
198 {
199 render_transformed_texture(texture, geometry,
200 framebuffer.get_orthographic_projection(), color, bits);
201 }
202
render_rectangle(wf::geometry_t geometry,wf::color_t color,glm::mat4 matrix)203 void render_rectangle(wf::geometry_t geometry, wf::color_t color,
204 glm::mat4 matrix)
205 {
206 color_program.use(wf::TEXTURE_TYPE_RGBA);
207 float x = geometry.x, y = geometry.y,
208 w = geometry.width, h = geometry.height;
209
210 GLfloat vertexData[] = {
211 x, y + h,
212 x + w, y + h,
213 x + w, y,
214 x, y,
215 };
216
217 color_program.attrib_pointer("position", 2, 0, vertexData);
218 color_program.uniformMatrix4f("MVP", matrix);
219 color_program.uniform4f("color", {color.r, color.g, color.b, color.a});
220
221 GL_CALL(glEnable(GL_BLEND));
222 GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
223 GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
224
225 color_program.deactivate();
226 }
227
render_begin()228 void render_begin()
229 {
230 /* No real reason for 10, 10, 0 but it doesn't matter */
231 render_begin(10, 10, 0);
232 }
233
render_begin(const wf::framebuffer_base_t & fb)234 void render_begin(const wf::framebuffer_base_t& fb)
235 {
236 render_begin(fb.viewport_width, fb.viewport_height, fb.fb);
237 }
238
render_begin(int32_t viewport_width,int32_t viewport_height,uint32_t fb)239 void render_begin(int32_t viewport_width, int32_t viewport_height, uint32_t fb)
240 {
241 if (!wlr_egl_is_current(wf::get_core_impl().egl))
242 {
243 wlr_egl_make_current(wf::get_core_impl().egl, EGL_NO_SURFACE, NULL);
244 }
245
246 wlr_renderer_begin(wf::get_core_impl().renderer,
247 viewport_width, viewport_height);
248 GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, fb));
249 }
250
clear(wf::color_t col,uint32_t mask)251 void clear(wf::color_t col, uint32_t mask)
252 {
253 GL_CALL(glClearColor(col.r, col.g, col.b, col.a));
254 GL_CALL(glClear(mask));
255 }
256
render_end()257 void render_end()
258 {
259 GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, current_output_fb));
260 wlr_renderer_scissor(wf::get_core().renderer, NULL);
261 wlr_renderer_end(wf::get_core().renderer);
262 }
263 }
264
framebuffer_status_to_str(GLuint status)265 static std::string framebuffer_status_to_str(
266 GLuint status)
267 {
268 switch (status)
269 {
270 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
271 return "incomplete attachment";
272
273 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
274 return "missing attachment";
275
276 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
277 return "incomplete dimensions";
278
279 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
280 return "incomplete multisample";
281
282 default:
283 return "unknown";
284 }
285 }
286
allocate(int width,int height)287 bool wf::framebuffer_base_t::allocate(int width, int height)
288 {
289 bool first_allocate = false;
290 if (fb == (uint32_t)-1)
291 {
292 first_allocate = true;
293 GL_CALL(glGenFramebuffers(1, &fb));
294 }
295
296 if (tex == (uint32_t)-1)
297 {
298 first_allocate = true;
299 GL_CALL(glGenTextures(1, &tex));
300 GL_CALL(glBindTexture(GL_TEXTURE_2D, tex));
301 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
302 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
303 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
304 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
305 }
306
307 bool is_resize = false;
308 /* Special case: fb = 0. This occurs in the default workspace streams, we don't
309 * resize anything */
310 if (fb != OpenGL::current_output_fb)
311 {
312 if (first_allocate || (width != viewport_width) ||
313 (height != viewport_height))
314 {
315 is_resize = true;
316 GL_CALL(glBindTexture(GL_TEXTURE_2D, tex));
317 GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
318 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
319 }
320 }
321
322 if (first_allocate)
323 {
324 GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, fb));
325 GL_CALL(glBindTexture(GL_TEXTURE_2D, tex));
326 GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
327 GL_TEXTURE_2D, tex, 0));
328
329 auto status = GL_CALL(glCheckFramebufferStatus(GL_FRAMEBUFFER));
330 if (status != GL_FRAMEBUFFER_COMPLETE)
331 {
332 LOGE("Failed to initialize framebuffer: ",
333 framebuffer_status_to_str(status));
334
335 return false;
336 }
337 }
338
339 viewport_width = width;
340 viewport_height = height;
341
342 GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
343 GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, OpenGL::current_output_fb));
344
345 return is_resize || first_allocate;
346 }
347
copy_state(wf::framebuffer_base_t && other)348 void wf::framebuffer_base_t::copy_state(wf::framebuffer_base_t&& other)
349 {
350 this->viewport_width = other.viewport_width;
351 this->viewport_height = other.viewport_height;
352
353 this->fb = other.fb;
354 this->tex = other.tex;
355
356 other.reset();
357 }
358
framebuffer_base_t(wf::framebuffer_base_t && other)359 wf::framebuffer_base_t::framebuffer_base_t(wf::framebuffer_base_t&& other)
360 {
361 copy_state(std::move(other));
362 }
363
operator =(wf::framebuffer_base_t && other)364 wf::framebuffer_base_t& wf::framebuffer_base_t::operator =(
365 wf::framebuffer_base_t&& other)
366 {
367 if (this == &other)
368 {
369 return *this;
370 }
371
372 release();
373 copy_state(std::move(other));
374
375 return *this;
376 }
377
bind() const378 void wf::framebuffer_base_t::bind() const
379 {
380 GL_CALL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb));
381 GL_CALL(glViewport(0, 0, viewport_width, viewport_height));
382 }
383
scissor(wlr_box box) const384 void wf::framebuffer_base_t::scissor(wlr_box box) const
385 {
386 GL_CALL(glEnable(GL_SCISSOR_TEST));
387 GL_CALL(glScissor(box.x, viewport_height - box.y - box.height,
388 box.width, box.height));
389 }
390
release()391 void wf::framebuffer_base_t::release()
392 {
393 if ((fb != uint32_t(-1)) && (fb != 0))
394 {
395 GL_CALL(glDeleteFramebuffers(1, &fb));
396 }
397
398 if ((tex != uint32_t(-1)) && ((fb != 0) || (tex != 0)))
399 {
400 GL_CALL(glDeleteTextures(1, &tex));
401 }
402
403 reset();
404 }
405
reset()406 void wf::framebuffer_base_t::reset()
407 {
408 fb = -1;
409 tex = -1;
410 viewport_width = viewport_height = 0;
411 }
412
framebuffer_box_from_geometry_box(wlr_box box) const413 wlr_box wf::framebuffer_t::framebuffer_box_from_geometry_box(wlr_box box) const
414 {
415 /* Step 1: Make relative to the framebuffer */
416 box.x -= this->geometry.x;
417 box.y -= this->geometry.y;
418
419 /* Step 2: Apply scale to box */
420 wlr_box scaled = box * scale;
421
422 /* Step 3: rotate */
423 if (has_nonstandard_transform)
424 {
425 // TODO: unimplemented, but also unused for now
426 LOGE("unimplemented reached: framebuffer_box_from_geometry_box"
427 " with has_nonstandard_transform");
428
429 return {0, 0, 0, 0};
430 }
431
432 int width = viewport_width, height = viewport_height;
433 if (wl_transform & 1)
434 {
435 std::swap(width, height);
436 }
437
438 wlr_box result;
439 wl_output_transform transform =
440 wlr_output_transform_invert((wl_output_transform)wl_transform);
441
442 wlr_box_transform(&result, &scaled, transform, width, height);
443
444 return result;
445 }
446
get_orthographic_projection() const447 glm::mat4 wf::framebuffer_t::get_orthographic_projection() const
448 {
449 auto ortho = glm::ortho(1.0f * geometry.x,
450 1.0f * geometry.x + 1.0f * geometry.width,
451 1.0f * geometry.y + 1.0f * geometry.height,
452 1.0f * geometry.y);
453
454 return this->transform * ortho;
455 }
456
logic_scissor(wlr_box box) const457 void wf::framebuffer_t::logic_scissor(wlr_box box) const
458 {
459 scissor(framebuffer_box_from_geometry_box(box));
460 }
461
462 /* look up the actual values of wl_output_transform enum
463 * All _flipped transforms have values (regular_transfrom + 4) */
get_output_matrix_from_transform(wl_output_transform transform)464 glm::mat4 get_output_matrix_from_transform(wl_output_transform transform)
465 {
466 glm::mat4 scale = glm::mat4(1.0);
467
468 if (transform >= 4)
469 {
470 scale = glm::scale(scale, {-1, 1, 1});
471 }
472
473 /* remove the third bit if it's set */
474 uint32_t rotation = transform & (~4);
475 glm::mat4 rotation_matrix(1.0);
476
477 if (rotation == WL_OUTPUT_TRANSFORM_90)
478 {
479 rotation_matrix =
480 glm::rotate(rotation_matrix, glm::radians(90.0f), {0, 0, 1});
481 }
482
483 if (rotation == WL_OUTPUT_TRANSFORM_180)
484 {
485 rotation_matrix = glm::rotate(rotation_matrix, glm::radians(
486 180.0f), {0, 0, 1});
487 }
488
489 if (rotation == WL_OUTPUT_TRANSFORM_270)
490 {
491 rotation_matrix = glm::rotate(rotation_matrix, glm::radians(
492 270.0f), {0, 0, 1});
493 }
494
495 return rotation_matrix * scale;
496 }
497
498 namespace wf
499 {
texture_t()500 wf::texture_t::texture_t()
501 {}
texture_t(GLuint tex)502 wf::texture_t::texture_t(GLuint tex)
503 {
504 this->tex_id = tex;
505 }
506
texture_t(wlr_texture * texture)507 wf::texture_t::texture_t(wlr_texture *texture)
508 {
509 assert(wlr_texture_is_gles2(texture));
510 wlr_gles2_texture_attribs attribs;
511 wlr_gles2_texture_get_attribs(texture, &attribs);
512
513 /* Wayfire Y-inverts by default */
514 this->invert_y = !attribs.inverted_y;
515 this->target = attribs.target;
516 this->tex_id = attribs.tex;
517
518 if (this->target == GL_TEXTURE_2D)
519 {
520 this->type = attribs.has_alpha ?
521 wf::TEXTURE_TYPE_RGBA : wf::TEXTURE_TYPE_RGBX;
522 } else
523 {
524 this->type = wf::TEXTURE_TYPE_EXTERNAL;
525 }
526 }
527
texture_t(wlr_surface * surface)528 wf::texture_t::texture_t(wlr_surface *surface) :
529 texture_t(surface->buffer->texture)
530 {
531 if (surface->current.viewport.has_src)
532 {
533 this->has_viewport = true;
534
535 auto width = surface->buffer->texture->width;
536 auto height = surface->buffer->texture->height;
537
538 wlr_fbox fbox;
539 wlr_surface_get_buffer_source_box(surface, &fbox);
540 viewport_box.x1 = fbox.x / width;
541 viewport_box.x2 = (fbox.x + fbox.width) / width;
542 viewport_box.y1 = 1.0 - (fbox.y + fbox.height) / height;
543 viewport_box.y2 = 1.0 - (fbox.y) / height;
544 }
545 }
546 }
547
548 namespace OpenGL
549 {
550 class program_t::impl
551 {
552 public:
553 std::set<int> active_attrs;
554 std::set<int> active_attrs_divisors;
555
556 int active_program_idx = 0;
557
558 int id[wf::TEXTURE_TYPE_ALL];
559 std::map<std::string, int> uniforms[wf::TEXTURE_TYPE_ALL];
560
561 /** Find the uniform location for the currently bound program */
find_uniform_loc(const std::string & name)562 int find_uniform_loc(const std::string& name)
563 {
564 auto it = uniforms[active_program_idx].find(name);
565 if (it != uniforms[active_program_idx].end())
566 {
567 return it->second;
568 }
569
570 uniforms[active_program_idx][name] =
571 GL_CALL(glGetUniformLocation(id[active_program_idx], name.c_str()));
572
573 return uniforms[active_program_idx][name];
574 }
575
576 std::map<std::string, int> attribs[wf::TEXTURE_TYPE_ALL];
577 /** Find the attrib location for the currently bound program */
find_attrib_loc(const std::string & name)578 int find_attrib_loc(const std::string& name)
579 {
580 auto it = attribs[active_program_idx].find(name);
581 if (it != attribs[active_program_idx].end())
582 {
583 return it->second;
584 }
585
586 attribs[active_program_idx][name] =
587 GL_CALL(glGetAttribLocation(id[active_program_idx], name.c_str()));
588
589 return attribs[active_program_idx][name];
590 }
591 };
592
program_t()593 program_t::program_t()
594 {
595 this->priv = std::make_unique<impl>();
596 for (int i = 0; i < wf::TEXTURE_TYPE_ALL; i++)
597 {
598 this->priv->id[i] = 0;
599 }
600 }
601
set_simple(GLuint program_id,wf::texture_type_t type)602 void program_t::set_simple(GLuint program_id, wf::texture_type_t type)
603 {
604 free_resources();
605 assert(type < wf::TEXTURE_TYPE_ALL);
606 this->priv->id[type] = program_id;
607 }
608
~program_t()609 program_t::~program_t()
610 {}
611
replace_builtin_with(const std::string & source,const std::string & builtin,const std::string & with)612 static std::string replace_builtin_with(const std::string& source,
613 const std::string& builtin, const std::string& with)
614 {
615 size_t pos = source.find(builtin);
616 if (pos == std::string::npos)
617 {
618 return source;
619 }
620
621 return source.substr(0, pos) + with + source.substr(pos + builtin.length());
622 }
623
624 static const std::string builtin = "@builtin@";
625 static const std::string builtin_ext = "@builtin_ext@";
626 struct texture_type_builtins
627 {
628 std::string builtin;
629 std::string builtin_ext;
630 };
631
632 std::map<wf::texture_type_t, texture_type_builtins> builtins = {
633 {wf::TEXTURE_TYPE_RGBA, {builtin_rgba_source, ""}},
634 {wf::TEXTURE_TYPE_RGBX, {builtin_rgbx_source, ""}},
635 {wf::TEXTURE_TYPE_EXTERNAL, {builtin_external_source,
636 builtin_ext_external_source}},
637 };
638
compile(const std::string & vertex_source,const std::string & fragment_source)639 void program_t::compile(const std::string& vertex_source,
640 const std::string& fragment_source)
641 {
642 free_resources();
643
644 for (const auto& program_type : builtins)
645 {
646 auto fragment = replace_builtin_with(fragment_source,
647 builtin, program_type.second.builtin);
648 fragment = replace_builtin_with(fragment,
649 builtin_ext, program_type.second.builtin_ext);
650 this->priv->id[program_type.first] =
651 compile_program(vertex_source, fragment);
652 }
653 }
654
free_resources()655 void program_t::free_resources()
656 {
657 for (int i = 0; i < wf::TEXTURE_TYPE_ALL; i++)
658 {
659 if (this->priv->id[i])
660 {
661 GL_CALL(glDeleteProgram(priv->id[i]));
662 this->priv->id[i] = 0;
663 }
664 }
665 }
666
use(wf::texture_type_t type)667 void program_t::use(wf::texture_type_t type)
668 {
669 if (priv->id[type] == 0)
670 {
671 throw std::runtime_error("program_t has no program for type " +
672 std::to_string(type));
673 }
674
675 GL_CALL(glUseProgram(priv->id[type]));
676 priv->active_program_idx = type;
677 }
678
get_program_id(wf::texture_type_t type)679 int program_t::get_program_id(wf::texture_type_t type)
680 {
681 return priv->id[type];
682 }
683
uniform1i(const std::string & name,int value)684 void program_t::uniform1i(const std::string& name, int value)
685 {
686 int loc = priv->find_uniform_loc(name);
687 GL_CALL(glUniform1i(loc, value));
688 }
689
uniform1f(const std::string & name,float value)690 void program_t::uniform1f(const std::string& name, float value)
691 {
692 int loc = priv->find_uniform_loc(name);
693 GL_CALL(glUniform1f(loc, value));
694 }
695
uniform2f(const std::string & name,float x,float y)696 void program_t::uniform2f(const std::string& name, float x, float y)
697 {
698 int loc = priv->find_uniform_loc(name);
699 GL_CALL(glUniform2f(loc, x, y));
700 }
701
uniform3f(const std::string & name,float x,float y,float z)702 void program_t::uniform3f(const std::string& name, float x, float y, float z)
703 {
704 int loc = priv->find_uniform_loc(name);
705 GL_CALL(glUniform3f(loc, x, y, z));
706 }
707
uniform4f(const std::string & name,const glm::vec4 & value)708 void program_t::uniform4f(const std::string& name, const glm::vec4& value)
709 {
710 int loc = priv->find_uniform_loc(name);
711 GL_CALL(glUniform4f(loc, value.r, value.g, value.b, value.a));
712 }
713
uniformMatrix4f(const std::string & name,const glm::mat4 & value)714 void program_t::uniformMatrix4f(const std::string& name, const glm::mat4& value)
715 {
716 int loc = priv->find_uniform_loc(name);
717 GL_CALL(glUniformMatrix4fv(loc, 1, GL_FALSE, &value[0][0]));
718 }
719
attrib_pointer(const std::string & attrib,int size,int stride,const void * ptr,GLenum type)720 void program_t::attrib_pointer(const std::string& attrib,
721 int size, int stride, const void *ptr, GLenum type)
722 {
723 int loc = priv->find_attrib_loc(attrib);
724 priv->active_attrs.insert(loc);
725
726 GL_CALL(glEnableVertexAttribArray(loc));
727 GL_CALL(glVertexAttribPointer(loc, size, type, GL_FALSE, stride, ptr));
728 }
729
attrib_divisor(const std::string & attrib,int divisor)730 void program_t::attrib_divisor(const std::string& attrib, int divisor)
731 {
732 int loc = priv->find_attrib_loc(attrib);
733 priv->active_attrs_divisors.insert(loc);
734 GL_CALL(glVertexAttribDivisor(loc, divisor));
735 }
736
set_active_texture(const wf::texture_t & texture)737 void program_t::set_active_texture(const wf::texture_t& texture)
738 {
739 GL_CALL(glActiveTexture(GL_TEXTURE0));
740 GL_CALL(glBindTexture(texture.target, texture.tex_id));
741 GL_CALL(glTexParameteri(texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
742
743 glm::vec2 base{0.0f, 0.0f};
744 glm::vec2 scale{1.0f, 1.0f};
745
746 if (texture.has_viewport)
747 {
748 scale.x = texture.viewport_box.x2 - texture.viewport_box.x1;
749 scale.y = texture.viewport_box.y2 - texture.viewport_box.y1;
750 base.x = texture.viewport_box.x1;
751 base.y = texture.viewport_box.y1;
752 }
753
754 if (texture.invert_y)
755 {
756 scale.y *= -1;
757 base.y = 1.0 - base.y;
758 }
759
760 uniform2f("_wayfire_uv_base", base.x, base.y);
761 uniform2f("_wayfire_uv_scale", scale.x, scale.y);
762 }
763
deactivate()764 void program_t::deactivate()
765 {
766 for (int loc : priv->active_attrs_divisors)
767 {
768 GL_CALL(glVertexAttribDivisor(loc, 0));
769 }
770
771 for (int loc : priv->active_attrs)
772 {
773 GL_CALL(glDisableVertexAttribArray(loc));
774 }
775
776 priv->active_attrs_divisors.clear();
777 priv->active_attrs.clear();
778 GL_CALL(glUseProgram(0));
779 }
780 }
781