diff options
Diffstat (limited to '')
-rw-r--r-- | src/ui/widget/canvas/glgraphics.h | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/ui/widget/canvas/glgraphics.h b/src/ui/widget/canvas/glgraphics.h new file mode 100644 index 0000000..7cb6ecf --- /dev/null +++ b/src/ui/widget/canvas/glgraphics.h @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * OpenGL display backend. + * Copyright (C) 2022 PBS <pbs3141@gmail.com> + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_WIDGET_CANVAS_GLGRAPHICS_H +#define INKSCAPE_UI_WIDGET_CANVAS_GLGRAPHICS_H + +#include <mutex> +#include <epoxy/gl.h> +#include "graphics.h" +#include "texturecache.h" + +namespace Inkscape { +namespace UI { +namespace Widget { +class Stores; +class Prefs; +class PixelStreamer; + +template <GLuint type> +struct Shader : boost::noncopyable +{ + GLuint id; + Shader(char const *src) { id = glCreateShader(type); glShaderSource(id, 1, &src, nullptr); glCompileShader(id); } + ~Shader() { glDeleteShader(id); } +}; +using GShader = Shader<GL_GEOMETRY_SHADER>; +using VShader = Shader<GL_VERTEX_SHADER>; +using FShader = Shader<GL_FRAGMENT_SHADER>; + +struct Program : boost::noncopyable +{ + GLuint id = 0; + void create(VShader const &v, FShader const &f) { id = glCreateProgram(); glAttachShader(id, v.id); glAttachShader(id, f.id); glLinkProgram(id); } + void create(VShader const &v, const GShader &g, FShader const &f) { id = glCreateProgram(); glAttachShader(id, v.id); glAttachShader(id, g.id); glAttachShader(id, f.id); glLinkProgram(id); } + auto loc(char const *str) const { return glGetUniformLocation(id, str); } + ~Program() { glDeleteProgram(id); } +}; + +class VAO +{ +public: + GLuint vao = 0; + GLuint vbuf; + + VAO() = default; + VAO(GLuint vao, GLuint vbuf) : vao(vao), vbuf(vbuf) {} + VAO(VAO &&other) noexcept { movefrom(other); } + VAO &operator=(VAO &&other) noexcept { reset(); movefrom(other); return *this; } + ~VAO() { reset(); } + +private: + void reset() noexcept { if (vao) { glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbuf); } } + void movefrom(VAO &other) noexcept { vao = other.vao; vbuf = other.vbuf; other.vao = 0; } +}; + +struct GLFragment +{ + Texture texture; + Texture outline_texture; +}; + +class GLGraphics : public Graphics +{ +public: + GLGraphics(Prefs const &prefs, Stores const &stores, PageInfo const &pi); + ~GLGraphics() override; + + void set_scale_factor(int scale) override { scale_factor = scale; } + void set_outlines_enabled(bool) override; + void set_background_in_stores(bool enabled) override { background_in_stores = enabled; } + void set_colours(uint32_t p, uint32_t d, uint32_t b) override { page = p; desk = d; border = b; } + + void recreate_store(Geom::IntPoint const &dimensions) override; + void shift_store(Fragment const &dest) override; + void swap_stores() override; + void fast_snapshot_combine() override; + void snapshot_combine(Fragment const &dest) override; + void invalidate_snapshot() override; + + bool is_opengl() const override { return true; } + void invalidated_glstate() override { state = State::None; } + + Cairo::RefPtr<Cairo::ImageSurface> request_tile_surface(Geom::IntRect const &rect, bool nogl) override; + void draw_tile(Fragment const &fragment, Cairo::RefPtr<Cairo::ImageSurface> surface, Cairo::RefPtr<Cairo::ImageSurface> outline_surface) override; + void junk_tile_surface(Cairo::RefPtr<Cairo::ImageSurface> surface) override; + + void paint_widget(Fragment const &view, PaintArgs const &args, Cairo::RefPtr<Cairo::Context> const &cr) override; + +private: + // Drawn content. + GLFragment store, snapshot; + + // OpenGL objects. + VAO rect; // Rectangle vertex data. + Program checker, shadow, texcopy, texcopydouble, outlineoverlay, xray, outlineoverlayxray; // Shaders + GLuint fbo; // Framebuffer object for rendering to stores. + + // Pixel streamer and texture cache for uploading pixel data to GPU. + std::unique_ptr<PixelStreamer> pixelstreamer; + std::unique_ptr<TextureCache> texturecache; + std::mutex ps_mutex; + + // For preventing unnecessary pipeline recreation. + enum class State { None, Widget, Stores, Tiles }; + State state; + void setup_stores_pipeline(); + void setup_tiles_pipeline(); + void setup_widget_pipeline(Fragment const &view); + + // For caching frequently-used uniforms. + GLuint mat_loc, trans_loc, subrect_loc, tex_loc, texoutline_loc; + + // Dependency objects in canvas. + Prefs const &prefs; + Stores const &stores; + PageInfo const π + + // Backend-agnostic state. + int scale_factor = 1; + bool outlines_enabled = false; + bool background_in_stores = false; + uint32_t page, desk, border; +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_WIDGET_CANVAS_GLGRAPHICS_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |