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