diff options
author | Younes Manton <[email protected]> | 2009-09-27 19:49:06 -0400 |
---|---|---|
committer | Younes Manton <[email protected]> | 2009-09-27 19:49:06 -0400 |
commit | f547472bfa0a797adacc2a7688b4c1ba65381a80 (patch) | |
tree | df0070c8a239b105c512fa8cf24e8b776523558a /src/gallium/auxiliary/vl/vl_compositor.c | |
parent | da793b743462e84e3bca7a0ed7f24b4c942e0834 (diff) |
g3dvl: pipe_video_context interface, softpipe impl, auxiliary libs
Diffstat (limited to 'src/gallium/auxiliary/vl/vl_compositor.c')
-rw-r--r-- | src/gallium/auxiliary/vl/vl_compositor.c | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/src/gallium/auxiliary/vl/vl_compositor.c b/src/gallium/auxiliary/vl/vl_compositor.c new file mode 100644 index 00000000000..0894421c0b8 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_compositor.c @@ -0,0 +1,590 @@ +#include "vl_compositor.h" +#include <assert.h> +#include <pipe/p_context.h> +#include <pipe/p_inlines.h> +#include <tgsi/tgsi_parse.h> +#include <tgsi/tgsi_build.h> +#include <util/u_memory.h> +#include "vl_shader_build.h" + +struct vertex2f +{ + float x, y; +}; + +struct vertex4f +{ + float x, y, z, w; +}; + +struct vertex_shader_consts +{ + struct vertex4f dst_scale; + struct vertex4f dst_trans; + struct vertex4f src_scale; + struct vertex4f src_trans; +}; + +struct fragment_shader_consts +{ + struct vertex4f bias; + float matrix[16]; +}; + +/* + * Represents 2 triangles in a strip in normalized coords. + * Used to render the surface onto the frame buffer. + */ +static const struct vertex2f surface_verts[4] = +{ + {0.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 0.0f}, + {1.0f, 1.0f} +}; + +/* + * Represents texcoords for the above. We can use the position values directly. + * TODO: Duplicate these in the shader, no need to create a buffer. + */ +static const struct vertex2f *surface_texcoords = surface_verts; + +/* + * Identity color conversion constants, for debugging + */ +static const struct fragment_shader_consts identity = +{ + { + 0.0f, 0.0f, 0.0f, 0.0f + }, + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [16,235] + */ +static const struct fragment_shader_consts bt_601 = +{ + { + 0.0f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.0f, 0.0f, 1.371f, 0.0f, + 1.0f, -0.336f, -0.698f, 0.0f, + 1.0f, 1.732f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [0,255] + */ +static const struct fragment_shader_consts bt_601_full = +{ + { + 0.062745098f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.164f, 0.0f, 1.596f, 0.0f, + 1.164f, -0.391f, -0.813f, 0.0f, + 1.164f, 2.018f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [16,235] + */ +static const struct fragment_shader_consts bt_709 = +{ + { + 0.0f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.0f, 0.0f, 1.540f, 0.0f, + 1.0f, -0.183f, -0.459f, 0.0f, + 1.0f, 1.816f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [0,255] + */ +const struct fragment_shader_consts bt_709_full = +{ + { + 0.062745098f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.164f, 0.0f, 1.793f, 0.0f, + 1.164f, -0.213f, -0.534f, 0.0f, + 1.164f, 2.115f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +static void +create_vert_shader(struct vl_compositor *c) +{ + const unsigned max_tokens = 50; + + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned ti; + + assert(c); + + tokens = (struct tgsi_token*)MALLOC(max_tokens * sizeof(struct tgsi_token)); + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header); + + ti = 3; + + /* + * decl i0 ; Vertex pos + * decl i1 ; Vertex texcoords + */ + for (unsigned i = 0; i < 2; i++) + { + decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl c0 ; Scaling vector to scale vertex pos rect to destination size + * decl c1 ; Translation vector to move vertex pos rect into position + * decl c2 ; Scaling vector to scale texcoord rect to source size + * decl c3 ; Translation vector to move texcoord rect into position + */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 3); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl o0 ; Vertex pos + * decl o1 ; Vertex texcoords + */ + for (unsigned i = 0; i < 2; i++) + { + decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* decl t0, t1 */ + decl = vl_decl_temps(0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * mad o0, i0, c0, c1 ; Scale and translate unit output rect to destination size and pos + * mad o1, i1, c2, c3 ; Scale and translate unit texcoord rect to source size and pos + */ + for (unsigned i = 0; i < 2; ++i) + { + inst = vl_inst4(TGSI_OPCODE_MAD, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i, TGSI_FILE_CONSTANT, i * 2, TGSI_FILE_CONSTANT, i * 2 + 1); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + assert(ti <= max_tokens); + + vs.tokens = tokens; + c->vertex_shader = c->pipe->create_vs_state(c->pipe, &vs); + FREE(tokens); +} + +static void +create_frag_shader(struct vl_compositor *c) +{ + const unsigned max_tokens = 50; + + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned ti; + + assert(c); + + tokens = (struct tgsi_token*)MALLOC(max_tokens * sizeof(struct tgsi_token)); + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header); + + ti = 3; + + /* decl i0 ; Texcoords for s0 */ + decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, 1, 0, 0, TGSI_INTERPOLATE_LINEAR); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl c0 ; Bias vector for CSC + * decl c1-c4 ; CSC matrix c1-c4 + */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 4); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl o0 ; Fragment color */ + decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl t0 */ + decl = vl_decl_temps(0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl s0 ; Sampler for tex containing picture to display */ + decl = vl_decl_samplers(0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* tex2d t0, i0, s0 ; Read src pixel */ + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_INPUT, 0, TGSI_FILE_SAMPLER, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* sub t0, t0, c0 ; Subtract bias vector from pixel */ + inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* + * dp4 o0.x, t0, c1 ; Multiply pixel by the color conversion matrix + * dp4 o0.y, t0, c2 + * dp4 o0.z, t0, c3 + */ + for (unsigned i = 0; i < 3; ++i) + { + inst = vl_inst3(TGSI_OPCODE_DP4, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, i + 1); + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + assert(ti <= max_tokens); + + fs.tokens = tokens; + c->fragment_shader = c->pipe->create_fs_state(c->pipe, &fs); + FREE(tokens); +} + +static bool +init_pipe_state(struct vl_compositor *c) +{ + struct pipe_sampler_state sampler; + + assert(c); + + c->fb_state.nr_cbufs = 1; + c->fb_state.zsbuf = NULL; + + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + /*sampler.prefilter = ;*/ + /*sampler.lod_bias = ;*/ + /*sampler.min_lod = ;*/ + /*sampler.max_lod = ;*/ + /*sampler.border_color[i] = ;*/ + /*sampler.max_anisotropy = ;*/ + c->sampler = c->pipe->create_sampler_state(c->pipe, &sampler); + + return true; +} + +static void cleanup_pipe_state(struct vl_compositor *c) +{ + assert(c); + + c->pipe->delete_sampler_state(c->pipe, c->sampler); +} + +static bool +init_shaders(struct vl_compositor *c) +{ + assert(c); + + create_vert_shader(c); + create_frag_shader(c); + + return true; +} + +static void cleanup_shaders(struct vl_compositor *c) +{ + assert(c); + + c->pipe->delete_vs_state(c->pipe, c->vertex_shader); + c->pipe->delete_fs_state(c->pipe, c->fragment_shader); +} + +static bool +init_buffers(struct vl_compositor *c) +{ + assert(c); + + /* + * Create our vertex buffer and vertex buffer element + * VB contains 4 vertices that render a quad covering the entire window + * to display a rendered surface + * Quad is rendered as a tri strip + */ + c->vertex_bufs[0].stride = sizeof(struct vertex2f); + c->vertex_bufs[0].max_index = 3; + c->vertex_bufs[0].buffer_offset = 0; + c->vertex_bufs[0].buffer = pipe_buffer_create + ( + c->pipe->screen, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct vertex2f) * 4 + ); + + memcpy + ( + pipe_buffer_map(c->pipe->screen, c->vertex_bufs[0].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + surface_verts, + sizeof(struct vertex2f) * 4 + ); + + pipe_buffer_unmap(c->pipe->screen, c->vertex_bufs[0].buffer); + + c->vertex_elems[0].src_offset = 0; + c->vertex_elems[0].vertex_buffer_index = 0; + c->vertex_elems[0].nr_components = 2; + c->vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* + * Create our texcoord buffer and texcoord buffer element + * Texcoord buffer contains the TCs for mapping the rendered surface to the 4 vertices + */ + c->vertex_bufs[1].stride = sizeof(struct vertex2f); + c->vertex_bufs[1].max_index = 3; + c->vertex_bufs[1].buffer_offset = 0; + c->vertex_bufs[1].buffer = pipe_buffer_create + ( + c->pipe->screen, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct vertex2f) * 4 + ); + + memcpy + ( + pipe_buffer_map(c->pipe->screen, c->vertex_bufs[1].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + surface_texcoords, + sizeof(struct vertex2f) * 4 + ); + + pipe_buffer_unmap(c->pipe->screen, c->vertex_bufs[1].buffer); + + c->vertex_elems[1].src_offset = 0; + c->vertex_elems[1].vertex_buffer_index = 1; + c->vertex_elems[1].nr_components = 2; + c->vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* + * Create our vertex shader's constant buffer + * Const buffer contains scaling and translation vectors + */ + c->vs_const_buf.buffer = pipe_buffer_create + ( + c->pipe->screen, + 1, + PIPE_BUFFER_USAGE_CONSTANT | PIPE_BUFFER_USAGE_DISCARD, + sizeof(struct vertex_shader_consts) + ); + + /* + * Create our fragment shader's constant buffer + * Const buffer contains the color conversion matrix and bias vectors + */ + c->fs_const_buf.buffer = pipe_buffer_create + ( + c->pipe->screen, + 1, + PIPE_BUFFER_USAGE_CONSTANT, + sizeof(struct fragment_shader_consts) + ); + + /* + * TODO: Refactor this into a seperate function, + * allow changing the CSC matrix at runtime to switch between regular & full versions + */ + memcpy + ( + pipe_buffer_map(c->pipe->screen, c->fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + &bt_601_full, + sizeof(struct fragment_shader_consts) + ); + + pipe_buffer_unmap(c->pipe->screen, c->fs_const_buf.buffer); + + return true; +} + +static void +cleanup_buffers(struct vl_compositor *c) +{ + assert(c); + + for (unsigned i = 0; i < 2; ++i) + pipe_buffer_reference(&c->vertex_bufs[i].buffer, NULL); + + pipe_buffer_reference(&c->vs_const_buf.buffer, NULL); + pipe_buffer_reference(&c->fs_const_buf.buffer, NULL); +} + +bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe) +{ + assert(compositor); + + memset(compositor, 0, sizeof(struct vl_compositor)); + + compositor->pipe = pipe; + + if (!init_pipe_state(compositor)) + return false; + if (!init_shaders(compositor)) + { + cleanup_pipe_state(compositor); + return false; + } + if (!init_buffers(compositor)) + { + cleanup_shaders(compositor); + cleanup_pipe_state(compositor); + return false; + } + + return true; +} + +void vl_compositor_cleanup(struct vl_compositor *compositor) +{ + assert(compositor); + + cleanup_buffers(compositor); + cleanup_shaders(compositor); + cleanup_pipe_state(compositor); +} + +void vl_compositor_render(struct vl_compositor *compositor, + /*struct pipe_texture *backround, + struct pipe_video_rect *backround_area,*/ + struct pipe_texture *src_surface, + enum pipe_mpeg12_picture_type picture_type, + /*unsigned num_past_surfaces, + struct pipe_texture *past_surfaces, + unsigned num_future_surfaces, + struct pipe_texture *future_surfaces,*/ + struct pipe_video_rect *src_area, + struct pipe_texture *dst_surface, + struct pipe_video_rect *dst_area, + /*unsigned num_layers, + struct pipe_texture *layers, + struct pipe_video_rect *layer_src_areas, + struct pipe_video_rect *layer_dst_areas*/ + struct pipe_fence_handle **fence) +{ + struct vertex_shader_consts *vs_consts; + + assert(compositor); + assert(src_surface); + assert(src_area); + assert(dst_surface); + assert(dst_area); + assert(picture_type == PIPE_MPEG12_PICTURE_TYPE_FRAME); + + compositor->fb_state.width = dst_surface->width[0]; + compositor->fb_state.height = dst_surface->height[0]; + compositor->fb_state.cbufs[0] = compositor->pipe->screen->get_tex_surface + ( + compositor->pipe->screen, + dst_surface, + 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE + ); + + compositor->viewport.scale[0] = compositor->fb_state.width; + compositor->viewport.scale[1] = compositor->fb_state.height; + compositor->viewport.scale[2] = 1; + compositor->viewport.scale[3] = 1; + compositor->viewport.translate[0] = 0; + compositor->viewport.translate[1] = 0; + compositor->viewport.translate[2] = 0; + compositor->viewport.translate[3] = 0; + + compositor->pipe->set_framebuffer_state(compositor->pipe, &compositor->fb_state); + compositor->pipe->set_viewport_state(compositor->pipe, &compositor->viewport); + compositor->pipe->bind_sampler_states(compositor->pipe, 1, &compositor->sampler); + compositor->pipe->set_sampler_textures(compositor->pipe, 1, &src_surface); + compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader); + compositor->pipe->bind_fs_state(compositor->pipe, compositor->fragment_shader); + compositor->pipe->set_vertex_buffers(compositor->pipe, 2, compositor->vertex_bufs); + compositor->pipe->set_vertex_elements(compositor->pipe, 2, compositor->vertex_elems); + compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_VERTEX, 0, &compositor->vs_const_buf); + compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, &compositor->fs_const_buf); + + vs_consts = pipe_buffer_map + ( + compositor->pipe->screen, + compositor->vs_const_buf.buffer, + PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD + ); + + vs_consts->dst_scale.x = dst_area->w / (float)compositor->fb_state.cbufs[0]->width; + vs_consts->dst_scale.y = dst_area->h / (float)compositor->fb_state.cbufs[0]->height; + vs_consts->dst_scale.z = 1; + vs_consts->dst_scale.w = 1; + vs_consts->dst_trans.x = dst_area->x / (float)compositor->fb_state.cbufs[0]->width; + vs_consts->dst_trans.y = dst_area->y / (float)compositor->fb_state.cbufs[0]->height; + vs_consts->dst_trans.z = 0; + vs_consts->dst_trans.w = 0; + + vs_consts->src_scale.x = src_area->w / (float)src_surface->width[0]; + vs_consts->src_scale.y = src_area->h / (float)src_surface->height[0]; + vs_consts->src_scale.z = 1; + vs_consts->src_scale.w = 1; + vs_consts->src_trans.x = src_area->x / (float)src_surface->width[0]; + vs_consts->src_trans.y = src_area->y / (float)src_surface->height[0]; + vs_consts->src_trans.z = 0; + vs_consts->src_trans.w = 0; + + pipe_buffer_unmap(compositor->pipe->screen, compositor->vs_const_buf.buffer); + + compositor->pipe->draw_arrays(compositor->pipe, PIPE_PRIM_TRIANGLE_STRIP, 0, 4); + compositor->pipe->flush(compositor->pipe, PIPE_FLUSH_RENDER_CACHE, fence); + + pipe_surface_reference(&compositor->fb_state.cbufs[0], NULL); +} |