diff --git a/Userland/Libraries/LibAccelGfx/CMakeLists.txt b/Userland/Libraries/LibAccelGfx/CMakeLists.txt index 5717f05a2e..74744c2ce9 100644 --- a/Userland/Libraries/LibAccelGfx/CMakeLists.txt +++ b/Userland/Libraries/LibAccelGfx/CMakeLists.txt @@ -5,6 +5,7 @@ if (HAS_ACCELERATED_GRAPHICS) Canvas.cpp Context.cpp Painter.cpp + Program.cpp ) serenity_lib(LibAccelGfx accelgfx) diff --git a/Userland/Libraries/LibAccelGfx/Painter.cpp b/Userland/Libraries/LibAccelGfx/Painter.cpp index 812787f02c..df35ec85a2 100644 --- a/Userland/Libraries/LibAccelGfx/Painter.cpp +++ b/Userland/Libraries/LibAccelGfx/Painter.cpp @@ -42,6 +42,21 @@ Gfx::FloatRect Painter::to_clip_space(Gfx::FloatRect const& screen_rect) const return { x, y, width, height }; } +char const* vertex_shader_source = R"( +attribute vec2 aVertexPosition; +void main() { + gl_Position = vec4(aVertexPosition, 0.0, 1.0); +} +)"; + +char const* solid_color_fragment_shader_source = R"( +precision mediump float; +uniform vec4 uColor; +void main() { + gl_FragColor = uColor; +} +)"; + OwnPtr Painter::create() { auto& context = Context::the(); @@ -50,6 +65,7 @@ OwnPtr Painter::create() Painter::Painter(Context& context) : m_context(context) + , m_rectangle_program(Program::create(vertex_shader_source, solid_color_fragment_shader_source)) { m_state_stack.empend(State()); } @@ -71,24 +87,6 @@ void Painter::fill_rect(Gfx::IntRect rect, Gfx::Color color) fill_rect(rect.to_type(), color); } -static GLuint create_shader(GLenum type, char const* source) -{ - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, nullptr); - glCompileShader(shader); - - int success; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (!success) { - char buffer[512]; - glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer); - dbgln("GLSL shader compilation failed: {}", buffer); - VERIFY_NOT_REACHED(); - } - - return shader; -} - static Array rect_to_vertices(Gfx::FloatRect const& rect) { return { @@ -109,45 +107,12 @@ void Painter::fill_rect(Gfx::FloatRect rect, Gfx::Color color) auto vertices = rect_to_vertices(to_clip_space(transform().map(rect))); - char const* vertex_shader_source = R"( - attribute vec2 position; - void main() { - gl_Position = vec4(position, 0.0, 1.0); - } -)"; - - char const* fragment_shader_source = R"( - precision mediump float; - uniform vec4 uColor; - void main() { - gl_FragColor = uColor; - } -)"; - auto [red, green, blue, alpha] = gfx_color_to_opengl_color(color); - GLuint vertex_shader = create_shader(GL_VERTEX_SHADER, vertex_shader_source); - GLuint fragment_shader = create_shader(GL_FRAGMENT_SHADER, fragment_shader_source); + m_rectangle_program.use(); - GLuint program = glCreateProgram(); - - glAttachShader(program, vertex_shader); - glAttachShader(program, fragment_shader); - glLinkProgram(program); - - int linked; - glGetProgramiv(program, GL_LINK_STATUS, &linked); - if (!linked) { - char buffer[512]; - glGetProgramInfoLog(program, sizeof(buffer), nullptr, buffer); - dbgln("GLSL program linking failed: {}", buffer); - VERIFY_NOT_REACHED(); - } - - glUseProgram(program); - - GLuint position_attribute = glGetAttribLocation(program, "position"); - GLuint color_uniform = glGetUniformLocation(program, "uColor"); + GLuint position_attribute = m_rectangle_program.get_attribute_location("aVertexPosition"); + GLuint color_uniform = m_rectangle_program.get_uniform_location("uColor"); glUniform4f(color_uniform, red, green, blue, alpha); @@ -158,10 +123,6 @@ void Painter::fill_rect(Gfx::FloatRect rect, Gfx::Color color) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDeleteShader(vertex_shader); - glDeleteShader(fragment_shader); - glDeleteProgram(program); } void Painter::save() diff --git a/Userland/Libraries/LibAccelGfx/Painter.h b/Userland/Libraries/LibAccelGfx/Painter.h index 9e0c6f6b7b..48937c09b7 100644 --- a/Userland/Libraries/LibAccelGfx/Painter.h +++ b/Userland/Libraries/LibAccelGfx/Painter.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,8 @@ private: [[nodiscard]] Gfx::FloatRect to_clip_space(Gfx::FloatRect const& screen_rect) const; Vector m_state_stack; + + Program m_rectangle_program; }; } diff --git a/Userland/Libraries/LibAccelGfx/Program.cpp b/Userland/Libraries/LibAccelGfx/Program.cpp new file mode 100644 index 0000000000..dab717f157 --- /dev/null +++ b/Userland/Libraries/LibAccelGfx/Program.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#define GL_GLEXT_PROTOTYPES + +#include +#include +#include +#include +#include + +namespace AccelGfx { + +static GLuint create_shader(GLenum type, char const* source) +{ + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, nullptr); + glCompileShader(shader); + + int success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char buffer[512]; + glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer); + dbgln("GLSL shader compilation failed: {}", buffer); + VERIFY_NOT_REACHED(); + } + + return shader; +} + +Program Program::create(char const* vertex_shader_source, char const* fragment_shader_source) +{ + GLuint program = glCreateProgram(); + + auto vertex_shader = create_shader(GL_VERTEX_SHADER, vertex_shader_source); + auto fragment_shader = create_shader(GL_FRAGMENT_SHADER, fragment_shader_source); + + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + glLinkProgram(program); + + int linked; + glGetProgramiv(program, GL_LINK_STATUS, &linked); + if (!linked) { + char buffer[512]; + glGetProgramInfoLog(program, sizeof(buffer), nullptr, buffer); + dbgln("GLSL program linking failed: {}", buffer); + VERIFY_NOT_REACHED(); + } + + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + + return Program { program }; +} + +void Program::use() +{ + glUseProgram(m_id); +} + +GLuint Program::get_attribute_location(char const* name) +{ + return glGetAttribLocation(m_id, name); +} + +GLuint Program::get_uniform_location(char const* name) +{ + return glGetUniformLocation(m_id, name); +} + +Program::~Program() +{ + glDeleteProgram(m_id); +} + +} diff --git a/Userland/Libraries/LibAccelGfx/Program.h b/Userland/Libraries/LibAccelGfx/Program.h new file mode 100644 index 0000000000..2de71da82d --- /dev/null +++ b/Userland/Libraries/LibAccelGfx/Program.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace AccelGfx { + +class Program { + AK_MAKE_NONCOPYABLE(Program); + +public: + static Program create(char const* vertex_shader_source, char const* fragment_shader_source); + + void use(); + GLuint get_attribute_location(char const* name); + GLuint get_uniform_location(char const* name); + + ~Program(); + +private: + Program(GLuint id) + : m_id(id) + { + } + + GLuint m_id { 0 }; +}; + +}