mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:07:45 +00:00
LibAccelGfx: Compile all needed shaders during Painter construction
Instead of recompiling shaders on each paint command call we can compile them once.
This commit is contained in:
parent
1e85bf221d
commit
b7f8d7e357
5 changed files with 139 additions and 58 deletions
|
@ -5,6 +5,7 @@ if (HAS_ACCELERATED_GRAPHICS)
|
||||||
Canvas.cpp
|
Canvas.cpp
|
||||||
Context.cpp
|
Context.cpp
|
||||||
Painter.cpp
|
Painter.cpp
|
||||||
|
Program.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
serenity_lib(LibAccelGfx accelgfx)
|
serenity_lib(LibAccelGfx accelgfx)
|
||||||
|
|
|
@ -42,6 +42,21 @@ Gfx::FloatRect Painter::to_clip_space(Gfx::FloatRect const& screen_rect) const
|
||||||
return { x, y, width, height };
|
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> Painter::create()
|
OwnPtr<Painter> Painter::create()
|
||||||
{
|
{
|
||||||
auto& context = Context::the();
|
auto& context = Context::the();
|
||||||
|
@ -50,6 +65,7 @@ OwnPtr<Painter> Painter::create()
|
||||||
|
|
||||||
Painter::Painter(Context& context)
|
Painter::Painter(Context& context)
|
||||||
: m_context(context)
|
: m_context(context)
|
||||||
|
, m_rectangle_program(Program::create(vertex_shader_source, solid_color_fragment_shader_source))
|
||||||
{
|
{
|
||||||
m_state_stack.empend(State());
|
m_state_stack.empend(State());
|
||||||
}
|
}
|
||||||
|
@ -71,24 +87,6 @@ void Painter::fill_rect(Gfx::IntRect rect, Gfx::Color color)
|
||||||
fill_rect(rect.to_type<float>(), color);
|
fill_rect(rect.to_type<float>(), 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<GLfloat, 8> rect_to_vertices(Gfx::FloatRect const& rect)
|
static Array<GLfloat, 8> rect_to_vertices(Gfx::FloatRect const& rect)
|
||||||
{
|
{
|
||||||
return {
|
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)));
|
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);
|
auto [red, green, blue, alpha] = gfx_color_to_opengl_color(color);
|
||||||
|
|
||||||
GLuint vertex_shader = create_shader(GL_VERTEX_SHADER, vertex_shader_source);
|
m_rectangle_program.use();
|
||||||
GLuint fragment_shader = create_shader(GL_FRAGMENT_SHADER, fragment_shader_source);
|
|
||||||
|
|
||||||
GLuint program = glCreateProgram();
|
GLuint position_attribute = m_rectangle_program.get_attribute_location("aVertexPosition");
|
||||||
|
GLuint color_uniform = m_rectangle_program.get_uniform_location("uColor");
|
||||||
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");
|
|
||||||
|
|
||||||
glUniform4f(color_uniform, red, green, blue, alpha);
|
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);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
|
||||||
glDeleteShader(vertex_shader);
|
|
||||||
glDeleteShader(fragment_shader);
|
|
||||||
glDeleteProgram(program);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Painter::save()
|
void Painter::save()
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibAccelGfx/Canvas.h>
|
#include <LibAccelGfx/Canvas.h>
|
||||||
#include <LibAccelGfx/Forward.h>
|
#include <LibAccelGfx/Forward.h>
|
||||||
|
#include <LibAccelGfx/Program.h>
|
||||||
#include <LibGfx/AffineTransform.h>
|
#include <LibGfx/AffineTransform.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@ private:
|
||||||
[[nodiscard]] Gfx::FloatRect to_clip_space(Gfx::FloatRect const& screen_rect) const;
|
[[nodiscard]] Gfx::FloatRect to_clip_space(Gfx::FloatRect const& screen_rect) const;
|
||||||
|
|
||||||
Vector<State, 1> m_state_stack;
|
Vector<State, 1> m_state_stack;
|
||||||
|
|
||||||
|
Program m_rectangle_program;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
81
Userland/Libraries/LibAccelGfx/Program.cpp
Normal file
81
Userland/Libraries/LibAccelGfx/Program.cpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
|
||||||
|
#include <AK/Assertions.h>
|
||||||
|
#include <AK/Format.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
|
#include <LibAccelGfx/Program.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
Userland/Libraries/LibAccelGfx/Program.h
Normal file
35
Userland/Libraries/LibAccelGfx/Program.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Noncopyable.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
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 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue