1 /**************************************************************************
3 * Copyright 2009 Younes Manton.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 #include "vl_compositor.h"
29 #include "util/u_draw.h"
31 #include <pipe/p_context.h>
32 #include <util/u_inlines.h>
33 #include <util/u_memory.h>
34 #include <util/u_keymap.h>
35 #include <util/u_draw.h>
36 #include <util/u_sampler.h>
37 #include <tgsi/tgsi_ureg.h>
40 struct vertex_shader_consts
42 struct vertex4f dst_scale
;
43 struct vertex4f dst_trans
;
44 struct vertex4f src_scale
;
45 struct vertex4f src_trans
;
48 struct fragment_shader_consts
54 u_video_rects_equal(struct pipe_video_rect
*a
, struct pipe_video_rect
*b
)
71 create_vert_shader(struct vl_compositor
*c
)
73 struct ureg_program
*shader
;
74 struct ureg_src vpos
, vtex
;
75 struct ureg_dst o_vpos
, o_vtex
;
77 shader
= ureg_create(TGSI_PROCESSOR_VERTEX
);
81 vpos
= ureg_DECL_vs_input(shader
, 0);
82 vtex
= ureg_DECL_vs_input(shader
, 1);
83 o_vpos
= ureg_DECL_output(shader
, TGSI_SEMANTIC_POSITION
, 0);
84 o_vtex
= ureg_DECL_output(shader
, TGSI_SEMANTIC_GENERIC
, 1);
90 ureg_MOV(shader
, o_vpos
, vpos
);
91 ureg_MOV(shader
, o_vtex
, vtex
);
95 c
->vertex_shader
= ureg_create_shader_and_destroy(shader
, c
->pipe
);
96 if (!c
->vertex_shader
)
103 create_frag_shader_ycbcr_2_rgb(struct vl_compositor
*c
)
105 struct ureg_program
*shader
;
107 struct ureg_src csc
[4];
108 struct ureg_src sampler
;
109 struct ureg_dst texel
;
110 struct ureg_dst fragment
;
113 shader
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
117 tc
= ureg_DECL_fs_input(shader
, TGSI_SEMANTIC_GENERIC
, 1, TGSI_INTERPOLATE_LINEAR
);
118 for (i
= 0; i
< 4; ++i
)
119 csc
[i
] = ureg_DECL_constant(shader
, i
);
120 sampler
= ureg_DECL_sampler(shader
, 0);
121 texel
= ureg_DECL_temporary(shader
);
122 fragment
= ureg_DECL_output(shader
, TGSI_SEMANTIC_COLOR
, 0);
125 * texel = tex(tc, sampler)
126 * fragment = csc * texel
128 ureg_TEX(shader
, texel
, TGSI_TEXTURE_2D
, tc
, sampler
);
129 for (i
= 0; i
< 3; ++i
)
130 ureg_DP4(shader
, ureg_writemask(fragment
, TGSI_WRITEMASK_X
<< i
), csc
[i
], ureg_src(texel
));
131 ureg_MOV(shader
, ureg_writemask(fragment
, TGSI_WRITEMASK_W
), ureg_imm1f(shader
, 1.0f
));
133 ureg_release_temporary(shader
, texel
);
136 c
->fragment_shader
.ycbcr_2_rgb
= ureg_create_shader_and_destroy(shader
, c
->pipe
);
137 if (!c
->fragment_shader
.ycbcr_2_rgb
)
144 create_frag_shader_palette_2_rgb(struct vl_compositor
*c
)
146 struct ureg_program
*shader
;
148 struct ureg_src sampler
;
149 struct ureg_src palette
;
150 struct ureg_dst texel
;
151 struct ureg_dst fragment
;
153 shader
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
157 tc
= ureg_DECL_fs_input(shader
, TGSI_SEMANTIC_GENERIC
, 1, TGSI_INTERPOLATE_LINEAR
);
158 sampler
= ureg_DECL_sampler(shader
, 0);
159 palette
= ureg_DECL_sampler(shader
, 1);
160 fragment
= ureg_DECL_output(shader
, TGSI_SEMANTIC_COLOR
, 0);
161 texel
= ureg_DECL_temporary(shader
);
164 * fragment = tex(tc, sampler)
166 ureg_TEX(shader
, texel
, TGSI_TEXTURE_2D
, tc
, sampler
);
167 ureg_TEX(shader
, fragment
, TGSI_TEXTURE_1D
, ureg_src(texel
), palette
);
168 ureg_MOV(shader
, ureg_writemask(fragment
, TGSI_WRITEMASK_W
), ureg_src(texel
));
170 ureg_release_temporary(shader
, texel
);
173 c
->fragment_shader
.palette_2_rgb
= ureg_create_shader_and_destroy(shader
, c
->pipe
);
174 if (!c
->fragment_shader
.palette_2_rgb
)
181 create_frag_shader_rgb_2_rgb(struct vl_compositor
*c
)
183 struct ureg_program
*shader
;
185 struct ureg_src sampler
;
186 struct ureg_dst fragment
;
188 shader
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
192 tc
= ureg_DECL_fs_input(shader
, TGSI_SEMANTIC_GENERIC
, 1, TGSI_INTERPOLATE_LINEAR
);
193 sampler
= ureg_DECL_sampler(shader
, 0);
194 fragment
= ureg_DECL_output(shader
, TGSI_SEMANTIC_COLOR
, 0);
197 * fragment = tex(tc, sampler)
199 ureg_TEX(shader
, fragment
, TGSI_TEXTURE_2D
, tc
, sampler
);
202 c
->fragment_shader
.rgb_2_rgb
= ureg_create_shader_and_destroy(shader
, c
->pipe
);
203 if (!c
->fragment_shader
.rgb_2_rgb
)
210 init_pipe_state(struct vl_compositor
*c
)
212 struct pipe_sampler_state sampler
;
213 struct pipe_blend_state blend
;
217 c
->fb_state
.nr_cbufs
= 1;
218 c
->fb_state
.zsbuf
= NULL
;
220 memset(&sampler
, 0, sizeof(sampler
));
221 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
222 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
223 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
224 sampler
.min_img_filter
= PIPE_TEX_FILTER_LINEAR
;
225 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
226 sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
227 sampler
.compare_mode
= PIPE_TEX_COMPARE_NONE
;
228 sampler
.compare_func
= PIPE_FUNC_ALWAYS
;
229 sampler
.normalized_coords
= 1;
230 /*sampler.lod_bias = ;*/
231 /*sampler.min_lod = ;*/
232 /*sampler.max_lod = ;*/
233 /*sampler.border_color[i] = ;*/
234 /*sampler.max_anisotropy = ;*/
235 c
->sampler
= c
->pipe
->create_sampler_state(c
->pipe
, &sampler
);
237 memset(&blend
, 0, sizeof blend
);
238 blend
.independent_blend_enable
= 0;
239 blend
.rt
[0].blend_enable
= 1;
240 blend
.rt
[0].rgb_func
= PIPE_BLEND_ADD
;
241 blend
.rt
[0].rgb_src_factor
= PIPE_BLENDFACTOR_SRC_ALPHA
;
242 blend
.rt
[0].rgb_dst_factor
= PIPE_BLENDFACTOR_INV_SRC_ALPHA
;
243 blend
.rt
[0].alpha_func
= PIPE_BLEND_ADD
;
244 blend
.rt
[0].alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
245 blend
.rt
[0].alpha_dst_factor
= PIPE_BLENDFACTOR_ONE
;
246 blend
.logicop_enable
= 0;
247 blend
.logicop_func
= PIPE_LOGICOP_CLEAR
;
248 blend
.rt
[0].colormask
= PIPE_MASK_RGBA
;
250 c
->blend
= c
->pipe
->create_blend_state(c
->pipe
, &blend
);
255 static void cleanup_pipe_state(struct vl_compositor
*c
)
259 c
->pipe
->delete_sampler_state(c
->pipe
, c
->sampler
);
260 c
->pipe
->delete_blend_state(c
->pipe
, c
->blend
);
264 init_shaders(struct vl_compositor
*c
)
268 if (!create_vert_shader(c
)) {
269 debug_printf("Unable to create vertex shader.\n");
272 if (!create_frag_shader_ycbcr_2_rgb(c
)) {
273 debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
276 if (!create_frag_shader_palette_2_rgb(c
)) {
277 debug_printf("Unable to create Palette-to-RGB fragment shader.\n");
280 if (!create_frag_shader_rgb_2_rgb(c
)) {
281 debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
288 static void cleanup_shaders(struct vl_compositor
*c
)
292 c
->pipe
->delete_vs_state(c
->pipe
, c
->vertex_shader
);
293 c
->pipe
->delete_fs_state(c
->pipe
, c
->fragment_shader
.ycbcr_2_rgb
);
294 c
->pipe
->delete_fs_state(c
->pipe
, c
->fragment_shader
.palette_2_rgb
);
295 c
->pipe
->delete_fs_state(c
->pipe
, c
->fragment_shader
.rgb_2_rgb
);
299 init_buffers(struct vl_compositor
*c
)
301 struct fragment_shader_consts fsc
;
302 struct pipe_vertex_element vertex_elems
[2];
307 * Create our vertex buffer and vertex buffer elements
309 c
->vertex_buf
.stride
= sizeof(struct vertex4f
);
310 c
->vertex_buf
.buffer_offset
= 0;
311 /* XXX: Create with DYNAMIC or STREAM */
312 c
->vertex_buf
.buffer
= pipe_buffer_create
315 PIPE_BIND_VERTEX_BUFFER
,
317 sizeof(struct vertex4f
) * (VL_COMPOSITOR_MAX_LAYERS
+ 1) * 4
320 vertex_elems
[0].src_offset
= 0;
321 vertex_elems
[0].instance_divisor
= 0;
322 vertex_elems
[0].vertex_buffer_index
= 0;
323 vertex_elems
[0].src_format
= PIPE_FORMAT_R32G32_FLOAT
;
324 vertex_elems
[1].src_offset
= sizeof(struct vertex2f
);
325 vertex_elems
[1].instance_divisor
= 0;
326 vertex_elems
[1].vertex_buffer_index
= 0;
327 vertex_elems
[1].src_format
= PIPE_FORMAT_R32G32_FLOAT
;
328 c
->vertex_elems_state
= c
->pipe
->create_vertex_elements_state(c
->pipe
, 2, vertex_elems
);
331 * Create our fragment shader's constant buffer
332 * Const buffer contains the color conversion matrix and bias vectors
334 /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
335 c
->fs_const_buf
= pipe_buffer_create
338 PIPE_BIND_CONSTANT_BUFFER
,
340 sizeof(struct fragment_shader_consts
)
343 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY
, NULL
, true, fsc
.matrix
);
345 vl_compositor_set_csc_matrix(c
, fsc
.matrix
);
351 cleanup_buffers(struct vl_compositor
*c
)
355 c
->pipe
->delete_vertex_elements_state(c
->pipe
, c
->vertex_elems_state
);
356 pipe_resource_reference(&c
->vertex_buf
.buffer
, NULL
);
357 pipe_resource_reference(&c
->fs_const_buf
, NULL
);
360 bool vl_compositor_init(struct vl_compositor
*compositor
, struct pipe_context
*pipe
)
366 memset(compositor
, 0, sizeof(struct vl_compositor
));
368 compositor
->pipe
= pipe
;
370 if (!init_pipe_state(compositor
))
373 if (!init_shaders(compositor
)) {
374 cleanup_pipe_state(compositor
);
377 if (!init_buffers(compositor
)) {
378 cleanup_shaders(compositor
);
379 cleanup_pipe_state(compositor
);
383 compositor
->fb_state
.width
= 0;
384 compositor
->fb_state
.height
= 0;
385 for (i
= 0; i
< VL_COMPOSITOR_MAX_LAYERS
; ++i
)
386 compositor
->layers
[i
] = NULL
;
387 compositor
->dirty_layers
= 0;
392 void vl_compositor_cleanup(struct vl_compositor
*compositor
)
396 cleanup_buffers(compositor
);
397 cleanup_shaders(compositor
);
398 cleanup_pipe_state(compositor
);
401 void vl_compositor_set_layers(struct vl_compositor
*compositor
,
402 struct pipe_sampler_view
*layers
[],
403 struct pipe_sampler_view
*palettes
[],
404 struct pipe_video_rect
*src_rects
[],
405 struct pipe_video_rect
*dst_rects
[],
411 assert(num_layers
<= VL_COMPOSITOR_MAX_LAYERS
);
413 for (i
= 0; i
< num_layers
; ++i
)
415 assert((layers
[i
] && src_rects
[i
] && dst_rects
[i
]) ||
416 (!layers
[i
] && !src_rects
[i
] && !dst_rects
[i
]));
418 if (compositor
->layers
[i
] != layers
[i
] ||
419 compositor
->palettes
[i
] != palettes
[i
] ||
420 !u_video_rects_equal(&compositor
->layer_src_rects
[i
], src_rects
[i
]) ||
421 !u_video_rects_equal(&compositor
->layer_dst_rects
[i
], dst_rects
[i
]))
423 pipe_sampler_view_reference(&compositor
->layers
[i
], layers
[i
]);
424 pipe_sampler_view_reference(&compositor
->palettes
[i
], palettes
[i
]);
425 compositor
->layer_src_rects
[i
] = *src_rects
[i
];
426 compositor
->layer_dst_rects
[i
] = *dst_rects
[i
];
427 compositor
->dirty_layers
|= 1 << i
;
431 compositor
->dirty_layers
|= 1 << i
;
434 for (; i
< VL_COMPOSITOR_MAX_LAYERS
; ++i
) {
435 pipe_sampler_view_reference(&compositor
->layers
[i
], NULL
);
436 pipe_sampler_view_reference(&compositor
->palettes
[i
], NULL
);
440 static void gen_rect_verts(struct pipe_video_rect
*src_rect
,
441 struct vertex2f
*src_inv_size
,
442 struct pipe_video_rect
*dst_rect
,
443 struct vertex2f
*dst_inv_size
,
447 assert(src_inv_size
);
448 assert((dst_rect
&& dst_inv_size
) /*|| (!dst_rect && !dst_inv_size)*/);
451 vb
[0].x
= dst_rect
->x
* dst_inv_size
->x
;
452 vb
[0].y
= dst_rect
->y
* dst_inv_size
->y
;
453 vb
[0].z
= src_rect
->x
* src_inv_size
->x
;
454 vb
[0].w
= src_rect
->y
* src_inv_size
->y
;
456 vb
[1].x
= (dst_rect
->x
+ dst_rect
->w
) * dst_inv_size
->x
;
457 vb
[1].y
= dst_rect
->y
* dst_inv_size
->y
;
458 vb
[1].z
= (src_rect
->x
+ src_rect
->w
) * src_inv_size
->x
;
459 vb
[1].w
= src_rect
->y
* src_inv_size
->y
;
461 vb
[2].x
= (dst_rect
->x
+ dst_rect
->w
) * dst_inv_size
->x
;
462 vb
[2].y
= (dst_rect
->y
+ dst_rect
->h
) * dst_inv_size
->y
;
463 vb
[2].z
= (src_rect
->x
+ src_rect
->w
) * src_inv_size
->x
;
464 vb
[2].w
= (src_rect
->y
+ src_rect
->h
) * src_inv_size
->y
;
466 vb
[3].x
= dst_rect
->x
* dst_inv_size
->x
;
467 vb
[3].y
= (dst_rect
->y
+ dst_rect
->h
) * dst_inv_size
->y
;
468 vb
[3].z
= src_rect
->x
* src_inv_size
->x
;
469 vb
[3].w
= (src_rect
->y
+ src_rect
->h
) * src_inv_size
->y
;
472 static unsigned gen_data(struct vl_compositor
*c
,
473 struct pipe_sampler_view
*src_surface
,
474 struct pipe_video_rect
*src_rect
,
475 struct pipe_video_rect
*dst_rect
,
476 struct pipe_sampler_view
*textures
[VL_COMPOSITOR_MAX_LAYERS
+ 1][2],
480 struct pipe_transfer
*buf_transfer
;
481 unsigned num_rects
= 0;
490 vb
= pipe_buffer_map(c
->pipe
, c
->vertex_buf
.buffer
,
491 PIPE_TRANSFER_WRITE
| PIPE_TRANSFER_DISCARD
,
498 struct vertex2f src_inv_size
= { 1.0f
/ src_surface
->texture
->width0
, 1.0f
/ src_surface
->texture
->height0
};
499 gen_rect_verts(src_rect
, &src_inv_size
, dst_rect
, &c
->fb_inv_size
, vb
);
500 textures
[num_rects
][0] = src_surface
;
501 textures
[num_rects
][1] = NULL
;
502 /* XXX: Hack, sort of */
503 frag_shaders
[num_rects
] = c
->fragment_shader
.ycbcr_2_rgb
;
508 for (i
= 0; c
->dirty_layers
> 0; i
++) {
509 assert(i
< VL_COMPOSITOR_MAX_LAYERS
);
511 if (c
->dirty_layers
& (1 << i
)) {
512 struct vertex2f layer_inv_size
= {1.0f
/ c
->layers
[i
]->texture
->width0
, 1.0f
/ c
->layers
[i
]->texture
->height0
};
513 gen_rect_verts(&c
->layer_src_rects
[i
], &layer_inv_size
, &c
->layer_dst_rects
[i
], &layer_inv_size
, vb
);
514 textures
[num_rects
][0] = c
->layers
[i
];
515 textures
[num_rects
][1] = c
->palettes
[i
];
518 frag_shaders
[num_rects
] = c
->fragment_shader
.palette_2_rgb
;
520 frag_shaders
[num_rects
] = c
->fragment_shader
.rgb_2_rgb
;
524 c
->dirty_layers
&= ~(1 << i
);
528 pipe_buffer_unmap(c
->pipe
, buf_transfer
);
533 static void draw_layers(struct vl_compositor
*c
,
534 struct pipe_sampler_view
*src_surface
,
535 struct pipe_video_rect
*src_rect
,
536 struct pipe_video_rect
*dst_rect
)
539 struct pipe_sampler_view
*surfaces
[VL_COMPOSITOR_MAX_LAYERS
+ 1][2];
540 void *frag_shaders
[VL_COMPOSITOR_MAX_LAYERS
+ 1];
548 num_rects
= gen_data(c
, src_surface
, src_rect
, dst_rect
, surfaces
, frag_shaders
);
550 c
->pipe
->bind_blend_state(c
->pipe
, c
->blend
);
551 for (i
= 0; i
< num_rects
; ++i
) {
552 c
->pipe
->bind_fs_state(c
->pipe
, frag_shaders
[i
]);
553 c
->pipe
->set_fragment_sampler_views(c
->pipe
, surfaces
[i
][1] ? 2 : 1, &surfaces
[i
][0]);
555 util_draw_arrays(c
->pipe
, PIPE_PRIM_QUADS
, i
* 4, 4);
559 void vl_compositor_render(struct vl_compositor
*compositor
,
560 struct pipe_sampler_view
*src_surface
,
561 enum pipe_mpeg12_picture_type picture_type
,
562 struct pipe_video_rect
*src_area
,
563 struct pipe_surface
*dst_surface
,
564 struct pipe_video_rect
*dst_area
,
565 struct pipe_fence_handle
**fence
)
574 assert(picture_type
== PIPE_MPEG12_PICTURE_TYPE_FRAME
);
576 if (compositor
->fb_state
.width
!= dst_surface
->width
) {
577 compositor
->fb_inv_size
.x
= 1.0f
/ dst_surface
->width
;
578 compositor
->fb_state
.width
= dst_surface
->width
;
580 if (compositor
->fb_state
.height
!= dst_surface
->height
) {
581 compositor
->fb_inv_size
.y
= 1.0f
/ dst_surface
->height
;
582 compositor
->fb_state
.height
= dst_surface
->height
;
585 compositor
->fb_state
.cbufs
[0] = dst_surface
;
587 compositor
->viewport
.scale
[0] = compositor
->fb_state
.width
;
588 compositor
->viewport
.scale
[1] = compositor
->fb_state
.height
;
589 compositor
->viewport
.scale
[2] = 1;
590 compositor
->viewport
.scale
[3] = 1;
591 compositor
->viewport
.translate
[0] = 0;
592 compositor
->viewport
.translate
[1] = 0;
593 compositor
->viewport
.translate
[2] = 0;
594 compositor
->viewport
.translate
[3] = 0;
596 samplers
[0] = samplers
[1] = compositor
->sampler
;
598 compositor
->pipe
->set_framebuffer_state(compositor
->pipe
, &compositor
->fb_state
);
599 compositor
->pipe
->set_viewport_state(compositor
->pipe
, &compositor
->viewport
);
600 compositor
->pipe
->bind_fragment_sampler_states(compositor
->pipe
, 2, &samplers
[0]);
601 compositor
->pipe
->bind_vs_state(compositor
->pipe
, compositor
->vertex_shader
);
602 compositor
->pipe
->set_vertex_buffers(compositor
->pipe
, 1, &compositor
->vertex_buf
);
603 compositor
->pipe
->bind_vertex_elements_state(compositor
->pipe
, compositor
->vertex_elems_state
);
604 compositor
->pipe
->set_constant_buffer(compositor
->pipe
, PIPE_SHADER_FRAGMENT
, 0, compositor
->fs_const_buf
);
606 draw_layers(compositor
, src_surface
, src_area
, dst_area
);
608 assert(!compositor
->dirty_layers
);
609 compositor
->pipe
->flush(compositor
->pipe
, fence
);
612 void vl_compositor_set_csc_matrix(struct vl_compositor
*compositor
, const float *mat
)
614 struct pipe_transfer
*buf_transfer
;
620 pipe_buffer_map(compositor
->pipe
, compositor
->fs_const_buf
,
621 PIPE_TRANSFER_WRITE
| PIPE_TRANSFER_DISCARD
,
624 sizeof(struct fragment_shader_consts
)
627 pipe_buffer_unmap(compositor
->pipe
, buf_transfer
);