VIGS: Support planar pixel formats 57/26357/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 16 Jun 2014 15:44:07 +0000 (19:44 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Tue, 19 Aug 2014 13:31:29 +0000 (17:31 +0400)
Planar pixel formats such as NV21 need to be
supported in order to be able to play video right
from decoder's output buffer, i.e. without
converting it to RGB. This is implemented via fragment
shader that takes Y and CbCr channels from two different
textures and combines them into a single RGB image

Change-Id: Ic4ba78fda7f077a05c1524313a31b1ba79e46f72
Signed-off-by: Stanislav Vorobiov <s.vorobiov@samsung.com>
14 files changed:
hw/vigs/vigs_comm.c
hw/vigs/vigs_comm.h
hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_gl_backend.h
hw/vigs/vigs_gl_backend_cgl.c
hw/vigs/vigs_gl_backend_glx.c
hw/vigs/vigs_gl_backend_wgl.c
hw/vigs/vigs_plane.h
hw/vigs/vigs_protocol.h
hw/vigs/vigs_server.c
hw/vigs/vigs_surface.h
hw/vigs/vigs_sw_backend.c
hw/vigs/vigs_utils.c
hw/vigs/vigs_utils.h

index 6e085170b0e2af8552bb1e7f67f3005d4cf9f7ba..de3b3c7c8dd62c3c866965853149008900207584 100644 (file)
@@ -195,9 +195,15 @@ static void vigs_comm_dispatch_set_plane(struct vigs_comm_batch_ops *ops,
                                          void *user_data,
                                          struct vigsp_cmd_set_plane_request *request)
 {
-    VIGS_LOG_TRACE("plane = %u, sfc_id = %u, src_rect = {%u, %u, %u, %u}, dst_x = %d, dst_y = %d, dst_size = {%u, %u}, z_pos = %d",
+    VIGS_LOG_TRACE("plane = %u, width = %u, height = %u, format = %u, surfaces = {%u, %u, %u, %u}, src_rect = {%u, %u, %u, %u}, dst_x = %d, dst_y = %d, dst_size = {%u, %u}, z_pos = %d",
                    request->plane,
-                   request->sfc_id,
+                   request->width,
+                   request->height,
+                   request->format,
+                   request->surfaces[0],
+                   request->surfaces[1],
+                   request->surfaces[2],
+                   request->surfaces[3],
                    request->src_rect.pos.x,
                    request->src_rect.pos.y,
                    request->src_rect.size.w,
@@ -208,11 +214,34 @@ static void vigs_comm_dispatch_set_plane(struct vigs_comm_batch_ops *ops,
                    request->dst_size.h,
                    request->z_pos);
 
-    ops->set_plane(user_data, request->plane, request->sfc_id,
+    ops->set_plane(user_data, request->plane, request->width, request->height,
+                   request->format, request->surfaces,
                    &request->src_rect, request->dst_x, request->dst_y,
                    &request->dst_size, request->z_pos);
 }
 
+static void vigs_comm_dispatch_ga_copy(struct vigs_comm_batch_ops *ops,
+                                       void *user_data,
+                                       struct vigsp_cmd_ga_copy_request *request)
+{
+    VIGS_LOG_TRACE("src = %u, src_scanout = %d, src_offset = %u, src_stride = %u, dst = %u, dst_stride = %u",
+                   request->src_id,
+                   request->src_scanout,
+                   request->src_offset,
+                   request->src_stride,
+                   request->dst_id,
+                   request->dst_stride);
+
+    ops->ga_copy(user_data,
+                 request->src_id,
+                 request->src_scanout,
+                 request->src_offset,
+                 request->src_stride,
+                 request->dst_id,
+                 request->dst_stride,
+                 &request->entry);
+}
+
 /*
  * @}
  */
@@ -236,11 +265,13 @@ static const vigs_dispatch_func vigs_dispatch_table[] =
     VIGS_DISPATCH_ENTRY(vigsp_cmd_solid_fill,
                         vigs_comm_dispatch_solid_fill),
     VIGS_DISPATCH_ENTRY(vigsp_cmd_set_plane,
-                        vigs_comm_dispatch_set_plane)
+                        vigs_comm_dispatch_set_plane),
+    VIGS_DISPATCH_ENTRY(vigsp_cmd_ga_copy,
+                        vigs_comm_dispatch_ga_copy)
 };
 
 #define VIGS_MIN_BATCH_CMD_ID vigsp_cmd_create_surface
-#define VIGS_MAX_BATCH_CMD_ID vigsp_cmd_set_plane
+#define VIGS_MAX_BATCH_CMD_ID vigsp_cmd_ga_copy
 
 struct vigs_comm *vigs_comm_create(uint8_t *ram_ptr)
 {
index b07c71b7170110b9ece63a34fcdbfe8539117d73..cea76a6f990cc70490c35ae934a8f4514af770b2 100644 (file)
@@ -89,13 +89,25 @@ struct vigs_comm_batch_ops
 
     void (*set_plane)(void */*user_data*/,
                       vigsp_u32 /*plane*/,
-                      vigsp_surface_id /*sfc_id*/,
+                      vigsp_u32 /*width*/,
+                      vigsp_u32 /*height*/,
+                      vigsp_plane_format /*format*/,
+                      vigsp_surface_id[4] /*surfaces*/,
                       const struct vigsp_rect */*src_rect*/,
                       int /*dst_x*/,
                       int /*dst_y*/,
                       const struct vigsp_size */*dst_size*/,
                       int /*z_pos*/);
 
+    void (*ga_copy)(void */*user_data*/,
+                    vigsp_surface_id /*src_id*/,
+                    bool /*src_scanout*/,
+                    vigsp_offset /*src_offset*/,
+                    vigsp_u32 /*src_stride*/,
+                    vigsp_surface_id /*dst_id*/,
+                    vigsp_u32 /*dst_stride*/,
+                    const struct vigsp_copy */*entry*/);
+
     void (*end)(void */*user_data*/, vigsp_fence_seq /*fence_seq*/);
 };
 
index 85faeb40056e5e198012e98131ab985bfaf42831..f76af3a2bd243fbfa613d4495b8f412d7da19a9d 100644 (file)
@@ -324,6 +324,81 @@ texscale);\n\
         mix(sample1, sample0, sx), sy) * brightness;\n\
 }";
 
