Compare commits

...

10 Commits

Author SHA1 Message Date
Andri Yngvason 6c01d80f5f render: Get damage checking working 2019-10-29 16:02:22 +00:00
Andri Yngvason 36eb48d0ca render: Add damage checking shader program 2019-10-28 19:04:00 +00:00
Andri Yngvason a62a9c43fc render: Pass width and height as attributes 2019-10-28 18:56:51 +00:00
Andri Yngvason f6314ba4d6 render: zero terminate shader code 2019-10-28 18:10:32 +00:00
Andri Yngvason 3e2e31dde2 render: Define constants for attribute indices 2019-10-28 17:32:16 +00:00
Andri Yngvason 3da3a59604 Add shaders for texture damage checking 2019-10-27 22:27:55 +00:00
Andri Yngvason 527d0caea7 render: Load shaders from files 2019-10-27 22:26:58 +00:00
Andri Yngvason 3d8bb78920 render: Create a function to read a shader from a file 2019-10-27 22:12:53 +00:00
Andri Yngvason a4503e5e14 render: Working on damage tracking on the GPU 2019-10-27 21:29:40 +00:00
Andri Yngvason b73b812bf8 Keep the last texture 2019-10-26 21:12:15 +00:00
8 changed files with 266 additions and 53 deletions

View File

