gl-renderer: implement surface_copy_content
Taking the easy way, always do a rendering pass when copying any real buffer or texture. Will handle YUV formats, and makes it easy to always return data the right y-direction up. All the FBO GL state is created and torn down on every invocation, so this is a pretty naive implementation. If there was a wl_shm buffer giving the content to the surface, and the stride of the buffer was greater than width * bytes_per_pixel, then this implementation will return stride long rows, not width. Changes in v2: - simplify pack_color() - remove stride and format from the API Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> v1 Tested-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA@xddp.denso.co.jp> Reviewed-by: Daniel Stone <daniels@collabora.com>
This commit is contained in:
parent
aeb917ee5d
commit
eb35cbe2b1
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2012 Intel Corporation
|
* Copyright © 2012 Intel Corporation
|
||||||
|
* Copyright © 2015 Collabora, Ltd.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, distribute, and sell this software and
|
* Permission to use, copy, modify, distribute, and sell this software and
|
||||||
* its documentation for any purpose is hereby granted without fee, provided
|
* its documentation for any purpose is hereby granted without fee, provided
|
||||||
@ -1363,6 +1364,151 @@ gl_renderer_surface_set_color(struct weston_surface *surface,
|
|||||||
gs->shader = &gr->solid_shader;
|
gs->shader = &gr->solid_shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gl_renderer_surface_get_content_size(struct weston_surface *surface,
|
||||||
|
int *width, int *height)
|
||||||
|
{
|
||||||
|
struct gl_surface_state *gs = get_surface_state(surface);
|
||||||
|
|
||||||
|
if (gs->buffer_type == BUFFER_TYPE_NULL) {
|
||||||
|
*width = 0;
|
||||||
|
*height = 0;
|
||||||
|
} else {
|
||||||
|
*width = gs->pitch;
|
||||||
|
*height = gs->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
pack_color(pixman_format_code_t format, float *c)
|
||||||
|
{
|
||||||
|
uint8_t r = round(c[0] * 255.0f);
|
||||||
|
uint8_t g = round(c[1] * 255.0f);
|
||||||
|
uint8_t b = round(c[2] * 255.0f);
|
||||||
|
uint8_t a = round(c[3] * 255.0f);
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case PIXMAN_a8b8g8r8:
|
||||||
|
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gl_renderer_surface_copy_content(struct weston_surface *surface,
|
||||||
|
void *target, size_t size,
|
||||||
|
int src_x, int src_y,
|
||||||
|
int width, int height)
|
||||||
|
{
|
||||||
|
static const GLfloat verts[4 * 2] = {
|
||||||
|
0.0f, 0.0f,
|
||||||
|
1.0f, 0.0f,
|
||||||
|
1.0f, 1.0f,
|
||||||
|
0.0f, 1.0f
|
||||||
|
};
|
||||||
|
static const GLfloat projmat_normal[16] = { /* transpose */
|
||||||
|
2.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 2.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
-1.0f, -1.0f, 0.0f, 1.0f
|
||||||
|
};
|
||||||
|
static const GLfloat projmat_yinvert[16] = { /* transpose */
|
||||||
|
2.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, -2.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
-1.0f, 1.0f, 0.0f, 1.0f
|
||||||
|
};
|
||||||
|
const pixman_format_code_t format = PIXMAN_a8b8g8r8;
|
||||||
|
const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
|
||||||
|
const GLenum gl_format = GL_RGBA; /* PIXMAN_a8b8g8r8 little-endian */
|
||||||
|
struct gl_renderer *gr = get_renderer(surface->compositor);
|
||||||
|
struct gl_surface_state *gs = get_surface_state(surface);
|
||||||
|
int cw, ch;
|
||||||
|
GLuint fbo;
|
||||||
|
GLuint tex;
|
||||||
|
GLenum status;
|
||||||
|
const GLfloat *proj;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
gl_renderer_surface_get_content_size(surface, &cw, &ch);
|
||||||
|
|
||||||
|
switch (gs->buffer_type) {
|
||||||
|
case BUFFER_TYPE_NULL:
|
||||||
|
return -1;
|
||||||
|
case BUFFER_TYPE_SOLID:
|
||||||
|
*(uint32_t *)target = pack_color(format, gs->color);
|
||||||
|
return 0;
|
||||||
|
case BUFFER_TYPE_SHM:
|
||||||
|
gl_renderer_flush_damage(surface);
|
||||||
|
/* fall through */
|
||||||
|
case BUFFER_TYPE_EGL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenTextures(1, &tex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch,
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
|
GL_TEXTURE_2D, tex, 0);
|
||||||
|
|
||||||
|
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
weston_log("%s: fbo error: %#x\n", __func__, status);
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glDeleteTextures(1, &tex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
glViewport(0, 0, cw, ch);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
use_shader(gr, gs->shader);
|
||||||
|
if (gs->y_inverted)
|
||||||
|
proj = projmat_normal;
|
||||||
|
else
|
||||||
|
proj = projmat_yinvert;
|
||||||
|
|
||||||
|
glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj);
|
||||||
|
glUniform1f(gs->shader->alpha_uniform, 1.0f);
|
||||||
|
|
||||||
|
for (i = 0; i < gs->num_textures; i++) {
|
||||||
|
glUniform1i(gs->shader->tex_uniforms[i], i);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
glBindTexture(gs->target, gs->textures[i]);
|
||||||
|
glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* position: */
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
/* texcoord: */
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, verts);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(1);
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, bytespp);
|
||||||
|
glReadPixels(src_x, src_y, width, height, gl_format,
|
||||||
|
GL_UNSIGNED_BYTE, target);
|
||||||
|
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glDeleteTextures(1, &tex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
|
surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
|
||||||
{
|
{
|
||||||
@ -1992,6 +2138,9 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
|
|||||||
gr->base.attach = gl_renderer_attach;
|
gr->base.attach = gl_renderer_attach;
|
||||||
gr->base.surface_set_color = gl_renderer_surface_set_color;
|
gr->base.surface_set_color = gl_renderer_surface_set_color;
|
||||||
gr->base.destroy = gl_renderer_destroy;
|
gr->base.destroy = gl_renderer_destroy;
|
||||||
|
gr->base.surface_get_content_size =
|
||||||
|
gl_renderer_surface_get_content_size;
|
||||||
|
gr->base.surface_copy_content = gl_renderer_surface_copy_content;
|
||||||
|
|
||||||
gr->egl_display = eglGetDisplay(display);
|
gr->egl_display = eglGetDisplay(display);
|
||||||
if (gr->egl_display == EGL_NO_DISPLAY) {
|
if (gr->egl_display == EGL_NO_DISPLAY) {
|
||||||
|
Loading…
Reference in New Issue
Block a user