VIGS: add h/w conversion from ARGB to XBGR
[sdk/emulator/qemu.git] / hw / vigs / vigs_gl_backend.c
index f4c6f4a..fa5182a 100644 (file)
@@ -47,6 +47,7 @@
                                 (((unsigned int)(d)) << 24))
 #define DRM_FORMAT_ARGB8888    MAKE_FOURCC('A', 'R', '2', '4')
 #define DRM_FORMAT_YUV420    MAKE_FOURCC('Y', 'U', '1', '2')
+#define DRM_FORMAT_XBGR8888    MAKE_FOURCC('X', 'B', '2', '4')
 #endif
 
 struct vigs_gl_surface;
@@ -362,6 +363,25 @@ static const char *g_fs_yuv420_source_gl3 =
     "    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_xbgr_source_gl2 =
+    "#version 120\n\n"
+    "uniform sampler2D tex;\n"
+    "varying vec2 v_texCoord;\n"
+    "void main()\n"
+    "{\n"
+    "    gl_FragColor = vec4(texture2D(tex, v_texCoord).bgr, 1.0);\n"
+    "}\n";
+
+static const char *g_fs_xbgr_source_gl3 =
+    "#version 140\n\n"
+    "uniform sampler2D tex;\n"
+    "in vec2 v_texCoord;\n"
+    "out vec4 FragColor;\n"
+    "void main()\n"
+    "{\n"
+    "    FragColor = vec4(texture(tex, v_texCoord).bgr, 1.0);\n"
+    "}\n";
+
 static GLuint vigs_gl_backend_alloc_tmp_texture(void *user_data,
                                                 uint32_t width,
                                                 uint32_t height,
@@ -674,6 +694,27 @@ static void vigs_gl_draw_yuv420_prog(struct vigs_gl_backend *backend,
     backend->DisableVertexAttribArray(backend->yuv420_prog_vertCoord_loc);
 }
 
+static void vigs_gl_draw_xbgr_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->xbgr_prog_vertCoord_loc);
+    backend->EnableVertexAttribArray(backend->xbgr_prog_texCoord_loc);
+
+    backend->VertexAttribPointer(backend->xbgr_prog_vertCoord_loc,
+                                 2, GL_FLOAT, GL_FALSE, 0, NULL);
+    backend->VertexAttribPointer(backend->xbgr_prog_texCoord_loc,
+                                 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2));
+
+    backend->DrawArrays(GL_TRIANGLES, 0, count);
+
+    backend->DisableVertexAttribArray(backend->xbgr_prog_texCoord_loc);
+    backend->DisableVertexAttribArray(backend->xbgr_prog_vertCoord_loc);
+}
+
 static void vigs_gl_create_ortho(GLfloat left, GLfloat right,
                                  GLfloat bottom, GLfloat top,
                                  GLfloat nearf, GLfloat farf,
@@ -1791,6 +1832,77 @@ static void vigs_gl_surface_convert_yuv2argb(struct vigs_surface *dst,
 
     vigs_gl_draw_yuv420_prog(gl_backend, 6);
 
+out:
+    gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+static void vigs_gl_surface_convert_argb2xbgr(struct vigs_surface *dst,
+                                              struct vigs_surface *src)
+{
+    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_gl_surface *gl_src = (struct vigs_gl_surface*)src;
+    struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst);
+    struct vigs_winsys_gl_surface *ws_src = get_ws_sfc(gl_src);
+    GLsizei dst_w = ws_dst->base.base.width;
+    GLsizei dst_h = ws_dst->base.base.height;
+    GLfloat *vert_coords;
+    GLfloat *tex_coords;
+
+    if (!vigs_winsys_gl_surface_create_texture(ws_dst)) {
+        goto out;
+    }
+
+    if (!ws_src->tex) {
+        VIGS_LOG_WARN("copying garbage ???");
+    }
+
+    if (!vigs_winsys_gl_surface_create_texture(ws_src)) {
+        goto out;
+    }
+
+    if (!vigs_gl_surface_setup_framebuffer(gl_dst,
+                                           gl_backend->xbgr_prog_id,
+                                           gl_backend->xbgr_prog_proj_loc)) {
+        goto out;
+    }
+
+    vigs_vector_resize(&gl_backend->v1, 12 * sizeof(GLfloat));
+    vigs_vector_resize(&gl_backend->v2, 12 * sizeof(GLfloat));
+
+    vert_coords = vigs_vector_data(&gl_backend->v1);
+    tex_coords = vigs_vector_data(&gl_backend->v2);
+
+    vert_coords[6] = vert_coords[0] = 0;
+    vert_coords[7] = vert_coords[1] = dst_h;
+    vert_coords[2] = dst_w;
+    vert_coords[3] = dst_h;
+    vert_coords[8] = vert_coords[4] = dst_w;
+    vert_coords[9] = vert_coords[5] = 0.0;
+    vert_coords[10] = 0.0;
+    vert_coords[11] = 0.0;
+
+    tex_coords[6] = tex_coords[0] = 0.0;
+    tex_coords[7] = tex_coords[1] = 1.0;
+    tex_coords[2] = 1.0;
+    tex_coords[3] = 1.0;
+    tex_coords[8] = tex_coords[4] = 1.0;
+    tex_coords[9] = tex_coords[5] = 0.0;
+    tex_coords[10] = 0.0;
+    tex_coords[11] = 0.0;
+
+    gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER,
+                                     GL_COLOR_ATTACHMENT0,
+                                     GL_TEXTURE_2D,
+                                     ws_dst->tex,
+                                     0);
+
+    gl_backend->BindTexture(GL_TEXTURE_2D, ws_src->tex);
+
+    gl_backend->UseProgram(gl_backend->xbgr_prog_id);
+
+    vigs_gl_draw_xbgr_prog(gl_backend, 6);
+
     gl_backend->UseProgram(gl_backend->tex_prog_id);
 
 out:
@@ -1805,6 +1917,7 @@ static void vigs_gl_surface_convert(struct vigs_surface *dst,
 {
     uint32_t width = dst->ws_sfc->width;
     uint32_t height = dst->ws_sfc->height;
+    bool conversion_supported = true;
 
     struct vigsp_copy entry = {
         .from = { 0, 0 },
@@ -1819,18 +1932,32 @@ static void vigs_gl_surface_convert(struct vigs_surface *dst,
                              -1.0f, 1.0f, gl_dst->ortho);
     }
 
-    /*
-     * Currently only ARGB8888 destination format is needed for support
-     */
-    switch (src_format) {
-    case DRM_FORMAT_YUV420:
-        vigs_gl_surface_convert_yuv2argb(dst, src);
-        break;
+    switch (dst_format) {
     case DRM_FORMAT_ARGB8888:
-        vigs_gl_surface_copy(dst, src, &entry, 1);
+        switch (src_format) {
+        case DRM_FORMAT_YUV420:
+            vigs_gl_surface_convert_yuv2argb(dst, src);
+            break;
+        case DRM_FORMAT_ARGB8888:
+            vigs_gl_surface_copy(dst, src, &entry, 1);
+            break;
+        default:
+            conversion_supported = false;
+            break;
+        }
+        break;
+    case DRM_FORMAT_XBGR8888:
+        switch (src_format) {
+        case DRM_FORMAT_ARGB8888:
+            vigs_gl_surface_convert_argb2xbgr(dst, src);
+            break;
+        default:
+            conversion_supported = false;
+            break;
+        }
         break;
     default:
-        VIGS_LOG_ERROR("source format 0x%x is not supported", src_format);
+        conversion_supported = false;
         break;
     }
 
@@ -1838,6 +1965,12 @@ static void vigs_gl_surface_convert(struct vigs_surface *dst,
         vigs_gl_create_ortho(0.0f, width, 0.0f, height,
                              -1.0f, 1.0f, gl_dst->ortho);
     }
+
+    if (!conversion_supported) {
+        VIGS_LOG_ERROR("format conversion from 0x%x to 0x%x is not supported",
+                       src_format,
+                       dst_format);
+    }
 }
 
 static void vigs_gl_surface_destroy(struct vigs_surface *sfc)
@@ -2653,6 +2786,30 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
     gl_backend->yuv420_prog_utex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "utex");
     gl_backend->yuv420_prog_vtex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "vtex");
 
+    gl_backend->xbgr_prog_fs_id = vigs_gl_create_shader(gl_backend,
+        (gl_backend->is_gl_2 ? g_fs_xbgr_source_gl2 : g_fs_xbgr_source_gl3),
+        GL_FRAGMENT_SHADER);
+
+    if (!gl_backend->xbgr_prog_fs_id) {
+        goto fail;
+    }
+
+    /*
+     * Let's borrow compiled vertex shader from tex program
+     */
+
+    gl_backend->xbgr_prog_id = vigs_gl_create_program(gl_backend,
+                                                      gl_backend->tex_prog_vs_id,
+                                                      gl_backend->xbgr_prog_fs_id);
+
+    if (!gl_backend->xbgr_prog_id) {
+        goto fail;
+    }
+
+    gl_backend->xbgr_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->xbgr_prog_id, "proj");
+    gl_backend->xbgr_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->xbgr_prog_id, "vertCoord");
+    gl_backend->xbgr_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->xbgr_prog_id, "texCoord");
+
     gl_backend->GenBuffers(1, &gl_backend->vbo);
     if (!gl_backend->vbo) {
         VIGS_LOG_CRITICAL("cannot create VBOs");