@ -18,6 +18,7 @@
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <pixman.h>
struct dmabuf_frame;
@ -25,12 +26,15 @@ struct renderer {
EGLDisplay display;
EGLSurface surface;
EGLContext context;
GLuint last_texture;
GLuint dmabuf_shader_program;
GLuint texture_shader_program;
GLuint damage_shader_program;
uint32_t width;
uint32_t height;
GLint read_format;
GLint read_type;
struct pixman_region16 current_damage;
};
int renderer_init(struct renderer* self, uint32_t width, uint32_t height);
@ -43,3 +47,5 @@ int render_framebuffer(struct renderer* self, const void* addr, uint32_t format,
/* Copy a horizontal stripe from the GL frame into a pixel buffer */
void render_copy_pixels(struct renderer* self, void* dst, uint32_t y,
uint32_t height);
void render_check_damage(struct renderer* self, GLenum target, GLuint tex);

View File

@ -0,0 +1,12 @@
#extension GL_OES_EGL_image_external: require
precision mediump float;
uniform samplerExternalOES u_tex;
varying vec2 v_texture;
void main()
{
gl_FragColor = texture2D(u_tex, v_texture);
}

View File

@ -0,0 +1,10 @@
attribute vec2 pos;
attribute vec2 texture;
varying vec2 v_texture;
void main()
{
v_texture = vec2(texture.s, 1.0 - texture.t);
gl_Position = vec4(pos, 0, 1);
}

View File

@ -0,0 +1,44 @@
precision mediump float;
uniform sampler2D tex0;
uniform sampler2D tex1;
varying vec2 v_texture;
varying float v_width;
varying float v_height;
float get_pixel_damage(vec2 coord)
{
vec3 diff = texture2D(tex0, coord).rgb - texture2D(tex1, coord).rgb;
vec3 absdiff = ceil(abs(diff));
return clamp(absdiff.r + absdiff.g + absdiff.b, 0.0, 1.0);
}
float get_damage(vec2 coord)
{
float x_off = 2.0 / v_width;
float y_off = 2.0 / v_height;
float ix = v_width * (1.0 + coord.x) * 2.0;
float iy = v_height * (1.0 + coord.y) * 2.0;
float x_start = mod(ix, 32.0) / v_width / 2.0;
float y_start = mod(iy, 32.0) / v_height / 2.0;
float color = 0.0;
for (float y = 0.0; y < 32.0; y += 1.0)
for (float x = 0.0; x < 32.0; x += 1.0) {
color += get_pixel_damage(vec2(coord.x - x_start + x * x_off,
coord.y - y_start + y * y_off));
}
return clamp(color, 0.0, 1.0);
}
void main()
{
float color = get_damage(v_texture);
gl_FragColor = vec4(color, color, color, 1.0);
}

View File

@ -0,0 +1,15 @@
attribute vec2 pos;
attribute vec2 texture;
attribute float width;
attribute float height;
varying vec2 v_texture;
varying float v_width;
varying float v_height;
void main() {
v_texture = texture;
v_width = width;
v_height = height;
gl_Position = vec4(pos, 0, 1);
}

View File

@ -0,0 +1,10 @@
precision mediump float;
uniform sampler2D u_tex;
varying vec2 v_texture;
void main()
{
gl_FragColor = texture2D(u_tex, v_texture);
}

View File

@ -0,0 +1,10 @@
attribute vec2 pos;
attribute vec2 texture;
varying vec2 v_texture;
void main()
{
v_texture = texture;
gl_Position = vec4(pos, 0, 1);
}

View File

@ -33,6 +33,13 @@
#define MAYBE_UNUSED __attribute__((unused))
enum {
ATTR_INDEX_POS = 0,
ATTR_INDEX_TEXTURE,
ATTR_INDEX_WIDTH,
ATTR_INDEX_HEIGHT,
};
#define XSTR(s) STR(s)
#define STR(s) #s
@ -158,52 +165,74 @@ static int gl_load_shader(GLuint* dst, const char* source, GLenum type)
return 0;
}
static const char dmabuf_vertex_src[] =
"attribute vec2 pos;\n"
"attribute vec2 texture;\n"
"varying vec2 v_texture;\n"
"void main() {\n"
" v_texture = vec2(texture.s, 1.0 - texture.t);\n"
" gl_Position = vec4(pos, 0, 1);\n"
"}\n";
static const char dmabuf_fragment_src[] =
"#extension GL_OES_EGL_image_external: require\n\n"
"precision mediump float;\n"
"uniform samplerExternalOES u_tex;\n"
"varying vec2 v_texture;\n"
"void main() {\n"
" gl_FragColor = texture2D(u_tex, v_texture);\n"
"}\n";
static const char texture_vertex_src[] =
"attribute vec2 pos;\n"
"attribute vec2 texture;\n"
"varying vec2 v_texture;\n"
"void main() {\n"
" v_texture = texture;\n"
" gl_Position = vec4(pos, 0, 1);\n"
"}\n";
static const char texture_fragment_src[] =
"precision mediump float;\n"
"uniform sampler2D u_tex;\n"
"varying vec2 v_texture;\n"
"void main() {\n"
" gl_FragColor = texture2D(u_tex, v_texture);\n"
"}\n";
static int gl_compile_shader_program(GLuint* dst, const char* vertex_src,
const char* fragment_src)
static char* read_file(const char* path)
{
FILE* stream = fopen(path, "r");
if (!stream)
return NULL;
size_t size = 4096;
size_t rsize = 0;
char* contents = malloc(size);
if (!contents)
goto alloc_failure;
while (1) {
rsize += fread(contents + rsize, 1, size - rsize, stream);
if (rsize < size)
break;
size *= 2;
contents = realloc(contents, size);
if (!contents)
goto read_failure;
}
if (ferror(stream))
goto read_failure;
if (rsize == size) {
contents = realloc(contents, size + 1);
if (!contents)
goto read_failure;
}
contents[rsize] = '\0';
fclose(stream);
return contents;
read_failure:
free(contents);
alloc_failure:
fclose(stream);
return NULL;
}
static int gl_load_shader_from_file(GLuint* dst, const char* path, GLenum type)
{
char* source = read_file(path);
if (!source)
return -1;
int rc = gl_load_shader(dst, source, type);
free(source);
return rc;
}
static int gl_compile_shader_program(GLuint* dst, const char* vertex_path,
const char* fragment_path)
{
int rc = -1;
GLuint vertex, fragment;
if (gl_load_shader(&vertex, vertex_src, GL_VERTEX_SHADER) < 0)
if (gl_load_shader_from_file(&vertex, vertex_path, GL_VERTEX_SHADER) < 0)
return -1;
if (gl_load_shader(&fragment, fragment_src, GL_FRAGMENT_SHADER) < 0)
if (gl_load_shader_from_file(&fragment, fragment_path,
GL_FRAGMENT_SHADER) < 0)
goto fragment_failure;
GLuint program = glCreateProgram();
@ -211,8 +240,10 @@ static int gl_compile_shader_program(GLuint* dst, const char* vertex_src,
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glBindAttribLocation(program, 0, "pos");
glBindAttribLocation(program, 1, "texture");
glBindAttribLocation(program, ATTR_INDEX_POS, "pos");
glBindAttribLocation(program, ATTR_INDEX_TEXTURE, "texture");
glBindAttribLocation(program, ATTR_INDEX_WIDTH, "width");
glBindAttribLocation(program, ATTR_INDEX_HEIGHT, "height");
glLinkProgram(program);
@ -239,7 +270,7 @@ void gl_clear(void)
glClear(GL_COLOR_BUFFER_BIT);
}
void gl_render(void)
void gl_render(struct renderer* self)
{
static const GLfloat s_vertices[4][2] = {
{ -1.0, 1.0 },
@ -257,8 +288,13 @@ void gl_render(void)
gl_clear();
glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, s_vertices);
glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, s_positions);
glVertexAttribPointer(ATTR_INDEX_POS, 2, GL_FLOAT, GL_FALSE, 0,
s_vertices);
glVertexAttribPointer(ATTR_INDEX_TEXTURE, 2, GL_FLOAT, GL_FALSE, 0,
s_positions);
glVertexAttrib1f(ATTR_INDEX_WIDTH, self->width);
glVertexAttrib1f(ATTR_INDEX_HEIGHT, self->height);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
@ -271,17 +307,25 @@ void gl_render(void)
void renderer_destroy(struct renderer* self)
{
if (self->last_texture)
glDeleteTextures(1, &self->last_texture);
glDeleteProgram(self->dmabuf_shader_program);
glDeleteProgram(self->texture_shader_program);
glDeleteProgram(self->damage_shader_program);
eglMakeCurrent(self->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
eglDestroySurface(self->display, self->surface);
eglDestroyContext(self->display, self->context);
eglTerminate(self->display);
pixman_region_fini(&self->current_damage);
}
int renderer_init(struct renderer* self, uint32_t width, uint32_t height)
{
pixman_region_init(&self->current_damage);
if (!eglBindAPI(EGL_OPENGL_ES_API))
return -1;
@ -344,13 +388,18 @@ int renderer_init(struct renderer* self, uint32_t width, uint32_t height)
goto late_extension_failure;
if (gl_compile_shader_program(&self->dmabuf_shader_program,
dmabuf_vertex_src,
dmabuf_fragment_src) < 0)
"shaders/dmabuf-vertex.glsl",
"shaders/dmabuf-fragment.glsl") < 0)
goto shader_failure;
if (gl_compile_shader_program(&self->texture_shader_program,
texture_vertex_src,
texture_fragment_src) < 0)
"shaders/texture-vertex.glsl",
"shaders/texture-fragment.glsl") < 0)
goto shader_failure;
if (gl_compile_shader_program(&self->damage_shader_program,
"shaders/texture-damage-vertex.glsl",
"shaders/texture-damage-fragment.glsl") < 0)
goto shader_failure;
self->width = width;
@ -427,10 +476,16 @@ int render_dmabuf_frame(struct renderer* self, struct dmabuf_frame* frame)
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
glUseProgram(self->dmabuf_shader_program);
gl_render();
glUniform1i(glGetUniformLocation(self->dmabuf_shader_program, "u_tex"), 0);
glViewport(0, 0, self->width, self->height);
gl_render(self);
if (self->last_texture)
glDeleteTextures(1, &self->last_texture);
self->last_texture = tex;
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(1, &tex);
eglDestroyImageKHR(self->display, image);
return 0;
@ -448,17 +503,29 @@ int render_framebuffer(struct renderer* self, const void* addr, uint32_t format,
if (gl_format_from_wl_shm(&gl_format, format) < 0)
return -1;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / 4);
glTexImage2D(GL_TEXTURE_2D, 0, self->read_format, width, height, 0,
gl_format, GL_UNSIGNED_BYTE, addr);
glGenerateMipmap(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
render_check_damage(self, GL_TEXTURE_2D, tex);
glUseProgram(self->texture_shader_program);
gl_render();
glUniform1i(glGetUniformLocation(self->texture_shader_program, "u_tex"), 0);
glViewport(0, 0, self->width, self->height);
gl_render(self);
if (self->last_texture)
glDeleteTextures(1, &self->last_texture);
self->last_texture = tex;
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(1, &tex);
return 0;
}
@ -471,3 +538,42 @@ void render_copy_pixels(struct renderer* self, void* dst, uint32_t y,
glReadPixels(0, y, self->width, height, self->read_format,
self->read_type, dst);
}
void render_check_damage(struct renderer* self, GLenum target, GLuint tex)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, tex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(target, self->last_texture);
glUseProgram(self->damage_shader_program);
glUniform1i(glGetUniformLocation(self->damage_shader_program, "tex0"), 0);
glUniform1i(glGetUniformLocation(self->damage_shader_program, "tex1"), 1);
int width = self->width / 32;
int height = self->height / 32;
uint32_t* buffer = malloc(width * height * 4);
if (!buffer)
return;
glViewport(0, 0, width, height);
gl_render(self);
glReadPixels(0, 0, width, height, self->read_format, self->read_type,
buffer);
struct pixman_region16* damage = &self->current_damage;
pixman_region_clear(damage);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
if (buffer[y * width + x] & 0xff00)
pixman_region_union_rect(damage, damage,
x * 32, y * 32,
32, 32);
free(buffer);
}