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 <GLES2/gl2.h>
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
#include <pixman.h>
|
||||||
|
|
||||||
struct dmabuf_frame;
|
struct dmabuf_frame;
|
||||||
|
|
||||||
|
@ -25,12 +26,15 @@ struct renderer {
|
||||||
EGLDisplay display;
|
EGLDisplay display;
|
||||||
EGLSurface surface;
|
EGLSurface surface;
|
||||||
EGLContext context;
|
EGLContext context;
|
||||||
|
GLuint last_texture;
|
||||||
GLuint dmabuf_shader_program;
|
GLuint dmabuf_shader_program;
|
||||||
GLuint texture_shader_program;
|
GLuint texture_shader_program;
|
||||||
|
GLuint damage_shader_program;
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
GLint read_format;
|
GLint read_format;
|
||||||
GLint read_type;
|
GLint read_type;
|
||||||
|
struct pixman_region16 current_damage;
|
||||||
};
|
};
|
||||||
|
|
||||||
int renderer_init(struct renderer* self, uint32_t width, uint32_t height);
|
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 */
|
/* Copy a horizontal stripe from the GL frame into a pixel buffer */
|
||||||
void render_copy_pixels(struct renderer* self, void* dst, uint32_t y,
|
void render_copy_pixels(struct renderer* self, void* dst, uint32_t y,
|
||||||
uint32_t height);
|
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))
|
#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 XSTR(s) STR(s)
|
||||||
#define STR(s) #s
|
#define STR(s) #s
|
||||||
|
|
||||||
|
@ -158,52 +165,74 @@ static int gl_load_shader(GLuint* dst, const char* source, GLenum type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char dmabuf_vertex_src[] =
|
static char* read_file(const char* path)
|
||||||
"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)
|
|
||||||
{
|
{
|
||||||
|
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;
|
int rc = -1;
|
||||||
GLuint vertex, fragment;
|
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;
|
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;
|
goto fragment_failure;
|
||||||
|
|
||||||
GLuint program = glCreateProgram();
|
GLuint program = glCreateProgram();
|
||||||
|
@ -211,8 +240,10 @@ static int gl_compile_shader_program(GLuint* dst, const char* vertex_src,
|
||||||
glAttachShader(program, vertex);
|
glAttachShader(program, vertex);
|
||||||
glAttachShader(program, fragment);
|
glAttachShader(program, fragment);
|
||||||
|
|
||||||
glBindAttribLocation(program, 0, "pos");
|
glBindAttribLocation(program, ATTR_INDEX_POS, "pos");
|
||||||
glBindAttribLocation(program, 1, "texture");
|
glBindAttribLocation(program, ATTR_INDEX_TEXTURE, "texture");
|
||||||
|
glBindAttribLocation(program, ATTR_INDEX_WIDTH, "width");
|
||||||
|
glBindAttribLocation(program, ATTR_INDEX_HEIGHT, "height");
|
||||||
|
|
||||||
glLinkProgram(program);
|
glLinkProgram(program);
|
||||||
|
|
||||||
|
@ -239,7 +270,7 @@ void gl_clear(void)
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_render(void)
|
void gl_render(struct renderer* self)
|
||||||
{
|
{
|
||||||
static const GLfloat s_vertices[4][2] = {
|
static const GLfloat s_vertices[4][2] = {
|
||||||
{ -1.0, 1.0 },
|
{ -1.0, 1.0 },
|
||||||
|
@ -257,8 +288,13 @@ void gl_render(void)
|
||||||
|
|
||||||
gl_clear();
|
gl_clear();
|
||||||
|
|
||||||
glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, s_vertices);
|
glVertexAttribPointer(ATTR_INDEX_POS, 2, GL_FLOAT, GL_FALSE, 0,
|
||||||
glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, s_positions);
|
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(0);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
|
@ -271,17 +307,25 @@ void gl_render(void)
|
||||||
|
|
||||||
void renderer_destroy(struct renderer* self)
|
void renderer_destroy(struct renderer* self)
|
||||||
{
|
{
|
||||||
|
if (self->last_texture)
|
||||||
|
glDeleteTextures(1, &self->last_texture);
|
||||||
|
|
||||||
glDeleteProgram(self->dmabuf_shader_program);
|
glDeleteProgram(self->dmabuf_shader_program);
|
||||||
glDeleteProgram(self->texture_shader_program);
|
glDeleteProgram(self->texture_shader_program);
|
||||||
|
glDeleteProgram(self->damage_shader_program);
|
||||||
eglMakeCurrent(self->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
eglMakeCurrent(self->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||||
EGL_NO_CONTEXT);
|
EGL_NO_CONTEXT);
|
||||||
eglDestroySurface(self->display, self->surface);
|
eglDestroySurface(self->display, self->surface);
|
||||||
eglDestroyContext(self->display, self->context);
|
eglDestroyContext(self->display, self->context);
|
||||||
eglTerminate(self->display);
|
eglTerminate(self->display);
|
||||||
|
|
||||||
|
pixman_region_fini(&self->current_damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
int renderer_init(struct renderer* self, uint32_t width, uint32_t height)
|
int renderer_init(struct renderer* self, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
|
pixman_region_init(&self->current_damage);
|
||||||
|
|
||||||
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -344,13 +388,18 @@ int renderer_init(struct renderer* self, uint32_t width, uint32_t height)
|
||||||
goto late_extension_failure;
|
goto late_extension_failure;
|
||||||
|
|
||||||
if (gl_compile_shader_program(&self->dmabuf_shader_program,
|
if (gl_compile_shader_program(&self->dmabuf_shader_program,
|
||||||
dmabuf_vertex_src,
|
"shaders/dmabuf-vertex.glsl",
|
||||||
dmabuf_fragment_src) < 0)
|
"shaders/dmabuf-fragment.glsl") < 0)
|
||||||
goto shader_failure;
|
goto shader_failure;
|
||||||
|
|
||||||
if (gl_compile_shader_program(&self->texture_shader_program,
|
if (gl_compile_shader_program(&self->texture_shader_program,
|
||||||
texture_vertex_src,
|
"shaders/texture-vertex.glsl",
|
||||||
texture_fragment_src) < 0)
|
"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;
|
goto shader_failure;
|
||||||
|
|
||||||
self->width = width;
|
self->width = width;
|
||||||
|
@ -427,10 +476,16 @@ int render_dmabuf_frame(struct renderer* self, struct dmabuf_frame* frame)
|
||||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
|
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
|
||||||
|
|
||||||
glUseProgram(self->dmabuf_shader_program);
|
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);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glDeleteTextures(1, &tex);
|
|
||||||
eglDestroyImageKHR(self->display, image);
|
eglDestroyImageKHR(self->display, image);
|
||||||
|
|
||||||
return 0;
|
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)
|
if (gl_format_from_wl_shm(&gl_format, format) < 0)
|
||||||
return -1;
|
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);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / 4);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, self->read_format, width, height, 0,
|
glTexImage2D(GL_TEXTURE_2D, 0, self->read_format, width, height, 0,
|
||||||
gl_format, GL_UNSIGNED_BYTE, addr);
|
gl_format, GL_UNSIGNED_BYTE, addr);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
|
||||||
|
|
||||||
|
render_check_damage(self, GL_TEXTURE_2D, tex);
|
||||||
|
|
||||||
glUseProgram(self->texture_shader_program);
|
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);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glDeleteTextures(1, &tex);
|
|
||||||
|
|
||||||
return 0;
|
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,
|
glReadPixels(0, y, self->width, height, self->read_format,
|
||||||
self->read_type, dst);
|
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