+static const char *g_vs_nv21_source_gl2 =
+    "#version 120\n\n"
+    "attribute vec4 vertCoord;\n"
+    "uniform mat4 proj;\n"
+    "attribute vec2 texCoord;\n"
+    "varying vec2 v_texCoord;\n"
+    "void main()\n"
+    "{\n"
+    "    v_texCoord = texCoord;\n"
+    "    gl_Position = proj * vertCoord;\n"
+    "}\n";
+
+static const char *g_vs_nv21_source_gl3 =
+    "#version 140\n\n"
+    "in vec4 vertCoord;\n"
+    "uniform mat4 proj;\n"
+    "in vec2 texCoord;\n"
+    "out vec2 v_texCoord;\n"
+    "void main()\n"
+    "{\n"
+    "    v_texCoord = texCoord;\n"
+    "    gl_Position = proj * vertCoord;\n"
+    "}\n";
+
+static const char *g_fs_nv21_source_gl2 =
+    "#version 120\n\n"
+    "uniform sampler2D ytex;\n"
+    "uniform sampler2D ctex;\n"
+    "uniform vec2 size;\n"
+    "uniform vec2 ytexSize;\n"
+    "uniform vec2 ctexSize;\n"
+    "varying vec2 v_texCoord;\n"
+    "void main()\n"
+    "{\n"
+    "    float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n"
+    "    float ytexPos = floor(ypos / 4);\n"
+    "    vec4 ytexColor = texture2D(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n"
+    "    float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n"
+    "    float cpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n"
+    "    float ctexPos = floor(cpos / 4);\n"
+    "    vec4 ctexColor = texture2D(ctex, vec2((mod(ctexPos, ctexSize.x) + 0.5) / ctexSize.x, 1.0 - (floor(ctexPos / ctexSize.x) + 0.5) / ctexSize.y));\n"
+    "    int index = 2 * int(mod(floor(cpos / 2) + 1, 2));"
+    "    float u = ctexColor[index];\n"
+    "    float v = ctexColor[3 - index];\n"
+    "    u -= 0.5;"
+    "    v -= 0.5;"
+    "    gl_FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n"
+    "}\n";
+
+static const char *g_fs_nv21_source_gl3 =
+    "#version 140\n\n"
+    "uniform sampler2D ytex;\n"
+    "uniform sampler2D ctex;\n"
+    "uniform vec2 size;\n"
+    "uniform vec2 ytexSize;\n"
+    "uniform vec2 ctexSize;\n"
+    "in vec2 v_texCoord;\n"
+    "out vec4 FragColor;\n"
+    "void main()\n"
+    "{\n"
+    "    float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n"
+    "    float ytexPos = floor(ypos / 4);\n"
+    "    vec4 ytexColor = texture(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n"
+    "    float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n"
+    "    float cpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n"
+    "    float ctexPos = floor(cpos / 4);\n"
+    "    vec4 ctexColor = texture(ctex, vec2((mod(ctexPos, ctexSize.x) + 0.5) / ctexSize.x, 1.0 - (floor(ctexPos / ctexSize.x) + 0.5) / ctexSize.y));\n"
+    "    int index = 2 * int(mod(floor(cpos / 2) + 1, 2));"
+    "    float u = ctexColor[index];\n"
+    "    float v = ctexColor[3 - index];\n"
+    "    u -= 0.5;"
+    "    v -= 0.5;"
+    "    FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n"
+    "}\n";
+
 static GLuint vigs_gl_backend_alloc_tmp_texture(void *user_data,
                                                 uint32_t width,
                                                 uint32_t height,
@@ -480,10 +555,9 @@ static GLuint vigs_gl_create_program(struct vigs_gl_backend *backend,
     return program;
 }
 
-static void vigs_gl_draw_tex_prog(struct vigs_gl_backend *backend,
-                                  uint32_t count)
+static void vigs_gl_draw_update_vert_tex_buffer(struct vigs_gl_backend *backend,
+                                                uint32_t size)
 {
-    uint32_t size = count * 16;
     void *ptr;
 
     if (size > backend->vbo_size) {
@@ -513,6 +587,14 @@ static void vigs_gl_draw_tex_prog(struct vigs_gl_backend *backend,
         backend->BufferSubData(GL_ARRAY_BUFFER, (size / 2),
                                (size / 2), vigs_vector_data(&backend->v2));
     }
+}
+
+static void vigs_gl_draw_tex_prog(struct vigs_gl_backend *backend,
+                                  uint32_t count)
+{
+    uint32_t size = count * 16;
+
+    vigs_gl_draw_update_vert_tex_buffer(backend, size);
 
     backend->EnableVertexAttribArray(backend->tex_prog_vertCoord_loc);
     backend->EnableVertexAttribArray(backend->tex_prog_texCoord_loc);
@@ -668,6 +750,27 @@ static void vigs_gl_draw_dpy_scale_prog(struct vigs_gl_backend *backend,
     backend->DisableVertexAttribArray(backend->dpy_scale_prog_vertCoord_loc);
 }
 
+static void vigs_gl_draw_nv12_prog(struct vigs_gl_backend *backend,
+                                   uint32_t count)
+{
+    uint32_t size = count * 16;
+
+    vigs_gl_draw_update_vert_tex_buffer(backend, size);
+
+    backend->EnableVertexAttribArray(backend->nv21_prog_vertCoord_loc);
+    backend->EnableVertexAttribArray(backend->nv21_prog_texCoord_loc);
+
+    backend->VertexAttribPointer(backend->nv21_prog_vertCoord_loc,
+                                 2, GL_FLOAT, GL_FALSE, 0, NULL);
+    backend->VertexAttribPointer(backend->nv21_prog_texCoord_loc,
+                                 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2));
+
+    backend->DrawArrays(GL_TRIANGLES, 0, count);
+
+    backend->DisableVertexAttribArray(backend->nv21_prog_texCoord_loc);
+    backend->DisableVertexAttribArray(backend->nv21_prog_vertCoord_loc);
+}
+
 static void vigs_gl_create_ortho(GLfloat left, GLfloat right,
                                  GLfloat bottom, GLfloat top,
                                  GLfloat nearf, GLfloat farf,
@@ -1387,6 +1490,111 @@ out:
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
+static void vigs_gl_surface_ga_copy(struct vigs_surface *dst,
+                                    uint32_t dst_stride,
+                                    struct vigs_surface *src,
+                                    uint8_t *src_pixels,
+                                    uint32_t src_stride,
+                                    const struct vigsp_copy *entry)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend;
+    struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst;
+    struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst);
+    GLfloat dst_w, dst_h, height;
+    GLfloat *vert_coords;
+    GLfloat *tex_coords;
+
+    if ((entry->from.x != 0) ||
+        (entry->to.x != 0) ||
+        (entry->to.y != 0)) {
+        VIGS_LOG_ERROR("not supported");
+    }
+
+    if (entry->from.y * src_stride + entry->size.w * entry->size.h >
+        src->stride * src->ws_sfc->height) {
+        VIGS_LOG_ERROR("out of bounds");
+        return;
+    }
+
+    if (!src_pixels) {
+        /*
+         * Contents were flushed to GPU, so read them back,
+         * not very pretty, but this path should be triggered
+         * very rarely.
+         */
+        vigs_vector_resize(&gl_backend->v1, src->stride * src->ws_sfc->height);
+
+        src_pixels = vigs_vector_data(&gl_backend->v1);
+
+        vigs_gl_surface_read_pixels(src, src_pixels);
+    }
+
+    if (!vigs_winsys_gl_surface_create_texture(ws_dst)) {
+        goto out;
+    }
+
+    if (!vigs_gl_surface_create_tmp_texture(gl_dst)) {
+        goto out;
+    }
+
+    if (!vigs_gl_surface_setup_framebuffer(gl_dst,
+                                           gl_backend->tex_prog_id,
+                                           gl_backend->tex_prog_proj_loc)) {
+        goto out;
+    }
+
+    height = (entry->size.w * entry->size.h + dst->stride - 1) / dst->stride;
+
+    dst_w = ws_dst->base.base.width;
+    dst_h = ws_dst->base.base.height;
+
+    gl_backend->BindTexture(GL_TEXTURE_2D, gl_dst->tmp_tex);
+
+    gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+    gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
+                              dst_w, height,
+                              ws_dst->tex_format,
+                              ws_dst->tex_type,
+                              src_pixels + entry->from.y * src_stride);
+
+    vigs_vector_resize(&gl_backend->v1, 0);
+    vigs_vector_resize(&gl_backend->v2, 0);
+
+    gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                     GL_TEXTURE_2D, ws_dst->tex, 0);
+
+    vert_coords = vigs_vector_append(&gl_backend->v1,
+                                     (12 * sizeof(GLfloat)));
+    tex_coords = vigs_vector_append(&gl_backend->v2,
+                                    (12 * sizeof(GLfloat)));
+
+    vert_coords[6] = vert_coords[0] = entry->to.x;
+    vert_coords[7] = vert_coords[1] = dst_h - entry->to.y;
+    vert_coords[2] = entry->to.x + dst_w;
+    vert_coords[3] = dst_h - entry->to.y;
+    vert_coords[8] = vert_coords[4] = entry->to.x + dst_w;
+    vert_coords[9] = vert_coords[5] = dst_h - (entry->to.y + height);
+    vert_coords[10] = entry->to.x;
+    vert_coords[11] = dst_h - (entry->to.y + height);
+
+    tex_coords[6] = tex_coords[0] = (GLfloat)entry->to.x / dst_w;
+    tex_coords[7] = tex_coords[1] = (GLfloat)entry->to.y / dst_h;
+    tex_coords[2] = (GLfloat)(entry->to.x + dst_w) / dst_w;
+    tex_coords[3] = (GLfloat)entry->to.y / dst_h;
+    tex_coords[8] = tex_coords[4] = (GLfloat)(entry->to.x + dst_w) / dst_w;
+    tex_coords[9] = tex_coords[5] = (GLfloat)(entry->to.y + height) / dst_h;
+    tex_coords[10] = (GLfloat)entry->to.x / dst_w;
+    tex_coords[11] = (GLfloat)(entry->to.y + height) / dst_h;
+
+    vigs_gl_draw_tex_prog(gl_backend, 6);
+
+out:
+    gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
 static void vigs_gl_surface_destroy(struct vigs_surface *sfc)
 {
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
@@ -1476,6 +1684,7 @@ static struct vigs_surface *vigs_gl_backend_create_surface(struct vigs_backend *
     gl_sfc->base.draw_pixels = &vigs_gl_surface_draw_pixels;
     gl_sfc->base.copy = &vigs_gl_surface_copy;
     gl_sfc->base.solid_fill = &vigs_gl_surface_solid_fill;
+    gl_sfc->base.ga_copy = &vigs_gl_surface_ga_copy;
     gl_sfc->base.destroy = &vigs_gl_surface_destroy;
 
     return &gl_sfc->base;
@@ -1489,7 +1698,8 @@ static struct vigs_surface *vigs_gl_backend_create_surface(struct vigs_backend *
 static bool vigs_gl_backend_composite_planes(struct vigs_gl_backend *gl_backend,
                                              const struct vigs_plane **planes,
                                              bool above_root,
-                                             bool bottom)
+                                             bool bottom,
+                                             GLfloat ortho[16])
 {
     uint32_t i;
     GLfloat *vert_coords = vigs_vector_data(&gl_backend->v1);
@@ -1497,19 +1707,14 @@ static bool vigs_gl_backend_composite_planes(struct vigs_gl_backend *gl_backend,
 
     for (i = 0; i < VIGS_MAX_PLANES; ++i) {
         const struct vigs_plane *plane = planes[i];
-        struct vigs_gl_surface *gl_sfc;
-        struct vigs_winsys_gl_surface *ws_sfc;
         GLfloat src_w, src_h;
 
-        if (!plane->sfc || ((plane->z_pos >= 0) ^ above_root)) {
+        if (!vigs_plane_enabled(plane) || ((plane->z_pos >= 0) ^ above_root)) {
             continue;
         }
 
-        gl_sfc = (struct vigs_gl_surface*)plane->sfc;
-        ws_sfc = get_ws_sfc(gl_sfc);
-
-        src_w = ws_sfc->base.base.width;
-        src_h = ws_sfc->base.base.height;
+        src_w = plane->width;
+        src_h = plane->height;
 
         vert_coords[6] = vert_coords[0] = plane->dst_x;
         vert_coords[7] = vert_coords[1] = plane->dst_y;
@@ -1529,7 +1734,7 @@ static bool vigs_gl_backend_composite_planes(struct vigs_gl_backend *gl_backend,
         tex_coords[10] = (GLfloat)plane->src_rect.pos.x / src_w;
         tex_coords[11] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
 
-        if (!bottom && (plane->sfc->format == vigsp_surface_bgra8888)) {
+        if (!bottom && (plane->format == vigsp_plane_bgra8888)) {
             /*
              * This is not bottom plane and it has alpha, turn on blending.
              */
@@ -1539,9 +1744,51 @@ static bool vigs_gl_backend_composite_planes(struct vigs_gl_backend *gl_backend,
             gl_backend->Disable(GL_BLEND);
         }
 
-        gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
+        if (plane->format == vigsp_plane_nv21) {
+            struct vigs_gl_surface *gl_sfc;
+            struct vigs_winsys_gl_surface *ws_sfc;
 
-        vigs_gl_draw_tex_prog(gl_backend, 6);
+            gl_backend->UseProgram(gl_backend->nv21_prog_id);
+
+            gl_backend->UniformMatrix4fv(gl_backend->nv21_prog_proj_loc,
+                                         1, GL_FALSE, ortho);
+
+            gl_sfc = (struct vigs_gl_surface*)plane->surfaces[1];
+            ws_sfc = get_ws_sfc(gl_sfc);
+
+            gl_backend->ActiveTexture(GL_TEXTURE1);
+            gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
+
+            gl_backend->Uniform2f(gl_backend->nv21_prog_ctexSize_loc,
+                                  ws_sfc->base.base.width,
+                                  ws_sfc->base.base.height);
+
+            gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0];
+            ws_sfc = get_ws_sfc(gl_sfc);
+
+            gl_backend->ActiveTexture(GL_TEXTURE0);
+            gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
+
+            gl_backend->Uniform2f(gl_backend->nv21_prog_ytexSize_loc,
+                                  ws_sfc->base.base.width,
+                                  ws_sfc->base.base.height);
+
+            gl_backend->Uniform2f(gl_backend->nv21_prog_size_loc, src_w, src_h);
+
+            vigs_gl_draw_nv12_prog(gl_backend, 6);
+
+            gl_backend->UseProgram(gl_backend->tex_prog_id);
+        } else {
+            struct vigs_gl_surface *gl_sfc;
+            struct vigs_winsys_gl_surface *ws_sfc;
+
+            gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0];
+            ws_sfc = get_ws_sfc(gl_sfc);
+
+            gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
+
+            vigs_gl_draw_tex_prog(gl_backend, 6);
+        }
 
         bottom = false;
     }
@@ -1558,6 +1805,7 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
     struct vigs_gl_surface *gl_root_sfc = (struct vigs_gl_surface*)surface;
     struct vigs_winsys_gl_surface *ws_root_sfc = get_ws_sfc(gl_root_sfc);
     uint32_t i;
+    int j;
     GLfloat *vert_coords;
     GLfloat *tex_coords;
     const struct vigs_plane *sorted_planes[VIGS_MAX_PLANES];
@@ -1591,19 +1839,26 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
         struct vigs_gl_surface *gl_sfc;
         struct vigs_winsys_gl_surface *ws_sfc;
 
-        if (!planes[i].sfc) {
+        if (!vigs_plane_enabled(&planes[i])) {
             continue;
         }
 
-        gl_sfc = (struct vigs_gl_surface*)planes[i].sfc;
-        ws_sfc = get_ws_sfc(gl_sfc);
+        for (j = 0; j < 4; ++j) {
+            gl_sfc = (struct vigs_gl_surface*)planes[i].surfaces[j];
 
-        if (!ws_sfc->tex) {
-            VIGS_LOG_WARN("compositing garbage (plane %u) ???", i);
-        }
+            if (!gl_sfc) {
+                continue;
+            }
 
-        if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
-            goto out;
+            ws_sfc = get_ws_sfc(gl_sfc);
+
+            if (!ws_sfc->tex) {
+                VIGS_LOG_WARN("compositing garbage (plane %u, sfc %d) ???", i, j);
+            }
+
+            if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
+                goto out;
+            }
         }
     }
 
@@ -1662,7 +1917,8 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
     bottom = vigs_gl_backend_composite_planes(gl_backend,
                                               sorted_planes,
                                               false,
-                                              bottom);
+                                              bottom,
+                                              gl_root_sfc->ortho);
 
     /*
      * Render root surface.
@@ -1727,7 +1983,8 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
     vigs_gl_backend_composite_planes(gl_backend,
                                      sorted_planes,
                                      true,
-                                     bottom);
+                                     bottom,
+                                     gl_root_sfc->ortho);
 
 out:
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -1969,6 +2226,39 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
     gl_backend->color_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->color_prog_id, "vertCoord");
     gl_backend->color_prog_color_loc = gl_backend->GetUniformLocation(gl_backend->color_prog_id, "color");
 
+    gl_backend->nv21_prog_vs_id = vigs_gl_create_shader(gl_backend,
+        (gl_backend->is_gl_2 ? g_vs_nv21_source_gl2 : g_vs_nv21_source_gl3),
+        GL_VERTEX_SHADER);
+
+    if (!gl_backend->nv21_prog_vs_id) {
+        goto fail;
+    }
+
+    gl_backend->nv21_prog_fs_id = vigs_gl_create_shader(gl_backend,
+        (gl_backend->is_gl_2 ? g_fs_nv21_source_gl2 : g_fs_nv21_source_gl3),
+        GL_FRAGMENT_SHADER);
+
+    if (!gl_backend->nv21_prog_fs_id) {
+        goto fail;
+    }
+
+    gl_backend->nv21_prog_id = vigs_gl_create_program(gl_backend,
+                                                      gl_backend->nv21_prog_vs_id,
+                                                      gl_backend->nv21_prog_fs_id);
+
+    if (!gl_backend->nv21_prog_id) {
+        goto fail;
+    }
+
+    gl_backend->nv21_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "proj");
+    gl_backend->nv21_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->nv21_prog_id, "vertCoord");
+    gl_backend->nv21_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->nv21_prog_id, "texCoord");
+    gl_backend->nv21_prog_size_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "size");
+    gl_backend->nv21_prog_ytexSize_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ytexSize");
+    gl_backend->nv21_prog_ctexSize_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ctexSize");
+    gl_backend->nv21_prog_ytex_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ytex");
+    gl_backend->nv21_prog_ctex_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ctex");
+
     gl_backend->GenBuffers(1, &gl_backend->vbo);
     gl_backend->GenBuffers(1, &gl_backend->dpy_vbo);
 
@@ -1979,6 +2269,10 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
 
     gl_backend->BindBuffer(GL_ARRAY_BUFFER, gl_backend->vbo);
 
+    gl_backend->UseProgram(gl_backend->nv21_prog_id);
+    gl_backend->Uniform1i(gl_backend->nv21_prog_ytex_loc, 0);
+    gl_backend->Uniform1i(gl_backend->nv21_prog_ctex_loc, 1);
+
     gl_backend->UseProgram(gl_backend->tex_prog_id);
     gl_backend->cur_prog_id = gl_backend->tex_prog_id;
 
@@ -2087,6 +2381,13 @@ void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
         gl_backend->DeleteShader(gl_backend->dpy_tex_prog_fs_id);
         gl_backend->DeleteProgram(gl_backend->dpy_tex_prog_id);
         gl_backend->DeleteBuffers(1, &gl_backend->vbo);
+        gl_backend->DetachShader(gl_backend->nv21_prog_id,
+                                 gl_backend->nv21_prog_vs_id);
+        gl_backend->DetachShader(gl_backend->nv21_prog_id,
+                                 gl_backend->nv21_prog_fs_id);
+        gl_backend->DeleteShader(gl_backend->nv21_prog_vs_id);
+        gl_backend->DeleteShader(gl_backend->nv21_prog_fs_id);
+        gl_backend->DeleteProgram(gl_backend->nv21_prog_id);
         gl_backend->DetachShader(gl_backend->color_prog_id,
                                  gl_backend->color_prog_vs_id);
         gl_backend->DetachShader(gl_backend->color_prog_id,
index a31e24303b3b4b5a1a600df7cda97c5317876d62..1ac1408458137d89ea225a81ddbdf6695e4cc488 100644 (file)
@@ -122,6 +122,9 @@ struct vigs_gl_backend
     void (GLAPIENTRY* UniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
     void (GLAPIENTRY* Uniform2fv)(GLint location, GLsizei count, const GLfloat* value);
     void (GLAPIENTRY* Uniform1f)(GLint location, GLfloat v0);
+    void (GLAPIENTRY* Uniform1i)(GLint location, GLint v0);
+    void (GLAPIENTRY* Uniform2f)(GLint location, GLfloat v0, GLfloat v1);
+    void (GLAPIENTRY* ActiveTexture)(GLenum texture);
 
     /*
      * @}
@@ -181,6 +184,18 @@ struct vigs_gl_backend
     GLint color_prog_vertCoord_loc;
     GLint color_prog_color_loc;
 
+    GLuint nv21_prog_vs_id;
+    GLuint nv21_prog_fs_id;
+    GLuint nv21_prog_id;
+    GLint nv21_prog_proj_loc;
+    GLint nv21_prog_vertCoord_loc;
+    GLint nv21_prog_texCoord_loc;
+    GLint nv21_prog_size_loc;
+    GLint nv21_prog_ytexSize_loc;
+    GLint nv21_prog_ctexSize_loc;
+    GLint nv21_prog_ytex_loc;
+    GLint nv21_prog_ctex_loc;
+
     GLuint vbo;
     uint32_t vbo_size;
 
index 5a273c24287d3ee017766d9508ca2ec040c40b7f..dbf8d4cfedc4ccad23e5a5391ca5392ced781e85 100644 (file)
@@ -323,6 +323,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
     VIGS_GL_GET_PROC(Uniform2fv, glUniform2fv);
     VIGS_GL_GET_PROC(Uniform1f, glUniform1f);
+    VIGS_GL_GET_PROC(Uniform1i, glUniform1i);
+    VIGS_GL_GET_PROC(Uniform2f, glUniform2f);
+    VIGS_GL_GET_PROC(ActiveTexture, glActiveTexture);
 
     VIGS_GL_GET_PROC_OPTIONAL(MapBufferRange, glMapBufferRange);
 
index 8c8858ea270b2445ad8e2512d2d6b4804eb3fc76..4306420d660ef4e5192c749b45a44bd0853ebc4f 100644 (file)
@@ -501,6 +501,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
     VIGS_GL_GET_PROC(Uniform2fv, glUniform2fv);
     VIGS_GL_GET_PROC(Uniform1f, glUniform1f);
+    VIGS_GL_GET_PROC(Uniform1i, glUniform1i);
+    VIGS_GL_GET_PROC(Uniform2f, glUniform2f);
+    VIGS_GL_GET_PROC(ActiveTexture, glActiveTexture);
 
     VIGS_GL_GET_PROC_OPTIONAL(MapBufferRange, glMapBufferRange);
 
index 91db6b28280ab2cc071d4d96660f6ad9c0a63294..e66a0fda16adc97ccc9fb00ab93b153341bbd741 100644 (file)
@@ -615,6 +615,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
     VIGS_GL_GET_PROC(Uniform2fv, glUniform2fv);
     VIGS_GL_GET_PROC(Uniform1f, glUniform1f);
+    VIGS_GL_GET_PROC(Uniform1i, glUniform1i);
+    VIGS_GL_GET_PROC(Uniform2f, glUniform2f);
+    VIGS_GL_GET_PROC(ActiveTexture, glActiveTexture);
 
     VIGS_GL_GET_PROC_OPTIONAL(MapBufferRange, glMapBufferRange);
 
index de53671f281d6c2379dcb4c37fac75e3e31b0f6f..0ae97205fa5732598bfd347b407c6f9ce4ada1a5 100644 (file)
 #define _QEMU_VIGS_PLANE_H
 
 #include "vigs_types.h"
-
-struct vigs_surface;
+#include "vigs_surface.h"
 
 struct vigs_plane
 {
-    struct vigs_surface *sfc;
+    uint32_t width;
+    uint32_t height;
+
+    vigsp_plane_format format;
+
+    struct vigs_surface *surfaces[4];
 
     struct vigsp_rect src_rect;
 
@@ -52,4 +56,59 @@ struct vigs_plane
     bool is_dirty;
 };
 
+static __inline bool vigs_plane_enabled(const struct vigs_plane *plane)
+{
+    return plane->surfaces[0] != NULL;
+}
+
+static __inline bool vigs_plane_dirty(const struct vigs_plane *plane)
+{
+    int i;
+
+    if (plane->is_dirty) {
+        return true;
+    }
+
+    for (i = 0; i < 4; ++i) {
+        if (plane->surfaces[i] && plane->surfaces[i]->is_dirty) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static __inline void vigs_plane_reset_dirty(struct vigs_plane *plane)
+{
+    int i;
+
+    plane->is_dirty = false;
+
+    for (i = 0; i < 4; ++i) {
+        if (plane->surfaces[i]) {
+            plane->surfaces[i]->is_dirty = false;
+        }
+    }
+}
+
+static __inline void vigs_plane_detach_surface(struct vigs_plane *plane,
+                                               struct vigs_surface *sfc)
+{
+    int i;
+
+    for (i = 0; i < 4; ++i) {
+        if (plane->surfaces[i] == sfc) {
+            /*
+             * If at least one surface gets detached - entire plane
+             * gets disabled.
+             */
+
+            memset(plane->surfaces, 0, sizeof(plane->surfaces));
+            plane->is_dirty = true;
+
+            return;
+        }
+    }
+}
+
 #endif
index f00e281b8b098cd85655e55055f651aa8d6f31ef..e4663d5a22b4461f78b50f751897950a951e1a96 100644 (file)
@@ -37,7 +37,7 @@
 /*
  * Bump this whenever protocol changes.
  */
-#define VIGS_PROTOCOL_VERSION 17
+#define VIGS_PROTOCOL_VERSION 18
 
 #define VIGS_MAX_PLANES 2
 
@@ -81,6 +81,7 @@ typedef enum
     vigsp_cmd_copy = 0x8,
     vigsp_cmd_solid_fill = 0x9,
     vigsp_cmd_set_plane = 0xA,
+    vigsp_cmd_ga_copy = 0xB
     /*
      * @}
      */
@@ -92,6 +93,15 @@ typedef enum
     vigsp_surface_bgra8888 = 0x1,
 } vigsp_surface_format;
 
