*
**************************************************************************/
-#include "vl_compositor.h"
#include <assert.h>
-#include <pipe/p_context.h>
-#include <util/u_inlines.h>
-#include <util/u_memory.h>
-#include <util/u_keymap.h>
-#include <util/u_draw.h>
-#include <util/u_sampler.h>
-#include <tgsi/tgsi_ureg.h>
-#include "vl_csc.h"
-struct vertex_shader_consts
-{
- struct vertex4f dst_scale;
- struct vertex4f dst_trans;
- struct vertex4f src_scale;
- struct vertex4f src_trans;
-};
+#include "pipe/p_compiler.h"
+#include "pipe/p_context.h"
-struct fragment_shader_consts
-{
- float matrix[16];
-};
+#include "util/u_memory.h"
+#include "util/u_draw.h"
+#include "util/u_surface.h"
-static bool
-u_video_rects_equal(struct pipe_video_rect *a, struct pipe_video_rect *b)
-{
- assert(a && b);
+#include "tgsi/tgsi_ureg.h"
- if (a->x != b->x)
- return false;
- if (a->y != b->y)
- return false;
- if (a->w != b->w)
- return false;
- if (a->h != b->h)
- return false;
+#include "vl_csc.h"
+#include "vl_types.h"
+#include "vl_compositor.h"
- return true;
-}
+typedef float csc_matrix[16];
-static bool
+static void *
create_vert_shader(struct vl_compositor *c)
{
struct ureg_program *shader;
ureg_END(shader);
- c->vertex_shader = ureg_create_shader_and_destroy(shader, c->pipe);
- if (!c->vertex_shader)
+ return ureg_create_shader_and_destroy(shader, c->pipe);
+}
+
+static void *
+create_frag_shader_video_buffer(struct vl_compositor *c)
+{
+ struct ureg_program *shader;
+ struct ureg_src tc;
+ struct ureg_src csc[3];
+ struct ureg_src sampler[3];
+ struct ureg_dst texel;
+ struct ureg_dst fragment;
+ unsigned i;
+
+ shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (!shader)
return false;
- return true;
+ tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
+ for (i = 0; i < 3; ++i) {
+ csc[i] = ureg_DECL_constant(shader, i);
+ sampler[i] = ureg_DECL_sampler(shader, i);
+ }
+ texel = ureg_DECL_temporary(shader);
+ fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+ /*
+ * texel.xyz = tex(tc, sampler[i])
+ * fragment = csc * texel
+ */
+ for (i = 0; i < 3; ++i)
+ ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, tc, sampler[i]);
+
+ ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
+
+ for (i = 0; i < 3; ++i)
+ ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
+
+ ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
+
+ ureg_release_temporary(shader, texel);
+ ureg_END(shader);
+
+ return ureg_create_shader_and_destroy(shader, c->pipe);
}
-static bool
-create_frag_shader_ycbcr_2_rgb(struct vl_compositor *c)
+static void *
+create_frag_shader_palette(struct vl_compositor *c, bool include_cc)
{
struct ureg_program *shader;
+ struct ureg_src csc[3];
struct ureg_src tc;
- struct ureg_src csc[4];
struct ureg_src sampler;
+ struct ureg_src palette;
struct ureg_dst texel;
struct ureg_dst fragment;
unsigned i;
if (!shader)
return false;
- tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
- for (i = 0; i < 4; ++i)
+ for (i = 0; i < 3; ++i)
csc[i] = ureg_DECL_constant(shader, i);
+
+ tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
sampler = ureg_DECL_sampler(shader, 0);
+ palette = ureg_DECL_sampler(shader, 1);
+
texel = ureg_DECL_temporary(shader);
fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
/*
* texel = tex(tc, sampler)
- * fragment = csc * texel
+ * fragment.xyz = tex(texel, palette) * csc
+ * fragment.a = texel.a
*/
ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
- for (i = 0; i < 4; ++i)
- ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
+ ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(texel));
+
+ if (include_cc) {
+ ureg_TEX(shader, texel, TGSI_TEXTURE_1D, ureg_src(texel), palette);
+ for (i = 0; i < 3; ++i)
+ ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
+ } else {
+ ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ),
+ TGSI_TEXTURE_1D, ureg_src(texel), palette);
+ }
ureg_release_temporary(shader, texel);
ureg_END(shader);
- c->fragment_shader.ycbcr_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
- if (!c->fragment_shader.ycbcr_2_rgb)
- return false;
-
- return true;
+ return ureg_create_shader_and_destroy(shader, c->pipe);
}
-static bool
-create_frag_shader_rgb_2_rgb(struct vl_compositor *c)
+static void *
+create_frag_shader_rgba(struct vl_compositor *c)
{
struct ureg_program *shader;
struct ureg_src tc;
ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler);
ureg_END(shader);
- c->fragment_shader.rgb_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
- if (!c->fragment_shader.rgb_2_rgb)
+ return ureg_create_shader_and_destroy(shader, c->pipe);
+}
+
+static bool
+init_shaders(struct vl_compositor *c)
+{
+ assert(c);
+
+ c->vs = create_vert_shader(c);
+ if (!c->vs) {
+ debug_printf("Unable to create vertex shader.\n");
+ return false;
+ }
+
+ c->fs_video_buffer = create_frag_shader_video_buffer(c);
+ if (!c->fs_video_buffer) {
+ debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
+ return false;
+ }
+
+ c->fs_palette.yuv = create_frag_shader_palette(c, true);
+ if (!c->fs_palette.yuv) {
+ debug_printf("Unable to create YUV-Palette-to-RGB fragment shader.\n");
+ return false;
+ }
+
+ c->fs_palette.rgb = create_frag_shader_palette(c, false);
+ if (!c->fs_palette.rgb) {
+ debug_printf("Unable to create RGB-Palette-to-RGB fragment shader.\n");
+ return false;
+ }
+
+ c->fs_rgba = create_frag_shader_rgba(c);
+ if (!c->fs_rgba) {
+ debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
return false;
+ }
return true;
}
+static void cleanup_shaders(struct vl_compositor *c)
+{
+ assert(c);
+
+ c->pipe->delete_vs_state(c->pipe, c->vs);
+ c->pipe->delete_fs_state(c->pipe, c->fs_video_buffer);
+ c->pipe->delete_fs_state(c->pipe, c->fs_palette.yuv);
+ c->pipe->delete_fs_state(c->pipe, c->fs_palette.rgb);
+ c->pipe->delete_fs_state(c->pipe, c->fs_rgba);
+}
+
static bool
init_pipe_state(struct vl_compositor *c)
{
+ struct pipe_rasterizer_state rast;
struct pipe_sampler_state sampler;
+ struct pipe_blend_state blend;
+ struct pipe_depth_stencil_alpha_state dsa;
+ unsigned i;
assert(c);
c->fb_state.nr_cbufs = 1;
c->fb_state.zsbuf = NULL;
+ c->viewport.scale[2] = 1;
+ c->viewport.scale[3] = 1;
+ c->viewport.translate[2] = 0;
+ c->viewport.translate[3] = 0;
+
+ memset(&sampler, 0, sizeof(sampler));
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.compare_mode = PIPE_TEX_COMPARE_NONE;
sampler.compare_func = PIPE_FUNC_ALWAYS;
sampler.normalized_coords = 1;
- /*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);
+ c->sampler_linear = c->pipe->create_sampler_state(c->pipe, &sampler);
+
+ sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
+ sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
+ c->sampler_nearest = c->pipe->create_sampler_state(c->pipe, &sampler);
+
+ memset(&blend, 0, sizeof blend);
+ blend.independent_blend_enable = 0;
+ blend.rt[0].blend_enable = 0;
+ blend.logicop_enable = 0;
+ blend.logicop_func = PIPE_LOGICOP_CLEAR;
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+ blend.dither = 0;
+ c->blend_clear = c->pipe->create_blend_state(c->pipe, &blend);
+
+ blend.rt[0].blend_enable = 1;
+ blend.rt[0].rgb_func = PIPE_BLEND_ADD;
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ blend.rt[0].alpha_func = PIPE_BLEND_ADD;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
+ c->blend_add = c->pipe->create_blend_state(c->pipe, &blend);
+
+ memset(&rast, 0, sizeof rast);
+ rast.flatshade = 1;
+ rast.front_ccw = 1;
+ rast.cull_face = PIPE_FACE_NONE;
+ rast.fill_back = PIPE_POLYGON_MODE_FILL;
+ rast.fill_front = PIPE_POLYGON_MODE_FILL;
+ rast.scissor = 1;
+ rast.line_width = 1;
+ rast.point_size_per_vertex = 1;
+ rast.offset_units = 1;
+ rast.offset_scale = 1;
+ rast.gl_rasterization_rules = 1;
+
+ c->rast = c->pipe->create_rasterizer_state(c->pipe, &rast);
+
+ memset(&dsa, 0, sizeof dsa);
+ dsa.depth.enabled = 0;
+ dsa.depth.writemask = 0;
+ dsa.depth.func = PIPE_FUNC_ALWAYS;
+ for (i = 0; i < 2; ++i) {
+ dsa.stencil[i].enabled = 0;
+ dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
+ dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].valuemask = 0;
+ dsa.stencil[i].writemask = 0;
+ }
+ dsa.alpha.enabled = 0;
+ dsa.alpha.func = PIPE_FUNC_ALWAYS;
+ dsa.alpha.ref_value = 0;
+ c->dsa = c->pipe->create_depth_stencil_alpha_state(c->pipe, &dsa);
+ c->pipe->bind_depth_stencil_alpha_state(c->pipe, c->dsa);
return true;
}
{
assert(c);
- c->pipe->delete_sampler_state(c->pipe, c->sampler);
-}
-
-static bool
-init_shaders(struct vl_compositor *c)
-{
- assert(c);
-
- if (!create_vert_shader(c)) {
- debug_printf("Unable to create vertex shader.\n");
- return false;
- }
- if (!create_frag_shader_ycbcr_2_rgb(c)) {
- debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
- return false;
- }
- if (!create_frag_shader_rgb_2_rgb(c)) {
- debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
- return false;
- }
+ /* Asserted in softpipe_delete_fs_state() for some reason */
+ c->pipe->bind_vs_state(c->pipe, NULL);
+ c->pipe->bind_fs_state(c->pipe, NULL);
- return true;
+ c->pipe->delete_depth_stencil_alpha_state(c->pipe, c->dsa);
+ c->pipe->delete_sampler_state(c->pipe, c->sampler_linear);
+ c->pipe->delete_sampler_state(c->pipe, c->sampler_nearest);
+ c->pipe->delete_blend_state(c->pipe, c->blend_clear);
+ c->pipe->delete_blend_state(c->pipe, c->blend_add);
+ c->pipe->delete_rasterizer_state(c->pipe, c->rast);
}
-static void cleanup_shaders(struct vl_compositor *c)
+static bool
+create_vertex_buffer(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.ycbcr_2_rgb);
- c->pipe->delete_fs_state(c->pipe, c->fragment_shader.rgb_2_rgb);
+ pipe_resource_reference(&c->vertex_buf.buffer, NULL);
+ c->vertex_buf.buffer = pipe_buffer_create
+ (
+ c->pipe->screen,
+ PIPE_BIND_VERTEX_BUFFER,
+ PIPE_USAGE_STREAM,
+ sizeof(struct vertex4f) * VL_COMPOSITOR_MAX_LAYERS * 4
+ );
+ return c->vertex_buf.buffer != NULL;
}
static bool
init_buffers(struct vl_compositor *c)
{
- struct fragment_shader_consts fsc;
struct pipe_vertex_element vertex_elems[2];
assert(c);
* Create our vertex buffer and vertex buffer elements
*/
c->vertex_buf.stride = sizeof(struct vertex4f);
- c->vertex_buf.max_index = (VL_COMPOSITOR_MAX_LAYERS + 2) * 6 - 1;
c->vertex_buf.buffer_offset = 0;
- /* XXX: Create with DYNAMIC or STREAM */
- c->vertex_buf.buffer = pipe_buffer_create
- (
- c->pipe->screen,
- PIPE_BIND_VERTEX_BUFFER,
- sizeof(struct vertex4f) * (VL_COMPOSITOR_MAX_LAYERS + 2) * 6
- );
+ create_vertex_buffer(c);
vertex_elems[0].src_offset = 0;
vertex_elems[0].instance_divisor = 0;
* Const buffer contains the color conversion matrix and bias vectors
*/
/* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
- c->fs_const_buf = pipe_buffer_create
+ c->csc_matrix = pipe_buffer_create
(
c->pipe->screen,
PIPE_BIND_CONSTANT_BUFFER,
- sizeof(struct fragment_shader_consts)
+ PIPE_USAGE_STATIC,
+ sizeof(csc_matrix)
);
- vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, fsc.matrix);
-
- vl_compositor_set_csc_matrix(c, fsc.matrix);
-
return true;
}
c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
pipe_resource_reference(&c->vertex_buf.buffer, NULL);
- pipe_resource_reference(&c->fs_const_buf, NULL);
+ pipe_resource_reference(&c->csc_matrix, NULL);
}
-static void
-texview_map_delete(const struct keymap *map,
- const void *key, void *data,
- void *user)
+static INLINE struct pipe_video_rect
+default_rect(struct vl_compositor_layer *layer)
{
- struct pipe_sampler_view *sv = (struct pipe_sampler_view*)data;
+ struct pipe_resource *res = layer->sampler_views[0]->texture;
+ struct pipe_video_rect rect = { 0, 0, res->width0, res->height0 };
+ return rect;
+}
- assert(map);
- assert(key);
- assert(data);
- assert(user);
+static INLINE struct vertex2f
+calc_topleft(struct vertex2f size, struct pipe_video_rect rect)
+{
+ struct vertex2f res = { rect.x / size.x, rect.y / size.y };
+ return res;
+}
- pipe_sampler_view_reference(&sv, NULL);
+static INLINE struct vertex2f
+calc_bottomright(struct vertex2f size, struct pipe_video_rect rect)
+{
+ struct vertex2f res = { (rect.x + rect.w) / size.x, (rect.y + rect.h) / size.y };
+ return res;
}
-bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe)
+static INLINE void
+calc_src_and_dst(struct vl_compositor_layer *layer, unsigned width, unsigned height,
+ struct pipe_video_rect src, struct pipe_video_rect dst)
{
- unsigned i;
+ struct vertex2f size = { width, height };
- assert(compositor);
+ layer->src.tl = calc_topleft(size, src);
+ layer->src.br = calc_bottomright(size, src);
+ layer->dst.tl = calc_topleft(size, dst);
+ layer->dst.br = calc_bottomright(size, dst);
+}
- memset(compositor, 0, sizeof(struct vl_compositor));
+static void
+gen_rect_verts(struct vertex4f *vb, struct vl_compositor_layer *layer)
+{
+ assert(vb && layer);
+
+ vb[0].x = layer->dst.tl.x;
+ vb[0].y = layer->dst.tl.y;
+ vb[0].z = layer->src.tl.x;
+ vb[0].w = layer->src.tl.y;
+
+ vb[1].x = layer->dst.br.x;
+ vb[1].y = layer->dst.tl.y;
+ vb[1].z = layer->src.br.x;
+ vb[1].w = layer->src.tl.y;
+
+ vb[2].x = layer->dst.br.x;
+ vb[2].y = layer->dst.br.y;
+ vb[2].z = layer->src.br.x;
+ vb[2].w = layer->src.br.y;
+
+ vb[3].x = layer->dst.tl.x;
+ vb[3].y = layer->dst.br.y;
+ vb[3].z = layer->src.tl.x;
+ vb[3].w = layer->src.br.y;
+}
- compositor->pipe = pipe;
+static void
+gen_vertex_data(struct vl_compositor *c)
+{
+ struct vertex4f *vb;
+ struct pipe_transfer *buf_transfer;
+ unsigned i;
- compositor->texview_map = util_new_keymap(sizeof(struct pipe_surface*), -1,
- texview_map_delete);
- if (!compositor->texview_map)
- return false;
+ assert(c);
- if (!init_pipe_state(compositor)) {
- util_delete_keymap(compositor->texview_map, compositor->pipe);
- return false;
- }
- if (!init_shaders(compositor)) {
- util_delete_keymap(compositor->texview_map, compositor->pipe);
- cleanup_pipe_state(compositor);
- return false;
- }
- if (!init_buffers(compositor)) {
- util_delete_keymap(compositor->texview_map, compositor->pipe);
- cleanup_shaders(compositor);
- cleanup_pipe_state(compositor);
- return false;
+ vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
+ PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_DONTBLOCK,
+ &buf_transfer);
+
+ if (!vb) {
+ // If buffer is still locked from last draw create a new one
+ create_vertex_buffer(c);
+ vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
+ PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &buf_transfer);
}
- compositor->fb_state.width = 0;
- compositor->fb_state.height = 0;
- compositor->bg = NULL;
- compositor->dirty_bg = false;
- for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
- compositor->layers[i] = NULL;
- compositor->dirty_layers = 0;
+ for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; i++) {
+ if (c->used_layers & (1 << i)) {
+ struct vl_compositor_layer *layer = &c->layers[i];
+ gen_rect_verts(vb, layer);
+ vb += 4;
+
+ if (layer->clearing &&
+ c->dirty_tl.x >= layer->dst.tl.x &&
+ c->dirty_tl.y >= layer->dst.tl.y &&
+ c->dirty_br.x <= layer->dst.br.x &&
+ c->dirty_br.y <= layer->dst.br.y) {
+
+ // We clear the dirty area anyway, no need for clear_render_target
+ c->dirty_tl.x = c->dirty_tl.y = 1.0f;
+ c->dirty_br.x = c->dirty_br.y = 0.0f;
+ }
+ }
+ }
- return true;
+ pipe_buffer_unmap(c->pipe, buf_transfer);
}
-void vl_compositor_cleanup(struct vl_compositor *compositor)
+static void
+draw_layers(struct vl_compositor *c)
{
- assert(compositor);
+ unsigned vb_index, i;
- util_delete_keymap(compositor->texview_map, compositor->pipe);
- cleanup_buffers(compositor);
- cleanup_shaders(compositor);
- cleanup_pipe_state(compositor);
+ assert(c);
+
+ for (i = 0, vb_index = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
+ if (c->used_layers & (1 << i)) {
+ struct vl_compositor_layer *layer = &c->layers[i];
+ struct pipe_sampler_view **samplers = &layer->sampler_views[0];
+ unsigned num_sampler_views = !samplers[1] ? 1 : !samplers[2] ? 2 : 3;
+
+ c->pipe->bind_blend_state(c->pipe, layer->blend);
+ c->pipe->bind_fs_state(c->pipe, layer->fs);
+ c->pipe->bind_fragment_sampler_states(c->pipe, num_sampler_views, layer->samplers);
+ c->pipe->set_fragment_sampler_views(c->pipe, num_sampler_views, samplers);
+ util_draw_arrays(c->pipe, PIPE_PRIM_QUADS, vb_index * 4, 4);
+ vb_index++;
+
+ // Remember the currently drawn area as dirty for the next draw command
+ c->dirty_tl.x = MIN2(layer->dst.tl.x, c->dirty_tl.x);
+ c->dirty_tl.y = MIN2(layer->dst.tl.y, c->dirty_tl.y);
+ c->dirty_br.x = MAX2(layer->dst.br.x, c->dirty_br.x);
+ c->dirty_br.y = MAX2(layer->dst.br.y, c->dirty_br.y);
+ }
+ }
}
-void vl_compositor_set_background(struct vl_compositor *compositor,
- struct pipe_surface *bg, struct pipe_video_rect *bg_src_rect)
+void
+vl_compositor_reset_dirty_area(struct vl_compositor *c)
{
- assert(compositor);
- assert((bg && bg_src_rect) || (!bg && !bg_src_rect));
-
- if (compositor->bg != bg ||
- !u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect)) {
- pipe_surface_reference(&compositor->bg, bg);
- /*if (!u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect))*/
- compositor->bg_src_rect = *bg_src_rect;
- compositor->dirty_bg = true;
- }
+ assert(c);
+
+ c->dirty_tl.x = c->dirty_tl.y = 0.0f;
+ c->dirty_br.x = c->dirty_br.y = 1.0f;
}
-void vl_compositor_set_layers(struct vl_compositor *compositor,
- struct pipe_surface *layers[],
- struct pipe_video_rect *src_rects[],
- struct pipe_video_rect *dst_rects[],
- unsigned num_layers)
+void
+vl_compositor_set_clear_color(struct vl_compositor *c, float color[4])
{
unsigned i;
- assert(compositor);
- assert(num_layers <= VL_COMPOSITOR_MAX_LAYERS);
-
- for (i = 0; i < num_layers; ++i)
- {
- assert((layers[i] && src_rects[i] && dst_rects[i]) ||
- (!layers[i] && !src_rects[i] && !dst_rects[i]));
-
- if (compositor->layers[i] != layers[i] ||
- !u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]) ||
- !u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))
- {
- pipe_surface_reference(&compositor->layers[i], layers[i]);
- /*if (!u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]))*/
- compositor->layer_src_rects[i] = *src_rects[i];
- /*if (!u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))*/
- compositor->layer_dst_rects[i] = *dst_rects[i];
- compositor->dirty_layers |= 1 << i;
- }
+ assert(c);
- if (layers[i])
- compositor->dirty_layers |= 1 << i;
- }
+ for (i = 0; i < 4; ++i)
+ c->clear_color[i] = color[i];
+}
+
+void
+vl_compositor_clear_layers(struct vl_compositor *c)
+{
+ unsigned i, j;
- for (; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
- pipe_surface_reference(&compositor->layers[i], NULL);
+ assert(c);
+
+ c->used_layers = 0;
+ for ( i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
+ c->layers[i].clearing = i ? false : true;
+ c->layers[i].blend = i ? c->blend_add : c->blend_clear;
+ c->layers[i].fs = NULL;
+ for ( j = 0; j < 3; j++)
+ pipe_sampler_view_reference(&c->layers[i].sampler_views[j], NULL);
+ }
}
-static void gen_rect_verts(unsigned pos,
- struct pipe_video_rect *src_rect,
- struct vertex2f *src_inv_size,
- struct pipe_video_rect *dst_rect,
- struct vertex2f *dst_inv_size,
- struct vertex4f *vb)
+void
+vl_compositor_cleanup(struct vl_compositor *c)
{
- assert(pos < VL_COMPOSITOR_MAX_LAYERS + 2);
- assert(src_rect);
- assert(src_inv_size);
- assert((dst_rect && dst_inv_size) /*|| (!dst_rect && !dst_inv_size)*/);
- assert(vb);
-
- vb[pos * 6 + 0].x = dst_rect->x * dst_inv_size->x;
- vb[pos * 6 + 0].y = dst_rect->y * dst_inv_size->y;
- vb[pos * 6 + 0].z = src_rect->x * src_inv_size->x;
- vb[pos * 6 + 0].w = src_rect->y * src_inv_size->y;
-
- vb[pos * 6 + 1].x = dst_rect->x * dst_inv_size->x;
- vb[pos * 6 + 1].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
- vb[pos * 6 + 1].z = src_rect->x * src_inv_size->x;
- vb[pos * 6 + 1].w = (src_rect->y + src_rect->h) * src_inv_size->y;
-
- vb[pos * 6 + 2].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
- vb[pos * 6 + 2].y = dst_rect->y * dst_inv_size->y;
- vb[pos * 6 + 2].z = (src_rect->x + src_rect->w) * src_inv_size->x;
- vb[pos * 6 + 2].w = src_rect->y * src_inv_size->y;
-
- vb[pos * 6 + 3].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
- vb[pos * 6 + 3].y = dst_rect->y * dst_inv_size->y;
- vb[pos * 6 + 3].z = (src_rect->x + src_rect->w) * src_inv_size->x;
- vb[pos * 6 + 3].w = src_rect->y * src_inv_size->y;
-
- vb[pos * 6 + 4].x = dst_rect->x * dst_inv_size->x;
- vb[pos * 6 + 4].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
- vb[pos * 6 + 4].z = src_rect->x * src_inv_size->x;
- vb[pos * 6 + 4].w = (src_rect->y + src_rect->h) * src_inv_size->y;
-
- vb[pos * 6 + 5].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
- vb[pos * 6 + 5].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
- vb[pos * 6 + 5].z = (src_rect->x + src_rect->w) * src_inv_size->x;
- vb[pos * 6 + 5].w = (src_rect->y + src_rect->h) * src_inv_size->y;
+ assert(c);
+
+ vl_compositor_clear_layers(c);
+
+ cleanup_buffers(c);
+ cleanup_shaders(c);
+ cleanup_pipe_state(c);
}
-static unsigned gen_data(struct vl_compositor *c,
- struct pipe_surface *src_surface,
- struct pipe_video_rect *src_rect,
- struct pipe_video_rect *dst_rect,
- struct pipe_surface **textures,
- void **frag_shaders)
+void
+vl_compositor_set_csc_matrix(struct vl_compositor *c, const float matrix[16])
{
- void *vb;
struct pipe_transfer *buf_transfer;
- unsigned num_rects = 0;
- unsigned i;
assert(c);
- assert(src_surface);
- assert(src_rect);
- assert(dst_rect);
- assert(textures);
- vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
- PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
- &buf_transfer);
-
- if (!vb)
- return 0;
-
- if (c->dirty_bg) {
- struct vertex2f bg_inv_size = {1.0f / c->bg->width, 1.0f / c->bg->height};
- gen_rect_verts(num_rects, &c->bg_src_rect, &bg_inv_size, NULL, NULL, vb);
- textures[num_rects] = c->bg;
- /* XXX: Hack */
- frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
- ++num_rects;
- c->dirty_bg = false;
- }
+ memcpy
+ (
+ pipe_buffer_map(c->pipe, c->csc_matrix,
+ PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &buf_transfer),
+ matrix,
+ sizeof(csc_matrix)
+ );
- {
- struct vertex2f src_inv_size = { 1.0f / src_surface->width, 1.0f / src_surface->height};
- gen_rect_verts(num_rects, src_rect, &src_inv_size, dst_rect, &c->fb_inv_size, vb);
- textures[num_rects] = src_surface;
- /* XXX: Hack, sort of */
- frag_shaders[num_rects] = c->fragment_shader.ycbcr_2_rgb;
- ++num_rects;
- }
+ pipe_buffer_unmap(c->pipe, buf_transfer);
+}
- for (i = 0; c->dirty_layers > 0; i++) {
- assert(i < VL_COMPOSITOR_MAX_LAYERS);
-
- if (c->dirty_layers & (1 << i)) {
- struct vertex2f layer_inv_size = {1.0f / c->layers[i]->width, 1.0f / c->layers[i]->height};
- gen_rect_verts(num_rects, &c->layer_src_rects[i], &layer_inv_size,
- &c->layer_dst_rects[i], &c->fb_inv_size, vb);
- textures[num_rects] = c->layers[i];
- /* XXX: Hack */
- frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
- ++num_rects;
- c->dirty_layers &= ~(1 << i);
- }
- }
+void
+vl_compositor_set_layer_blend(struct vl_compositor *c,
+ unsigned layer, void *blend,
+ bool is_clearing)
+{
+ assert(c && blend);
- pipe_buffer_unmap(c->pipe, c->vertex_buf.buffer, buf_transfer);
+ assert(layer < VL_COMPOSITOR_MAX_LAYERS);
- return num_rects;
+ c->layers[layer].clearing = is_clearing;
+ c->layers[layer].blend = blend;
}
-static void draw_layers(struct vl_compositor *c,
- struct pipe_surface *src_surface,
- struct pipe_video_rect *src_rect,
- struct pipe_video_rect *dst_rect)
+void
+vl_compositor_set_buffer_layer(struct vl_compositor *c,
+ unsigned layer,
+ struct pipe_video_buffer *buffer,
+ struct pipe_video_rect *src_rect,
+ struct pipe_video_rect *dst_rect)
{
- unsigned num_rects;
- struct pipe_surface *src_surfaces[VL_COMPOSITOR_MAX_LAYERS + 2];
- void *frag_shaders[VL_COMPOSITOR_MAX_LAYERS + 2];
+ struct pipe_sampler_view **sampler_views;
unsigned i;
- assert(c);
- assert(src_surface);
- assert(src_rect);
- assert(dst_rect);
-
- num_rects = gen_data(c, src_surface, src_rect, dst_rect, src_surfaces, frag_shaders);
-
- for (i = 0; i < num_rects; ++i) {
- boolean delete_view = FALSE;
- struct pipe_sampler_view *surface_view = (struct pipe_sampler_view*)util_keymap_lookup(c->texview_map,
- &src_surfaces[i]);
- if (!surface_view) {
- struct pipe_sampler_view templat;
- u_sampler_view_default_template(&templat, src_surfaces[i]->texture,
- src_surfaces[i]->texture->format);
- surface_view = c->pipe->create_sampler_view(c->pipe, src_surfaces[i]->texture,
- &templat);
- if (!surface_view)
- return;
-
- delete_view = !util_keymap_insert(c->texview_map, &src_surfaces[i],
- surface_view, c->pipe);
- }
+ assert(c && buffer);
- c->pipe->bind_fs_state(c->pipe, frag_shaders[i]);
- c->pipe->set_fragment_sampler_views(c->pipe, 1, &surface_view);
-
+ assert(layer < VL_COMPOSITOR_MAX_LAYERS);
- util_draw_arrays(c->pipe,PIPE_PRIM_TRIANGLES,i * 6,6);
+ c->used_layers |= 1 << layer;
+ c->layers[layer].fs = c->fs_video_buffer;
- if (delete_view) {
- pipe_sampler_view_reference(&surface_view, NULL);
- }
+ sampler_views = buffer->get_sampler_view_components(buffer);
+ for (i = 0; i < 3; ++i) {
+ c->layers[layer].samplers[i] = c->sampler_linear;
+ pipe_sampler_view_reference(&c->layers[layer].sampler_views[i], sampler_views[i]);
}
+
+ calc_src_and_dst(&c->layers[layer], buffer->width, buffer->height,
+ src_rect ? *src_rect : default_rect(&c->layers[layer]),
+ dst_rect ? *dst_rect : default_rect(&c->layers[layer]));
}
-void vl_compositor_render(struct vl_compositor *compositor,
- struct pipe_surface *src_surface,
- enum pipe_mpeg12_picture_type picture_type,
- /*unsigned num_past_surfaces,
- struct pipe_surface *past_surfaces,
- unsigned num_future_surfaces,
- struct pipe_surface *future_surfaces,*/
- struct pipe_video_rect *src_area,
- struct pipe_surface *dst_surface,
- struct pipe_video_rect *dst_area,
- struct pipe_fence_handle **fence)
+void
+vl_compositor_set_palette_layer(struct vl_compositor *c,
+ unsigned layer,
+ struct pipe_sampler_view *indexes,
+ struct pipe_sampler_view *palette,
+ struct pipe_video_rect *src_rect,
+ struct pipe_video_rect *dst_rect,
+ bool include_color_conversion)
{
- assert(compositor);
- assert(src_surface);
- assert(src_area);
+ assert(c && indexes && palette);
+
+ assert(layer < VL_COMPOSITOR_MAX_LAYERS);
+
+ c->used_layers |= 1 << layer;
+
+ c->layers[layer].fs = include_color_conversion ?
+ c->fs_palette.yuv : c->fs_palette.rgb;
+
+ c->layers[layer].samplers[0] = c->sampler_linear;
+ c->layers[layer].samplers[1] = c->sampler_nearest;
+ c->layers[layer].samplers[2] = NULL;
+ pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], indexes);
+ pipe_sampler_view_reference(&c->layers[layer].sampler_views[1], palette);
+ pipe_sampler_view_reference(&c->layers[layer].sampler_views[2], NULL);
+ calc_src_and_dst(&c->layers[layer], indexes->texture->width0, indexes->texture->height0,
+ src_rect ? *src_rect : default_rect(&c->layers[layer]),
+ dst_rect ? *dst_rect : default_rect(&c->layers[layer]));
+
+}
+
+void
+vl_compositor_set_rgba_layer(struct vl_compositor *c,
+ unsigned layer,
+ struct pipe_sampler_view *rgba,
+ struct pipe_video_rect *src_rect,
+ struct pipe_video_rect *dst_rect)
+{
+ assert(c && rgba);
+
+ assert(layer < VL_COMPOSITOR_MAX_LAYERS);
+
+ c->used_layers |= 1 << layer;
+ c->layers[layer].fs = c->fs_rgba;
+ c->layers[layer].samplers[0] = c->sampler_linear;
+ c->layers[layer].samplers[1] = NULL;
+ c->layers[layer].samplers[2] = NULL;
+ pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], rgba);
+ pipe_sampler_view_reference(&c->layers[layer].sampler_views[1], NULL);
+ pipe_sampler_view_reference(&c->layers[layer].sampler_views[2], NULL);
+ calc_src_and_dst(&c->layers[layer], rgba->texture->width0, rgba->texture->height0,
+ src_rect ? *src_rect : default_rect(&c->layers[layer]),
+ dst_rect ? *dst_rect : default_rect(&c->layers[layer]));
+}
+
+void
+vl_compositor_render(struct vl_compositor *c,
+ struct pipe_surface *dst_surface,
+ struct pipe_video_rect *dst_area,
+ struct pipe_video_rect *dst_clip,
+ bool clear_dirty_area)
+{
+ struct pipe_scissor_state scissor;
+
+ assert(c);
assert(dst_surface);
- assert(dst_area);
- assert(picture_type == PIPE_MPEG12_PICTURE_TYPE_FRAME);
- if (compositor->fb_state.width != dst_surface->width) {
- compositor->fb_inv_size.x = 1.0f / dst_surface->width;
- compositor->fb_state.width = dst_surface->width;
+ c->fb_state.width = dst_surface->width;
+ c->fb_state.height = dst_surface->height;
+ c->fb_state.cbufs[0] = dst_surface;
+
+ if (dst_area) {
+ c->viewport.scale[0] = dst_area->w;
+ c->viewport.scale[1] = dst_area->h;
+ c->viewport.translate[0] = dst_area->x;
+ c->viewport.translate[1] = dst_area->y;
+ } else {
+ c->viewport.scale[0] = dst_surface->width;
+ c->viewport.scale[1] = dst_surface->height;
+ c->viewport.translate[0] = 0;
+ c->viewport.translate[1] = 0;
+ }
+
+ if (dst_clip) {
+ scissor.minx = dst_clip->x;
+ scissor.miny = dst_clip->y;
+ scissor.maxx = dst_clip->x + dst_clip->w;
+ scissor.maxy = dst_clip->y + dst_clip->h;
+ } else {
+ scissor.minx = 0;
+ scissor.miny = 0;
+ scissor.maxx = dst_surface->width;
+ scissor.maxy = dst_surface->height;
}
- if (compositor->fb_state.height != dst_surface->height) {
- compositor->fb_inv_size.y = 1.0f / dst_surface->height;
- compositor->fb_state.height = dst_surface->height;
+
+ gen_vertex_data(c);
+
+ if (clear_dirty_area && (c->dirty_tl.x < c->dirty_br.x ||
+ c->dirty_tl.y < c->dirty_br.y)) {
+ util_clear_render_target(c->pipe, dst_surface, c->clear_color,
+ 0, 0, dst_surface->width, dst_surface->height);
+ c->dirty_tl.x = c->dirty_tl.y = 1.0f;
+ c->dirty_br.x = c->dirty_br.y = 0.0f;
}
- compositor->fb_state.cbufs[0] = dst_surface;
-
- 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_fragment_sampler_states(compositor->pipe, 1, &compositor->sampler);
- compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader);
- compositor->pipe->set_vertex_buffers(compositor->pipe, 1, &compositor->vertex_buf);
- compositor->pipe->bind_vertex_elements_state(compositor->pipe, compositor->vertex_elems_state);
- compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, compositor->fs_const_buf);
-
- draw_layers(compositor, src_surface, src_area, dst_area);
-
- assert(!compositor->dirty_bg && !compositor->dirty_layers);
- compositor->pipe->flush(compositor->pipe, PIPE_FLUSH_RENDER_CACHE, fence);
+ c->pipe->set_scissor_state(c->pipe, &scissor);
+ c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
+ c->pipe->set_viewport_state(c->pipe, &c->viewport);
+ c->pipe->bind_vs_state(c->pipe, c->vs);
+ c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf);
+ c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
+ c->pipe->set_constant_buffer(c->pipe, PIPE_SHADER_FRAGMENT, 0, c->csc_matrix);
+ c->pipe->bind_rasterizer_state(c->pipe, c->rast);
+
+ draw_layers(c);
}
-void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat)
+bool
+vl_compositor_init(struct vl_compositor *c, struct pipe_context *pipe)
{
- struct pipe_transfer *buf_transfer;
+ csc_matrix csc_matrix;
- assert(compositor);
+ c->pipe = pipe;
- memcpy
- (
- pipe_buffer_map(compositor->pipe, compositor->fs_const_buf,
- PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
- &buf_transfer),
- mat,
- sizeof(struct fragment_shader_consts)
- );
+ if (!init_pipe_state(c))
+ return false;
- pipe_buffer_unmap(compositor->pipe, compositor->fs_const_buf,
- buf_transfer);
+ if (!init_shaders(c)) {
+ cleanup_pipe_state(c);
+ return false;
+ }
+ if (!init_buffers(c)) {
+ cleanup_shaders(c);
+ cleanup_pipe_state(c);
+ return false;
+ }
+
+ vl_compositor_clear_layers(c);
+
+ vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, csc_matrix);
+ vl_compositor_set_csc_matrix(c, csc_matrix);
+
+ c->clear_color[0] = c->clear_color[1] = 0.0f;
+ c->clear_color[2] = c->clear_color[3] = 0.0f;
+ vl_compositor_reset_dirty_area(c);
+
+ return true;
}