From 06668b0bd2b38db42e17c25f24c8e47da1b9d3ce Mon Sep 17 00:00:00 2001 From: Matthew Kosarek Date: Mon, 27 May 2024 18:58:54 -0400 Subject: [PATCH] refactor: move ProgramFactory to its own file + clang-tidy issues around the renderer (#139) * refactor: move ProgramFactory to its own file * refactor: fixing various clang-tidy issues * refactor: plenty of more cleanup --- CMakeLists.txt | 1 + src/program_factory.cpp | 236 ++++++++++++++++++++++++++ src/program_factory.h | 121 ++++++++++++++ src/renderer.cpp | 360 ++++++---------------------------------- src/renderer.h | 14 +- src/surface_tracker.cpp | 2 +- src/surface_tracker.h | 2 +- 7 files changed, 415 insertions(+), 321 deletions(-) create mode 100644 src/program_factory.cpp create mode 100644 src/program_factory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c9da9c..63227e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ add_library(miracle-wm-implementation src/window_tools_accessor.cpp src/animator.cpp src/animation_definition.cpp + src/program_factory.cpp ) add_executable(miracle-wm diff --git a/src/program_factory.cpp b/src/program_factory.cpp new file mode 100644 index 0000000..36bfd84 --- /dev/null +++ b/src/program_factory.cpp @@ -0,0 +1,236 @@ +/** +Copyright (C) 2024 Matthew Kosarek + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +**/ + +#define MIR_LOG_COMPONENT "program_factory" + +#include "program_factory.h" +#include +#include +#include +#include + +namespace +{ +const GLchar* const vertex_shader_src = R"( +attribute vec3 position; +attribute vec2 texcoord; + +uniform mat4 screen_to_gl_coords; +uniform mat4 display_transform; +uniform mat4 workspace_transform; +uniform mat4 transform; +uniform vec2 centre; + +varying vec2 v_texcoord; + +void main() { + vec4 mid = vec4(centre, 0.0, 0.0); + vec4 transformed = (transform * (vec4(position, 1.0) - mid)) + mid; + gl_Position = display_transform * screen_to_gl_coords * workspace_transform * transformed; + v_texcoord = texcoord; +} +)"; +} + +miracle::ProgramData::ProgramData(GLuint program_id) +{ + id = program_id; + position_attr = glGetAttribLocation(id, "position"); + if (position_attr < 0) + mir::log_warning("Program is missing position_attr"); + texcoord_attr = glGetAttribLocation(id, "texcoord"); + if (position_attr < 0) + mir::log_warning("Program is missing texcoord_attr"); + for (auto i = 0u; i < tex_uniforms.size(); ++i) + { + /* You can reference uniform arrays as tex[0], tex[1], tex[2], … until you + * hit the end of the array, which will return -1 as the location. + */ + auto const uniform_name = std::string { "tex[" } + std::to_string(i) + "]"; + tex_uniforms[i] = glGetUniformLocation(id, uniform_name.c_str()); + } + centre_uniform = glGetUniformLocation(id, "centre"); + if (centre_uniform < 0) + mir::log_warning("Program is missing centre_uniform"); + + display_transform_uniform = glGetUniformLocation(id, "display_transform"); + if (display_transform_uniform < 0) + mir::log_warning("Program is missing display_transform_uniform"); + + workspace_transform_uniform = glGetUniformLocation(id, "workspace_transform"); + if (workspace_transform_uniform < 0) + mir::log_warning("Program is missing workspace_transform_uniform"); + + transform_uniform = glGetUniformLocation(id, "transform"); + if (transform_uniform < 0) + mir::log_warning("Program is missing transform_uniform"); + + screen_to_gl_coords_uniform = glGetUniformLocation(id, "screen_to_gl_coords"); + if (screen_to_gl_coords_uniform < 0) + mir::log_warning("Program is missing screen_to_gl_coords_uniform"); + + alpha_uniform = glGetUniformLocation(id, "alpha"); + if (alpha_uniform < 0) + mir::log_warning("Program is missing alpha_uniform"); + + outline_color_uniform = glGetUniformLocation(id, "outline_color"); + if (outline_color_uniform < 0) + mir::log_warning("Program is missing outline_color_uniform"); +} + +miracle::Program::Program( + ProgramHandle&& opaque_shader, ProgramHandle&& alpha_shader, ProgramHandle&& outline_shader) : + opaque_handle(std::move(opaque_shader)), + alpha_handle(std::move(alpha_shader)), + outline_handle(std::move(outline_shader)), + opaque { opaque_handle }, + alpha { alpha_handle }, + outline(outline_handle) {} + +miracle::ProgramFactory::ProgramFactory() : + vertex_shader { compile_shader(GL_VERTEX_SHADER, vertex_shader_src) } {} + +mir::graphics::gl::Program& miracle::ProgramFactory::compile_fragment_shader( + void const* id, + char const* extension_fragment, + char const* fragment_fragment) + { + /* NOTE: This does not lock the programs vector as there is one ProgramFactory instance + * per rendering thread. + */ + + for (auto const& pair : programs) + { + if (pair.first == id) + { + return *pair.second; + } + } + + std::stringstream opaque_fragment; + opaque_fragment + << extension_fragment + << "\n" + << "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + << "\n" + << fragment_fragment + << "\n" + << "varying vec2 v_texcoord;\n" + "void main() {\n" + " gl_FragColor = sample_to_rgba(v_texcoord);\n" + "}\n"; + + std::stringstream alpha_fragment; + alpha_fragment + << extension_fragment + << "\n" + << "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + << "\n" + << fragment_fragment + << "\n" + << "varying vec2 v_texcoord;\n" + "uniform float alpha;\n" + "void main() {\n" + " gl_FragColor = alpha * sample_to_rgba(v_texcoord);\n" + "}\n"; + + const GLchar* const outline_shader_src = R"( +#ifdef GL_ES +precision mediump float; +#endif + +uniform float alpha; +uniform vec4 outline_color; +void main() { + gl_FragColor = alpha * outline_color; +} +)"; + + // GL shader compilation is *not* threadsafe, and requires external synchronisation + std::lock_guard lock { compilation_mutex }; + + ShaderHandle const opaque_shader { + compile_shader(GL_FRAGMENT_SHADER, opaque_fragment.str().c_str()) + }; + ShaderHandle const alpha_shader { + compile_shader(GL_FRAGMENT_SHADER, alpha_fragment.str().c_str()) + }; + ShaderHandle const outline_shader { + compile_shader(GL_FRAGMENT_SHADER, outline_shader_src) + }; + + programs.emplace_back(id, std::make_unique( + link_shader(vertex_shader, opaque_shader), + link_shader(vertex_shader, alpha_shader), + link_shader(vertex_shader, outline_shader))); + + return *programs.back().second; + + // We delete opaque_shader and alpha_shader here. This is fine; it only marks them + // for deletion. GL will only delete them once the GL Program they're linked in is destroyed. +} + +GLuint miracle::ProgramFactory::compile_shader(GLenum type, GLchar const* src) +{ + GLuint id = glCreateShader(type); + if (!id) + { + BOOST_THROW_EXCEPTION(mir::graphics::gl_error("Failed to create shader")); + } + + glShaderSource(id, 1, &src, NULL); + glCompileShader(id); + GLint ok; + glGetShaderiv(id, GL_COMPILE_STATUS, &ok); + if (!ok) + { + GLchar log[1024] = "(No log info)"; + glGetShaderInfoLog(id, sizeof log, NULL, log); + glDeleteShader(id); + BOOST_THROW_EXCEPTION( + std::runtime_error( + std::string("Compile failed: ") + log + " for:\n" + src)); + } + return id; +} + +miracle::ProgramHandle miracle::ProgramFactory::link_shader( + ShaderHandle const& vertex_shader, + ShaderHandle const& fragment_shader) +{ + ProgramHandle program { glCreateProgram() }; + glAttachShader(program, fragment_shader); + glAttachShader(program, vertex_shader); + glLinkProgram(program); + GLint ok; + glGetProgramiv(program, GL_LINK_STATUS, &ok); + if (!ok) + { + GLchar log[1024]; + glGetProgramInfoLog(program, sizeof log - 1, NULL, log); + log[sizeof log - 1] = '\0'; + BOOST_THROW_EXCEPTION( + std::runtime_error( + std::string("Linking GL shader failed: ") + log)); + } + + return program; +} \ No newline at end of file diff --git a/src/program_factory.h b/src/program_factory.h new file mode 100644 index 0000000..ea692e5 --- /dev/null +++ b/src/program_factory.h @@ -0,0 +1,121 @@ +/** +Copyright (C) 2024 Matthew Kosarek + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +**/ + +#ifndef MIRACLE_WM_PROGRAM_FACTORY_H +#define MIRACLE_WM_PROGRAM_FACTORY_H + +#include +#include +#include +#include +#include +#include + +namespace miracle +{ + +template +class GLHandle +{ +public: + explicit GLHandle(GLuint id) : + id { id } + { + } + + ~GLHandle() + { + if (id) + (*deleter)(id); + } + + GLHandle(GLHandle const&) = delete; + + GLHandle& operator=(GLHandle const&) = delete; + + GLHandle(GLHandle&& from) : + id { from.id } + { + from.id = 0; + } + + operator GLuint() const + { + return id; + } + +private: + GLuint id; +}; + +using ProgramHandle = GLHandle<&glDeleteProgram>; +using ShaderHandle = GLHandle<&glDeleteShader>; + +struct ProgramData +{ + GLuint id = 0; + /* 8 is the minimum number of texture units a GL implementation can provide + * and should comfortably provide enough textures for any conceivable buffer + * format + */ + std::array tex_uniforms; + GLint position_attr = -1; + GLint texcoord_attr = -1; + GLint centre_uniform = -1; + GLint display_transform_uniform = -1; + GLint workspace_transform_uniform = -1; + GLint transform_uniform = -1; + GLint screen_to_gl_coords_uniform = -1; + GLint alpha_uniform = -1; + GLint outline_color_uniform = -1; + mutable long long last_used_frameno = 0; + + ProgramData(GLuint program_id); +}; + +struct Program : public mir::graphics::gl::Program +{ +public: + Program(ProgramHandle&& opaque_shader, ProgramHandle&& alpha_shader, ProgramHandle&& outline_shader); + ProgramHandle opaque_handle, alpha_handle, outline_handle; + ProgramData opaque, alpha, outline; +}; + +class ProgramFactory : public mir::graphics::gl::ProgramFactory +{ +public: + ProgramFactory(); + mir::graphics::gl::Program& compile_fragment_shader( + void const* id, + char const* extension_fragment, + char const* fragment_fragment) override; + +private: + static GLuint compile_shader(GLenum type, GLchar const* src); + static ProgramHandle link_shader( + ShaderHandle const& vertex_shader, + ShaderHandle const& fragment_shader); + + ShaderHandle const vertex_shader; + std::vector>> programs; + // GL requires us to synchronise multi-threaded access to the shader APIs. + std::mutex compilation_mutex; +}; + +} // miracle + +#endif //MIRACLE_WM_PROGRAM_FACTORY_H diff --git a/src/renderer.cpp b/src/renderer.cpp index 16d6168..1e32446 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -15,35 +15,30 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . **/ -#include +#define GLM_FORCE_RADIANS #define MIR_LOG_COMPONENT "GLRenderer" + +#include #include "window_tools_accessor.h" #include "workspace_content.h" - -#include "mir/graphics/buffer.h" -#include "mir/graphics/display_sink.h" -#include "mir/graphics/egl_error.h" -#include "mir/graphics/platform.h" -#include "mir/graphics/program.h" -#include "mir/graphics/program_factory.h" -#include "mir/graphics/renderable.h" -#include "mir/graphics/texture.h" -#include "mir/log.h" -#include "mir/renderer/gl/gl_surface.h" +#include "program_factory.h" #include "miracle_config.h" #include "renderer.h" #include "tessellation_helpers.h" #include "window_metadata.h" -#define GLM_FORCE_RADIANS +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include - -#include #include -#include -#include #include namespace mg = mir::graphics; @@ -51,270 +46,6 @@ namespace mgl = mir::gl; namespace geom = mir::geometry; using namespace miracle; -namespace -{ -template -class GLHandle -{ -public: - explicit GLHandle(GLuint id) : - id { id } - { - } - - ~GLHandle() - { - if (id) - (*deleter)(id); - } - - GLHandle(GLHandle const&) = delete; - - GLHandle& operator=(GLHandle const&) = delete; - - GLHandle(GLHandle&& from) : - id { from.id } - { - from.id = 0; - } - - operator GLuint() const - { - return id; - } - -private: - GLuint id; -}; - -using ProgramHandle = GLHandle<&glDeleteProgram>; -using ShaderHandle = GLHandle<&glDeleteShader>; - -struct ProgramData -{ - GLuint id = 0; - /* 8 is the minimum number of texture units a GL implementation can provide - * and should comfortably provide enough textures for any conceivable buffer - * format - */ - std::array tex_uniforms; - GLint position_attr = -1; - GLint texcoord_attr = -1; - GLint centre_uniform = -1; - GLint display_transform_uniform = -1; - GLint workspace_transform_uniform = -1; - GLint transform_uniform = -1; - GLint screen_to_gl_coords_uniform = -1; - GLint alpha_uniform = -1; - GLint outline_color_uniform = -1; - mutable long long last_used_frameno = 0; - - ProgramData(GLuint program_id) - { - id = program_id; - position_attr = glGetAttribLocation(id, "position"); - texcoord_attr = glGetAttribLocation(id, "texcoord"); - for (auto i = 0u; i < tex_uniforms.size(); ++i) - { - /* You can reference uniform arrays as tex[0], tex[1], tex[2], … until you - * hit the end of the array, which will return -1 as the location. - */ - auto const uniform_name = std::string { "tex[" } + std::to_string(i) + "]"; - tex_uniforms[i] = glGetUniformLocation(id, uniform_name.c_str()); - } - centre_uniform = glGetUniformLocation(id, "centre"); - display_transform_uniform = glGetUniformLocation(id, "display_transform"); - workspace_transform_uniform = glGetUniformLocation(id, "workspace_transform"); - transform_uniform = glGetUniformLocation(id, "transform"); - screen_to_gl_coords_uniform = glGetUniformLocation(id, "screen_to_gl_coords"); - alpha_uniform = glGetUniformLocation(id, "alpha"); - outline_color_uniform = glGetUniformLocation(id, "outline_color"); - } -}; - -struct Program : public mir::graphics::gl::Program -{ -public: - Program(ProgramHandle&& opaque_shader, ProgramHandle&& alpha_shader, ProgramHandle&& outline_shader) : - opaque_handle(std::move(opaque_shader)), - alpha_handle(std::move(alpha_shader)), - outline_handle(std::move(outline_shader)), - opaque { opaque_handle }, - alpha { alpha_handle }, - outline(outline_handle) - { - } - - ProgramHandle opaque_handle, alpha_handle, outline_handle; - ProgramData opaque, alpha, outline; -}; - -const GLchar* const vertex_shader_src = R"( -attribute vec3 position; -attribute vec2 texcoord; -uniform mat4 screen_to_gl_coords; -uniform mat4 display_transform; -uniform mat4 workspace_transform; -uniform mat4 transform; -uniform vec2 centre; -uniform vec4 outline_color; -varying vec2 v_texcoord; -varying vec4 v_outline_color; -void main() { - vec4 mid = vec4(centre, 0.0, 0.0); - vec4 transformed = (transform * (vec4(position, 1.0) - mid)) + mid; - gl_Position = display_transform * screen_to_gl_coords * workspace_transform * transformed; - v_texcoord = texcoord; - v_outline_color = outline_color; -} -)"; -} - -class Renderer::ProgramFactory : public mir::graphics::gl::ProgramFactory -{ -public: - // NOTE: This must be called with a current GL context - ProgramFactory() : - vertex_shader { compile_shader(GL_VERTEX_SHADER, vertex_shader_src) } - { - } - - mir::graphics::gl::Program& - compile_fragment_shader( - void const* id, - char const* extension_fragment, - char const* fragment_fragment) override - { - /* NOTE: This does not lock the programs vector as there is one ProgramFactory instance - * per rendering thread. - */ - - for (auto const& pair : programs) - { - if (pair.first == id) - { - return *pair.second; - } - } - - std::stringstream opaque_fragment; - opaque_fragment - << extension_fragment - << "\n" - << "#ifdef GL_ES\n" - "precision mediump float;\n" - "#endif\n" - << "\n" - << fragment_fragment - << "\n" - << "varying vec2 v_texcoord;\n" - "void main() {\n" - " gl_FragColor = sample_to_rgba(v_texcoord);\n" - "}\n"; - - std::stringstream alpha_fragment; - alpha_fragment - << extension_fragment - << "\n" - << "#ifdef GL_ES\n" - "precision mediump float;\n" - "#endif\n" - << "\n" - << fragment_fragment - << "\n" - << "varying vec2 v_texcoord;\n" - "uniform float alpha;\n" - "void main() {\n" - " gl_FragColor = alpha * sample_to_rgba(v_texcoord);\n" - "}\n"; - - const GLchar* const outline_shader_src = R"( -#ifdef GL_ES -precision mediump float; -#endif - -varying vec2 v_texcoord; -varying vec4 v_outline_color; -void main() { - gl_FragColor = v_outline_color; -} -)"; - - // GL shader compilation is *not* threadsafe, and requires external synchronisation - std::lock_guard lock { compilation_mutex }; - - ShaderHandle const opaque_shader { - compile_shader(GL_FRAGMENT_SHADER, opaque_fragment.str().c_str()) - }; - ShaderHandle const alpha_shader { - compile_shader(GL_FRAGMENT_SHADER, alpha_fragment.str().c_str()) - }; - ShaderHandle const outline_shader { - compile_shader(GL_FRAGMENT_SHADER, outline_shader_src) - }; - - programs.emplace_back(id, std::make_unique<::Program>(link_shader(vertex_shader, opaque_shader), link_shader(vertex_shader, alpha_shader), link_shader(vertex_shader, outline_shader))); - - return *programs.back().second; - - // We delete opaque_shader and alpha_shader here. This is fine; it only marks them - // for deletion. GL will only delete them once the GL Program they're linked in is destroyed. - } - -private: - static GLuint compile_shader(GLenum type, GLchar const* src) - { - GLuint id = glCreateShader(type); - if (!id) - { - BOOST_THROW_EXCEPTION(mg::gl_error("Failed to create shader")); - } - - glShaderSource(id, 1, &src, NULL); - glCompileShader(id); - GLint ok; - glGetShaderiv(id, GL_COMPILE_STATUS, &ok); - if (!ok) - { - GLchar log[1024] = "(No log info)"; - glGetShaderInfoLog(id, sizeof log, NULL, log); - glDeleteShader(id); - BOOST_THROW_EXCEPTION( - std::runtime_error( - std::string("Compile failed: ") + log + " for:\n" + src)); - } - return id; - } - - static ProgramHandle link_shader( - ShaderHandle const& vertex_shader, - ShaderHandle const& fragment_shader) - { - ProgramHandle program { glCreateProgram() }; - glAttachShader(program, fragment_shader); - glAttachShader(program, vertex_shader); - glLinkProgram(program); - GLint ok; - glGetProgramiv(program, GL_LINK_STATUS, &ok); - if (!ok) - { - GLchar log[1024]; - glGetProgramInfoLog(program, sizeof log - 1, NULL, log); - log[sizeof log - 1] = '\0'; - BOOST_THROW_EXCEPTION( - std::runtime_error( - std::string("Linking GL shader failed: ") + log)); - } - - return program; - } - - ShaderHandle const vertex_shader; - std::vector>> programs; - // GL requires us to synchronise multi-threaded access to the shader APIs. - std::mutex compilation_mutex; -}; - namespace { auto make_output_current(std::unique_ptr output) -> std::unique_ptr @@ -333,22 +64,22 @@ public: { } - ID id() const override + [[nodiscard]] ID id() const override { return ""; } - std::shared_ptr buffer() const override + [[nodiscard]] std::shared_ptr buffer() const override { return renderable.buffer(); } - geom::Rectangle screen_position() const override + [[nodiscard]] geom::Rectangle screen_position() const override { return get_rectangle(renderable.screen_position()); } - std::optional clip_area() const override + [[nodiscard]] std::optional clip_area() const override { auto clip_area_rect = renderable.clip_area(); if (!clip_area_rect) @@ -356,28 +87,28 @@ public: return get_rectangle(clip_area_rect.value()); } - float alpha() const override + [[nodiscard]] float alpha() const override { return _alpha; } - glm::mat4 transformation() const override + [[nodiscard]] glm::mat4 transformation() const override { return renderable.transformation(); } - bool shaped() const override + [[nodiscard]] bool shaped() const override { return renderable.shaped(); } - std::optional surface_if_any() const override + [[nodiscard]] std::optional surface_if_any() const override { return {}; } private: - geom::Rectangle get_rectangle(geom::Rectangle const& in) const + [[nodiscard]] geom::Rectangle get_rectangle(geom::Rectangle const& in) const { auto rectangle = in; rectangle.top_left = { @@ -405,6 +136,7 @@ Renderer::Renderer( clear_color { 0.0f, 0.0f, 0.0f, 1.0f }, program_factory { std::make_unique() }, display_transform(1), + screen_to_gl_coords(1), gl_interface { std::move(gl_interface) }, config { config }, surface_tracker { surface_tracker } @@ -466,13 +198,9 @@ Renderer::Renderer( glBindBuffer(GL_ARRAY_BUFFER, 0); } -Renderer::~Renderer() -{ -} - void Renderer::tessellate( std::vector& primitives, - mg::Renderable const& renderable) const + mg::Renderable const& renderable) { primitives.resize(1); primitives[0] = mgl::tessellate_renderable_into_rectangle(renderable, geom::Displacement { 0, 0 }); @@ -492,7 +220,12 @@ auto Renderer::render(mg::RenderableList const& renderables) const -> std::uniqu ++frameno; for (auto const& r : renderables) { - draw(*r); + auto context = draw(*r); + if (context.enabled) + { + OutlineRenderable outline(*r, context.size, context.color.a); + draw(outline, &context); + } } auto output = output_surface->commit(); @@ -504,7 +237,7 @@ auto Renderer::render(mg::RenderableList const& renderables) const -> std::uniqu return output; } -void Renderer::draw(mg::Renderable const& renderable, OutlineContext* context) const +miracle::Renderer::OutlineContext Renderer::draw(mg::Renderable const& renderable, OutlineContext* context) const { auto surface = renderable.surface_if_any(); std::shared_ptr userdata = nullptr; @@ -568,7 +301,7 @@ void Renderer::draw(mg::Renderable const& renderable, OutlineContext* context) c auto const* const prog = [&](bool alpha) -> ProgramData const* { - auto const& family = static_cast<::Program const&>(texture->shader(*program_factory)); + auto const& family = dynamic_cast(texture->shader(*program_factory)); if (context) return &family.outline; if (alpha) @@ -585,7 +318,7 @@ void Renderer::draw(mg::Renderable const& renderable, OutlineContext* context) c { if (prog->tex_uniforms[i] != -1) { - glUniform1i(prog->tex_uniforms[i], i); + glUniform1i(prog->tex_uniforms[i], (int)i); } } glUniformMatrix4fv(prog->display_transform_uniform, 1, GL_FALSE, @@ -597,8 +330,8 @@ void Renderer::draw(mg::Renderable const& renderable, OutlineContext* context) c glActiveTexture(GL_TEXTURE0); auto const& rect = renderable.screen_position(); - GLfloat centrex = rect.top_left.x.as_int() + rect.size.width.as_int() / 2.0f; - GLfloat centrey = rect.top_left.y.as_int() + rect.size.height.as_int() / 2.0f; + GLfloat centrex = (float)rect.top_left.x.as_int() + (float)rect.size.width.as_int() / 2.0f; + GLfloat centrey = (float)rect.top_left.y.as_int() + (float)rect.size.height.as_int() / 2.0f; glUniform2f(prog->centre_uniform, centrex, centrey); glm::mat4 transform = renderable.transformation(); @@ -633,7 +366,7 @@ void Renderer::draw(mg::Renderable const& renderable, OutlineContext* context) c glUniformMatrix4fv(prog->workspace_transform_uniform, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.f))); - if (context) + if (prog->outline_color_uniform >= 0 && context) { glUniform4f(prog->outline_color_uniform, context->color.r, context->color.g, @@ -726,11 +459,11 @@ void Renderer::draw(mg::Renderable const& renderable, OutlineContext* context) c { bool is_focused = userdata->is_focused(); auto color = is_focused ? border_config.focus_color : border_config.color; - OutlineContext outline_context = { color }; - OutlineRenderable outline(renderable, border_config.size, color.a); - draw(outline, &outline_context); + return OutlineContext{ true, color, border_config.size }; } } + + return OutlineContext{ false }; } void Renderer::set_viewport(mir::geometry::Rectangle const& rect) @@ -758,12 +491,13 @@ void Renderer::set_viewport(mir::geometry::Rectangle const& rect) screen_to_gl_coords[2][3] = -1.0f; float const vertical_fov_degrees = 30.0f; - float const near = (rect.size.height.as_int() / 2.0f) / std::tan((vertical_fov_degrees * M_PI / 180.0f) / 2.0f); + float half_height = (float)rect.size.height.as_int() / 2.f; + float const near = half_height / tanf((float)(vertical_fov_degrees * M_PI / 180.0f) / 2.f); float const far = -near; screen_to_gl_coords = glm::scale(screen_to_gl_coords, - glm::vec3 { 2.0f / rect.size.width.as_int(), - -2.0f / rect.size.height.as_int(), + glm::vec3 { 2.0f / (float)rect.size.width.as_int(), + -2.0f / (float)rect.size.height.as_int(), 2.0f / (near - far) }); screen_to_gl_coords = glm::translate(screen_to_gl_coords, glm::vec3 { -rect.top_left.x.as_int(), @@ -786,17 +520,17 @@ void Renderer::update_gl_viewport() auto viewport_height = fabs(transformed_viewport[1]); auto const output_size = output_surface->size(); - auto const output_width = output_size.width.as_value(); - auto const output_height = output_size.height.as_value(); + int const output_width = output_size.width.as_value(); + int const output_height = output_size.height.as_value(); if (viewport_width > 0.0f && viewport_height > 0.0f && output_width > 0 && output_height > 0) { GLint reduced_width = output_width, reduced_height = output_height; // if viewport_aspect_ratio >= output_aspect_ratio - if (viewport_width * output_height >= output_width * viewport_height) - reduced_height = output_width * viewport_height / viewport_width; + if (viewport_width * (float)output_height >= (float)output_width * viewport_height) + reduced_height = (int)((float)output_width * viewport_height / viewport_width); else - reduced_width = output_height * viewport_width / viewport_height; + reduced_width = (int)((float)output_height * viewport_width / viewport_height); GLint offset_x = (output_width - reduced_width) / 2; GLint offset_y = (output_height - reduced_height) / 2; diff --git a/src/renderer.h b/src/renderer.h index d04ba86..1e3cf19 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -20,12 +20,13 @@ along with this program. If not, see . #include "primitive.h" #include "surface_tracker.h" +#include "program_factory.h" + #include #include #include #include #include - #include #include #include @@ -54,7 +55,7 @@ public: std::unique_ptr output, std::shared_ptr const& config, SurfaceTracker& surface_tracker); - virtual ~Renderer(); + ~Renderer() override = default; // These are called with a valid GL context: void set_viewport(mir::geometry::Rectangle const& rect) override; @@ -81,20 +82,21 @@ private: * the only OpenGL-specific class in the display server, and * tessellation is very much OpenGL-specific. */ - virtual void tessellate(std::vector& primitives, - mir::graphics::Renderable const& renderable) const; + static void tessellate(std::vector& primitives, + mir::graphics::Renderable const& renderable); struct OutlineContext { + bool enabled = false; glm::vec4 color; + int size; }; - virtual void draw(mir::graphics::Renderable const& renderable, OutlineContext* context = nullptr) const; + OutlineContext draw(mir::graphics::Renderable const& renderable, OutlineContext* context = nullptr) const; void update_gl_viewport(); std::unique_ptr const output_surface; GLfloat clear_color[4]; mutable long long frameno = 0; - class ProgramFactory; std::unique_ptr const program_factory; mir::geometry::Rectangle viewport; glm::mat4 screen_to_gl_coords; diff --git a/src/surface_tracker.cpp b/src/surface_tracker.cpp index 15aeffc..06e3da3 100644 --- a/src/surface_tracker.cpp +++ b/src/surface_tracker.cpp @@ -33,7 +33,7 @@ void SurfaceTracker::remove(miral::Window const& window) map.erase(it); } -miral::Window SurfaceTracker::get(mir::scene::Surface const* surface) +miral::Window SurfaceTracker::get(mir::scene::Surface const* surface) const { auto it = map.find(surface); if (it == map.end()) diff --git a/src/surface_tracker.h b/src/surface_tracker.h index e6b2679..bd4bb88 100644 --- a/src/surface_tracker.h +++ b/src/surface_tracker.h @@ -29,7 +29,7 @@ class SurfaceTracker public: void add(miral::Window const&); void remove(miral::Window const&); - miral::Window get(mir::scene::Surface const*); + miral::Window get(mir::scene::Surface const*) const; private: std::map map;