VIGS: Support planar pixel formats 02/27402/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 16 Jun 2014 15:44:07 +0000 (19:44 +0400)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Fri, 12 Sep 2014 08:47:02 +0000 (17:47 +0900)
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 438de8d21b287f42fed161e1e0566c1dc8747de5..ba6baab2ab6eebf1639b4f2a4621af118861e51c 100644 (file)
@@ -203,6 +203,81 @@ static const char *g_fs_color_source_gl3 =
     "    FragColor = color;\n"
     "}\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 = 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;"
+    "    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,
@@ -359,10 +434,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) {
@@ -392,6 +466,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);
@@ -451,6 +533,27 @@ static void vigs_gl_draw_color_prog(struct vigs_gl_backend *backend,
     backend->DisableVertexAttribArray(backend->color_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,
@@ -1097,6 +1200,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;
@@ -1186,6 +1394,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;
@@ -1238,7 +1447,8 @@ static void vigs_gl_backend_read_pixels_work(struct work_queue_item *wq_item)
 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);
@@ -1246,19 +1456,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;
@@ -1278,7 +1483,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.
              */
@@ -1288,9 +1493,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;
     }
@@ -1308,6 +1555,7 @@ static void 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];
@@ -1333,19 +1581,26 @@ static void 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;
+            }
         }
     }
 
@@ -1404,7 +1659,8 @@ static void 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.
@@ -1458,7 +1714,8 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface,
     vigs_gl_backend_composite_planes(gl_backend,
                                      sorted_planes,
                                      true,
-                                     bottom);
+                                     bottom,
+                                     gl_root_sfc->ortho);
 
     /*
      * Now schedule asynchronous glReadPixels.
@@ -1609,6 +1866,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);
 
     if (!gl_backend->vbo) {
@@ -1618,6 +1908,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;
 
@@ -1658,6 +1952,13 @@ void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
     if (gl_backend->make_current(gl_backend, true)) {
         gl_backend->DeleteBuffers(1, &gl_backend->pbo);
         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 5d3b019a1293e1d7547500e47ca075cbb748d854..72f663075cd69e2e7321606565cc2e909152de81 100644 (file)
@@ -121,6 +121,9 @@ struct vigs_gl_backend
     void (GLAPIENTRY* VertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
     void (GLAPIENTRY* Uniform4fv)(GLint location, GLsizei count, const GLfloat* value);
     void (GLAPIENTRY* UniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+    void (GLAPIENTRY* Uniform1i)(GLint location, GLint v0);
+    void (GLAPIENTRY* Uniform2f)(GLint location, GLfloat v0, GLfloat v1);
+    void (GLAPIENTRY* ActiveTexture)(GLenum texture);
 
     /*
      * @}
@@ -179,6 +182,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 996618ad9f7ae1bee63ad4000fdcec3f2dfcfbf6..e21a7a16c7046b38001d833c213b204185f993a6 100644 (file)
@@ -321,6 +321,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(VertexAttribPointer, glVertexAttribPointer);
     VIGS_GL_GET_PROC(Uniform4fv, glUniform4fv);
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
+    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 caf5096bacc8bb6824def29b3605052edb4f71b4..8faa13b48d8b231a2f7c583d0968c35bf51d79b4 100644 (file)
@@ -470,6 +470,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(VertexAttribPointer, glVertexAttribPointer);
     VIGS_GL_GET_PROC(Uniform4fv, glUniform4fv);
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
+    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 b9b689ed70e2514c67639fb4b5081d8c5f7458cd..219eb4d1ecb90a1d2dcec3311af8d63fde5bf6f1 100644 (file)
@@ -611,6 +611,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(VertexAttribPointer, glVertexAttribPointer);
     VIGS_GL_GET_PROC(Uniform4fv, glUniform4fv);
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
+    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 6be06b75bd1d9822f1e6efb5975a3e537da264f6..518bf237f1fd15f8be2153cec969c720a50a1d34 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
 };
 
@@ -500,23 +550,12 @@ 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 (!planes_dirty) {
+            planes_dirty = vigs_plane_dirty(&server->planes[i]);
         }
 
-        if (server->planes[i].sfc) {
-            planes_on = true;
-
-            /*
-             * If plane's surface is dirty then we're dirty.
-             */
-            if (server->planes[i].sfc->is_dirty) {
-                planes_dirty = true;
-            }
+        if (!planes_on) {
+            planes_on = vigs_plane_enabled(&server->planes[i]);
         }
     }
 
@@ -551,14 +590,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) {
-            if (server->planes[i].is_dirty) {
-                server->planes[i].is_dirty = false;
-            }
-
-            if (server->planes[i].sfc &&
-                server->planes[i].sfc->is_dirty) {
-                server->planes[i].sfc->is_dirty = false;
-            }
+            vigs_plane_reset_dirty(&server->planes[i]);
         }
     } else {
         /*
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 5991089237fc766718251cef2ec89ba3f426512d..ee3869d1adfdd6512ad0cd676874c39bcb3583e5 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