+typedef enum
+{
+    vigsp_plane_bgrx8888 = 0x0,
+    vigsp_plane_bgra8888 = 0x1,
+    vigsp_plane_nv21 = 0x2,
+    vigsp_plane_nv42 = 0x3,
+    vigsp_plane_nv61 = 0x4
+} vigsp_plane_format;
+
 #pragma pack(1)
 
 struct vigsp_point
@@ -332,9 +342,9 @@ struct vigsp_cmd_solid_fill_request
 /*
  * cmd_set_plane
  *
- * Assigns surface 'sfc_id' to plane identified by 'plane'.
+ * Assigns surfaces 'surfaces' to plane identified by 'plane'.
  *
- * Pass 0 as sfc_id in order to disable the plane.
+ * Pass 0 as surfaces[0] in order to disable the plane.
  *
  * @{
  */
@@ -342,7 +352,10 @@ struct vigsp_cmd_solid_fill_request
 struct vigsp_cmd_set_plane_request
 {
     vigsp_u32 plane;
-    vigsp_surface_id sfc_id;
+    vigsp_u32 width;
+    vigsp_u32 height;
+    vigsp_plane_format format;
+    vigsp_surface_id surfaces[4];
     struct vigsp_rect src_rect;
     vigsp_s32 dst_x;
     vigsp_s32 dst_y;
@@ -350,6 +363,31 @@ struct vigsp_cmd_set_plane_request
     vigsp_s32 z_pos;
 };
 
+/*
+ * @}
+ */
+
+/*
+ * cmd_ga_copy
+ *
+ * Copies part of surface 'src_id' to
+ * surface 'dst_id' given surface
+ * sizes.
+ *
+ * @{
+ */
+
+struct vigsp_cmd_ga_copy_request
+{
+    vigsp_surface_id src_id;
+    vigsp_bool src_scanout;
+    vigsp_offset src_offset;
+    vigsp_u32 src_stride;
+    vigsp_surface_id dst_id;
+    vigsp_u32 dst_stride;
+    struct vigsp_copy entry;
+};
+
 /*
  * @}
  */
index 54d712e62a9bed02bb33647742fbe8cb6c6eeeac..954b12a69ad3c30d7cf3593663b0a2c0de7f7f4b 100644 (file)
@@ -78,10 +78,7 @@ static void vigs_server_unuse_surface(struct vigs_server *server,
      * If it was attached to a plane then detach it.
      */
     for (i = 0; i < VIGS_MAX_PLANES; ++i) {
-        if (server->planes[i].sfc == sfc) {
-            server->planes[i].sfc = NULL;
-            server->planes[i].is_dirty = true;
-        }
+        vigs_plane_detach_surface(&server->planes[i], sfc);
     }
 }
 
@@ -307,7 +304,10 @@ static void vigs_server_dispatch_solid_fill(void *user_data,
 
 static void vigs_server_dispatch_set_plane(void *user_data,
                                            vigsp_u32 plane,
-                                           vigsp_surface_id sfc_id,
+                                           vigsp_u32 width,
+                                           vigsp_u32 height,
+                                           vigsp_plane_format format,
+                                           vigsp_surface_id surface_ids[4],
                                            const struct vigsp_rect *src_rect,
                                            int dst_x,
                                            int dst_y,
@@ -315,28 +315,34 @@ static void vigs_server_dispatch_set_plane(void *user_data,
                                            int z_pos)
 {
     struct vigs_server *server = user_data;
-    struct vigs_surface *sfc = NULL;
+    struct vigs_surface *surfaces[4] = { NULL, NULL, NULL, NULL };
+    int i, num_buffers = vigs_format_num_buffers(format);
 
     if (!server->initialized) {
         VIGS_LOG_ERROR("not initialized");
         return;
     }
 
-    if (sfc_id) {
-        sfc = g_hash_table_lookup(server->surfaces, GUINT_TO_POINTER(sfc_id));
-
-        if (!sfc) {
-            VIGS_LOG_ERROR("surface %u not found", sfc_id);
-            return;
-        }
-    }
-
     if (plane >= VIGS_MAX_PLANES) {
         VIGS_LOG_ERROR("bad plane %u", plane);
         return;
     }
 
-    server->planes[plane].sfc = sfc;
+    for (i = 0; i < num_buffers; ++i) {
+        if (surface_ids[i]) {
+            surfaces[i] = g_hash_table_lookup(server->surfaces, GUINT_TO_POINTER(surface_ids[i]));
+
+            if (!surfaces[i]) {
+                VIGS_LOG_ERROR("surface %u not found", surface_ids[i]);
+                return;
+            }
+        }
+    }
+
+    server->planes[plane].width = width;
+    server->planes[plane].height = height;
+    server->planes[plane].format = format;
+    memcpy(server->planes[plane].surfaces, surfaces, sizeof(surfaces));
     server->planes[plane].src_rect = *src_rect;
     server->planes[plane].dst_x = dst_x;
     server->planes[plane].dst_y = dst_y;
@@ -345,6 +351,49 @@ static void vigs_server_dispatch_set_plane(void *user_data,
     server->planes[plane].is_dirty = true;
 }
 
+static void vigs_server_dispatch_ga_copy(void *user_data,
+                                         vigsp_surface_id src_id,
+                                         bool src_scanout,
+                                         vigsp_offset src_offset,
+                                         vigsp_u32 src_stride,
+                                         vigsp_surface_id dst_id,
+                                         vigsp_u32 dst_stride,
+                                         const struct vigsp_copy *entry)
+{
+    struct vigs_server *server = user_data;
+    struct vigs_surface *src;
+    struct vigs_surface *dst;
+
+    if (!server->initialized) {
+        VIGS_LOG_ERROR("not initialized");
+        return;
+    }
+
+    src = g_hash_table_lookup(server->surfaces, GUINT_TO_POINTER(src_id));
+
+    if (!src) {
+        VIGS_LOG_ERROR("src surface %u not found", src_id);
+        return;
+    }
+
+    if (src_id == dst_id) {
+        dst = src;
+    } else {
+        dst = g_hash_table_lookup(server->surfaces, GUINT_TO_POINTER(dst_id));
+
+        if (!dst) {
+            VIGS_LOG_ERROR("dst surface %u not found", dst_id);
+            return;
+        }
+    }
+
+    dst->ga_copy(dst, dst_stride,
+                 src, (src_scanout ? (server->vram_ptr + src_offset) : NULL),
+                 src_stride, entry);
+
+    dst->is_dirty = true;
+}
+
 static void vigs_server_dispatch_batch_end(void *user_data,
                                            vigsp_fence_seq fence_seq)
 {
@@ -367,6 +416,7 @@ static struct vigs_comm_batch_ops vigs_server_dispatch_batch_ops =
     .copy = &vigs_server_dispatch_copy,
     .solid_fill = &vigs_server_dispatch_solid_fill,
     .set_plane = &vigs_server_dispatch_set_plane,
+    .ga_copy = &vigs_server_dispatch_ga_copy,
     .end = &vigs_server_dispatch_batch_end
 };
 
@@ -449,20 +499,7 @@ static void vigs_server_update_display_work(struct work_queue_item *wq_item)
     }
 
     for (i = 0; i < VIGS_MAX_PLANES; ++i) {
-        /*
-         * If plane was moved/resized or turned on/off
-         * then we're dirty.
-         */
-        if (server->planes[i].is_dirty) {
-            planes_dirty = true;
-        }
-
-        if (server->planes[i].sfc && server->planes[i].sfc->is_dirty) {
-            /*
-             * If plane's surface is dirty then we're dirty.
-             */
-            planes_dirty = true;
-        }
+        planes_dirty |= vigs_plane_dirty(&server->planes[i]);
     }
 
     if (root_sfc->ptr || root_sfc->is_dirty || planes_dirty) {
@@ -494,11 +531,7 @@ static void vigs_server_update_display_work(struct work_queue_item *wq_item)
         root_sfc->is_dirty = false;
 
         for (i = 0; i < VIGS_MAX_PLANES; ++i) {
-            server->planes[i].is_dirty = false;
-
-            if (server->planes[i].sfc) {
-                server->planes[i].sfc->is_dirty = false;
-            }
+            vigs_plane_reset_dirty(&server->planes[i]);
         }
     }
 
index 9867b0f9a136d167580cbc31bc3533545c7e73ad..a508d06e108d32d23e85de298d0ce8a89d3b9c8b 100644 (file)
@@ -70,6 +70,13 @@ struct vigs_surface
                        const struct vigsp_rect */*entries*/,
                        uint32_t /*num_entries*/);
 
+    void (*ga_copy)(struct vigs_surface */*dst*/,
+                    uint32_t /*dst_stride*/,
+                    struct vigs_surface */*src*/,
+                    uint8_t */*src_pixels*/,
+                    uint32_t /*src_stride*/,
+                    const struct vigsp_copy */*entry*/);
+
     void (*destroy)(struct vigs_surface */*sfc*/);
 };
 
index 613f6e557a48c84feeb20c0603fe782314fabe0d..fa8cfb85663f18f053233419f292fd45751377ac 100644 (file)
@@ -312,6 +312,18 @@ static void vigs_sw_surface_solid_fill(struct vigs_surface *sfc,
     }
 }
 
+static void vigs_sw_surface_ga_copy(struct vigs_surface *dst,
+                                    uint32_t dst_stride,
+                                    struct vigs_surface *src,
+                                    uint8_t *src_pixels,
+                                    uint32_t src_stride,
+                                    const struct vigsp_copy *entry)
+{
+    /*
+     * TODO: Implement.
+     */
+}
+
 static void vigs_sw_surface_destroy(struct vigs_surface *sfc)
 {
     struct vigs_sw_surface *sw_sfc = (struct vigs_sw_surface*)sfc;
@@ -359,6 +371,7 @@ static struct vigs_surface *vigs_sw_backend_create_surface(struct vigs_backend *
     sw_sfc->base.draw_pixels = &vigs_sw_surface_draw_pixels;
     sw_sfc->base.copy = &vigs_sw_surface_copy;
     sw_sfc->base.solid_fill = &vigs_sw_surface_solid_fill;
+    sw_sfc->base.ga_copy = &vigs_sw_surface_ga_copy;
     sw_sfc->base.destroy = &vigs_sw_surface_destroy;
 
     return &sw_sfc->base;
index 0a2dab864e826cf8cc7665a7b1367467a21472f9..bca7de6a345f8ea2356824e91cd3eda63ae4c44b 100644 (file)
@@ -42,3 +42,19 @@ uint32_t vigs_format_bpp(vigsp_surface_format format)
         return 0;
     }
 }
+
+int vigs_format_num_buffers(vigsp_plane_format format)
+{
+    switch (format) {
+    case vigsp_plane_bgrx8888: return 1;
+    case vigsp_plane_bgra8888: return 1;
+    case vigsp_plane_nv21: return 2;
+    case vigsp_plane_nv42: return 2;
+    case vigsp_plane_nv61: return 2;
+    default:
+        assert(false);
+        VIGS_LOG_CRITICAL("unknown format: %d", format);
+        exit(1);
+        return 1;
+    }
+}
index 7e046fcfc790706b4ec30081e57ab85b4d8bb218..3d53702859017452249aa47772719957bde27a4e 100644 (file)
@@ -38,4 +38,6 @@
  */
 uint32_t vigs_format_bpp(vigsp_surface_format format);
 
+int vigs_format_num_buffers(vigsp_plane_format format);
+
 #endif