[PATCH weston v2 6/7] gl-renderer: implement surface_copy_content
Pekka Paalanen
ppaalanen at gmail.com
Wed Feb 25 03:06:02 PST 2015
From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
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 at collabora.co.uk>
v1 Tested-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
src/gl-renderer.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 149 insertions(+)
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 8a7a44b..8835765 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2012 Intel Corporation
+ * Copyright © 2015 Collabora, Ltd.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -1364,6 +1365,151 @@ gl_renderer_surface_set_color(struct weston_surface *surface,
}
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
surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
{
int i;
@@ -1992,6 +2138,9 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
gr->base.attach = gl_renderer_attach;
gr->base.surface_set_color = gl_renderer_surface_set_color;
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);
if (gr->egl_display == EGL_NO_DISPLAY) {
--
2.0.5
More information about the wayland-devel
mailing list