Compare commits
10 Commits
master
...
shader-dam
Author | SHA1 | Date |
---|---|---|
Andri Yngvason | 6c01d80f5f | |
Andri Yngvason | 36eb48d0ca | |
Andri Yngvason | a62a9c43fc | |
Andri Yngvason | f6314ba4d6 | |
Andri Yngvason | 3e2e31dde2 | |
Andri Yngvason | 3da3a59604 | |
Andri Yngvason | 527d0caea7 | |
Andri Yngvason | 3d8bb78920 | |
Andri Yngvason | a4503e5e14 | |
Andri Yngvason | b73b812bf8 |
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
precision mediump float;
|
||||
|
||||
uniform sampler2D u_tex;
|
||||
|
||||
varying vec2 v_texture;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(u_tex, v_texture);
|
||||
}
|
|
@ -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);
|
||||
}
|
212
src/render.c
212
src/render.c
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue