From 880d8f3f6dc878a4e89e103fe072ed4825cdfa3e Mon Sep 17 00:00:00 2001 From: Stanislav Vorobiov Date: Mon, 16 Jun 2014 19:44:07 +0400 Subject: [PATCH] VIGS: Support planar pixel formats 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 --- hw/vigs/vigs_comm.c | 41 ++++- hw/vigs/vigs_comm.h | 14 +- hw/vigs/vigs_gl_backend.c | 351 +++++++++++++++++++++++++++++++++++++++--- hw/vigs/vigs_gl_backend.h | 15 ++ hw/vigs/vigs_gl_backend_cgl.c | 3 + hw/vigs/vigs_gl_backend_glx.c | 3 + hw/vigs/vigs_gl_backend_wgl.c | 3 + hw/vigs/vigs_plane.h | 65 +++++++- hw/vigs/vigs_protocol.h | 46 +++++- hw/vigs/vigs_server.c | 110 ++++++++----- hw/vigs/vigs_surface.h | 7 + hw/vigs/vigs_sw_backend.c | 13 ++ hw/vigs/vigs_utils.c | 16 ++ hw/vigs/vigs_utils.h | 2 + 14 files changed, 612 insertions(+), 77 deletions(-) diff --git a/hw/vigs/vigs_comm.c b/hw/vigs/vigs_comm.c index 6e08517..de3b3c7 100644 --- a/hw/vigs/vigs_comm.c +++ b/hw/vigs/vigs_comm.c @@ -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) { diff --git a/hw/vigs/vigs_comm.h b/hw/vigs/vigs_comm.h index b07c71b..cea76a6 100644 --- a/hw/vigs/vigs_comm.h +++ b/hw/vigs/vigs_comm.h @@ -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*/); }; diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index 438de8d..ba6baab 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -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, diff --git a/hw/vigs/vigs_gl_backend.h b/hw/vigs/vigs_gl_backend.h index 5d3b019..72f6630 100644 --- a/hw/vigs/vigs_gl_backend.h +++ b/hw/vigs/vigs_gl_backend.h @@ -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; diff --git a/hw/vigs/vigs_gl_backend_cgl.c b/hw/vigs/vigs_gl_backend_cgl.c index 996618a..e21a7a1 100644 --- a/hw/vigs/vigs_gl_backend_cgl.c +++ b/hw/vigs/vigs_gl_backend_cgl.c @@ -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); diff --git a/hw/vigs/vigs_gl_backend_glx.c b/hw/vigs/vigs_gl_backend_glx.c index caf5096..8faa13b 100644 --- a/hw/vigs/vigs_gl_backend_glx.c +++ b/hw/vigs/vigs_gl_backend_glx.c @@ -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); diff --git a/hw/vigs/vigs_gl_backend_wgl.c b/hw/vigs/vigs_gl_backend_wgl.c index b9b689e..219eb4d 100644 --- a/hw/vigs/vigs_gl_backend_wgl.c +++ b/hw/vigs/vigs_gl_backend_wgl.c @@ -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); diff --git a/hw/vigs/vigs_plane.h b/hw/vigs/vigs_plane.h index de53671..0ae9720 100644 --- a/hw/vigs/vigs_plane.h +++ b/hw/vigs/vigs_plane.h @@ -31,12 +31,16 @@ #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 diff --git a/hw/vigs/vigs_protocol.h b/hw/vigs/vigs_protocol.h index f00e281..e4663d5 100644 --- a/hw/vigs/vigs_protocol.h +++ b/hw/vigs/vigs_protocol.h @@ -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; @@ -354,6 +367,31 @@ struct vigsp_cmd_set_plane_request * @} */ +/* + * 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; +}; + +/* + * @} + */ + #pragma pack() #endif diff --git a/hw/vigs/vigs_server.c b/hw/vigs/vigs_server.c index 6be06b7..518bf23 100644 --- a/hw/vigs/vigs_server.c +++ b/hw/vigs/vigs_server.c @@ -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 { /* diff --git a/hw/vigs/vigs_surface.h b/hw/vigs/vigs_surface.h index 9867b0f..a508d06 100644 --- a/hw/vigs/vigs_surface.h +++ b/hw/vigs/vigs_surface.h @@ -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*/); }; diff --git a/hw/vigs/vigs_sw_backend.c b/hw/vigs/vigs_sw_backend.c index 5991089..ee3869d 100644 --- a/hw/vigs/vigs_sw_backend.c +++ b/hw/vigs/vigs_sw_backend.c @@ -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; diff --git a/hw/vigs/vigs_utils.c b/hw/vigs/vigs_utils.c index 0a2dab8..bca7de6 100644 --- a/hw/vigs/vigs_utils.c +++ b/hw/vigs/vigs_utils.c @@ -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; + } +} diff --git a/hw/vigs/vigs_utils.h b/hw/vigs/vigs_utils.h index 7e046fc..3d53702 100644 --- a/hw/vigs/vigs_utils.h +++ b/hw/vigs/vigs_utils.h @@ -38,4 +38,6 @@ */ uint32_t vigs_format_bpp(vigsp_surface_format format); +int vigs_format_num_buffers(vigsp_plane_format format); + #endif -- 2.7.4