g3dvl: enable deinterlacing
[mesa/nouveau-pmpeg.git] / src / gallium / auxiliary / vl / vl_compositor.c
blob4f4c26961b26e35943b4f6136b0e2bf6179e5ff1
1 /**************************************************************************
3 * Copyright 2009 Younes Manton.
4 * All Rights Reserved.
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
16 * of the Software.
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 <assert.h>
30 #include "pipe/p_compiler.h"
31 #include "pipe/p_context.h"
33 #include "util/u_memory.h"
34 #include "util/u_draw.h"
35 #include "util/u_surface.h"
36 #include "util/u_sampler.h"
38 #include "tgsi/tgsi_ureg.h"
40 #include "vl_csc.h"
41 #include "vl_types.h"
42 #include "vl_compositor.h"
44 typedef float csc_matrix[16];
46 /* Set to 1 to run a contour shader */
47 #define DEBUG_CONTOUR 0
49 static void *
50 create_vert_shader(struct vl_compositor *c)
52 struct ureg_program *shader;
53 struct ureg_src vpos, vtex;
54 struct ureg_dst o_vpos, o_vtex;
56 shader = ureg_create(TGSI_PROCESSOR_VERTEX);
57 if (!shader)
58 return false;
60 vpos = ureg_DECL_vs_input(shader, 0);
61 vtex = ureg_DECL_vs_input(shader, 1);
62 o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0);
63 o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, 1);
66 * o_vpos = vpos
67 * o_vtex = vtex
69 ureg_MOV(shader, o_vpos, vpos);
70 ureg_MOV(shader, o_vtex, vtex);
72 ureg_END(shader);
74 return ureg_create_shader_and_destroy(shader, c->pipe);
77 static void *
78 create_frag_shader_video_buffer(struct vl_compositor *c, unsigned planes)
80 struct ureg_program *shader;
81 struct ureg_src tc;
82 struct ureg_src csc[3];
83 struct ureg_src sampler[3];
84 struct ureg_dst texel;
85 struct ureg_dst fragment;
86 unsigned i;
88 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
89 if (!shader)
90 return false;
92 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
93 for (i = 0; i < 3; ++i) {
94 csc[i] = ureg_DECL_constant(shader, i);
95 if (i < planes)
96 sampler[i] = ureg_DECL_sampler(shader, i);
98 texel = ureg_DECL_temporary(shader);
99 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
102 * texel.xyz = tex(tc, sampler[i])
103 * fragment = csc * texel
105 if (planes == 2) {
106 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, tc, sampler[0]);
107 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_YZ), TGSI_TEXTURE_2D, tc, sampler[1]);
108 } else {
109 for (i = 0; i < 3; ++i)
110 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, tc, sampler[i]);
113 ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
115 for (i = 0; i < 3; ++i)
116 ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
118 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
120 ureg_release_temporary(shader, texel);
121 ureg_END(shader);
123 return ureg_create_shader_and_destroy(shader, c->pipe);
126 static struct ureg_dst
127 calc_line(struct ureg_program *shader, unsigned nearest)
129 struct ureg_dst tmp;
130 struct ureg_src pos;
132 tmp = ureg_DECL_temporary(shader);
134 pos = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_POSITION, 0, TGSI_INTERPOLATE_LINEAR);
137 * tmp.y = fraction(pos.y * .5) >= 0.5 ? 1 : 0
138 * however, for linear interpolation (chroma deinterlace) 2 pixels are required..
140 if (nearest)
141 ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.5f));
142 else
143 ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.25f));
144 ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp));
145 ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp), ureg_imm1f(shader, 0.5f));
147 return tmp;
150 /* Deinterlace or weave NV12 or YV12 to a temporary video buffer
153 static void *
154 create_frag_shader_weave(struct vl_compositor *c, unsigned luma, unsigned interlaced, unsigned comps)
156 struct ureg_program *shader;
157 struct ureg_src tc, sampler[4];
158 struct ureg_dst field, fragment, swizcolor;
159 unsigned label, writemask, nearest;
160 if (luma)
161 writemask = TGSI_WRITEMASK_X;
162 else if (comps == 2)
163 writemask = TGSI_WRITEMASK_YZ;
164 else
165 writemask = TGSI_WRITEMASK_Y;
167 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
168 if (!shader)
169 return false;
171 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
172 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
173 sampler[0] = ureg_DECL_sampler(shader, 0);
174 sampler[1] = ureg_DECL_sampler(shader, 1);
175 if (!luma && comps == 1) {
176 sampler[2] = ureg_DECL_sampler(shader, 2);
177 sampler[3] = ureg_DECL_sampler(shader, 3);
180 nearest = luma || c->chroma == PIPE_VIDEO_CHROMA_FORMAT_444 || !interlaced;
181 field = calc_line(shader, nearest);
182 swizcolor = ureg_DECL_temporary(shader);
184 /* field.y = fraction(coord/2) >= .5 (from vl_mc.c)
186 * if (field.y)
187 * swiz = sampler[bottom];
188 * else
189 * swiz = sampler[top];
191 * if (LUMA)
192 * color.x = swiz;
193 * else
194 * color.xy = swiz.yz;
197 ureg_IF(shader, ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y), &label);
199 struct ureg_dst adjtc = ureg_DECL_temporary(shader);
200 if (!nearest) {
201 /* -2.0 / c->video_h (1 pixel up, chroma = half height, full height wouldn't need this)
202 * + .5 / c->video_h (.25 pixel down, since interlaced first pixel = .75 first
204 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_X), tc);
205 ureg_SUB(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_Y), ureg_scalar(tc, TGSI_SWIZZLE_Y),
206 ureg_imm1f(shader, 1.5f / c->video_h));
207 } else
208 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_XY), tc);
209 ureg_TEX(shader, ureg_writemask(swizcolor, writemask), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[1]);
210 if (!luma && comps == 1)
211 ureg_TEX(shader, ureg_writemask(swizcolor, TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[3]);
212 ureg_release_temporary(shader, adjtc);
213 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
215 ureg_ELSE(shader, &label);
217 struct ureg_dst adjtc = ureg_DECL_temporary(shader);
218 if (!nearest) {
219 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_X), tc);
220 ureg_ADD(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_Y), ureg_scalar(tc, TGSI_SWIZZLE_Y),
221 ureg_imm1f(shader, .5f / c->video_h));
222 } else
223 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_XY), tc);
224 ureg_TEX(shader, ureg_writemask(swizcolor, writemask), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[0]);
225 if (!luma && comps == 1)
226 ureg_TEX(shader, ureg_writemask(swizcolor, TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[2]);
227 ureg_release_temporary(shader, adjtc);
228 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
230 ureg_ENDIF(shader);
232 if (luma)
233 ureg_MOV(shader, ureg_writemask(fragment, writemask), ureg_src(swizcolor));
234 else
235 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XY),
236 ureg_swizzle(ureg_src(swizcolor), TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z));
238 ureg_release_temporary(shader, swizcolor);
239 ureg_release_temporary(shader, field);
240 ureg_END(shader);
241 return ureg_create_shader_and_destroy(shader, c->pipe);
244 static void *
245 create_frag_shader_sobel(struct vl_compositor *c)
247 struct ureg_program *shader;
248 struct ureg_src tc, sampler;
249 struct ureg_dst fragment, color[9], tctmp;
250 float v[3] = { -1.f, 0.f, 1.f };
251 int i;
253 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
254 if (!shader)
255 return NULL;
257 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
258 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
259 sampler = ureg_DECL_sampler(shader, 0);
261 tctmp = ureg_DECL_temporary(shader);
262 for (i = 0; i < Elements(color); ++i)
263 color[i] = ureg_DECL_temporary(shader);
265 for (i = 0; i < 9; ++i) {
266 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_XY), tc, ureg_imm2f(shader, v[i%3]/(float)c->video_w, v[i/3]/(float)c->video_h));
267 ureg_TEX(shader, ureg_writemask(color[i], TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, ureg_src(tctmp), sampler);
270 /* tmp.x = P1 + P3 + 2 * P2 */
271 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), ureg_src(color[0]), ureg_src(color[2]));
272 ureg_MAD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), ureg_src(color[1]), ureg_imm1f(shader, 2.f), ureg_src(tctmp));
274 /* tmp.y = P7 + P9 + 2 * P8 */
275 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_Y),
276 ureg_scalar(ureg_src(color[6]), TGSI_SWIZZLE_X),
277 ureg_scalar(ureg_src(color[8]), TGSI_SWIZZLE_X));
278 ureg_MAD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_Y),
279 ureg_scalar(ureg_src(color[7]), TGSI_SWIZZLE_X),
280 ureg_imm1f(shader, 2.f), ureg_src(tctmp));
282 /* tmp.z = | tmp.x - tmp.y | */
283 ureg_SUB(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_Z),
284 ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_X),
285 ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_Y));
286 ureg_ABS(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_Z), ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_Z));
288 /* tmp.x = P3 + P9 + 2 * P6 */
289 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), ureg_src(color[2]), ureg_src(color[8]));
290 ureg_MAD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), ureg_src(color[5]), ureg_imm1f(shader, 2.f), ureg_src(tctmp));
292 /* tmp.y = P1 + P7 + 2 * P4 */
293 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_Y),
294 ureg_scalar(ureg_src(color[0]), TGSI_SWIZZLE_X),
295 ureg_scalar(ureg_src(color[6]), TGSI_SWIZZLE_X));
296 ureg_MAD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_Y),
297 ureg_scalar(ureg_src(color[3]), TGSI_SWIZZLE_X),
298 ureg_imm1f(shader, 2.f), ureg_src(tctmp));
300 /* tmp.x = | tmp.x - tmp.y | */
301 ureg_SUB(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X),
302 ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_X),
303 ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_Y));
304 ureg_ABS(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), ureg_src(tctmp));
306 /* tmp.x += tmp.z */
307 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X),
308 ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_X),
309 ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_Z));
311 /* color = color + tmp.x >= .5f */
312 ureg_SGE(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), ureg_src(tctmp), ureg_imm1f(shader, 0.4f));
313 ureg_MAD(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X), ureg_src(color[4]), ureg_imm1f(shader, .25f), ureg_src(tctmp));
315 for (i = 0; i < Elements(color); ++i)
316 ureg_release_temporary(shader, color[i]);
318 ureg_release_temporary(shader, tctmp);
319 ureg_END(shader);
320 return ureg_create_shader_and_destroy(shader, c->pipe);
323 static void *
324 create_frag_shader_palette(struct vl_compositor *c, bool include_cc)
326 struct ureg_program *shader;
327 struct ureg_src csc[3];
328 struct ureg_src tc;
329 struct ureg_src sampler;
330 struct ureg_src palette;
331 struct ureg_dst texel;
332 struct ureg_dst fragment;
333 unsigned i;
335 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
336 if (!shader)
337 return false;
339 for (i = 0; include_cc && i < 3; ++i)
340 csc[i] = ureg_DECL_constant(shader, i);
342 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
343 sampler = ureg_DECL_sampler(shader, 0);
344 palette = ureg_DECL_sampler(shader, 1);
346 texel = ureg_DECL_temporary(shader);
347 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
350 * texel = tex(tc, sampler)
351 * fragment.xyz = tex(texel, palette) * csc
352 * fragment.a = texel.a
354 ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
355 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(texel));
357 if (include_cc) {
358 ureg_TEX(shader, texel, TGSI_TEXTURE_1D, ureg_src(texel), palette);
359 for (i = 0; i < 3; ++i)
360 ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
361 } else {
362 ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ),
363 TGSI_TEXTURE_1D, ureg_src(texel), palette);
366 ureg_release_temporary(shader, texel);
367 ureg_END(shader);
369 return ureg_create_shader_and_destroy(shader, c->pipe);
372 static void *
373 create_frag_shader_rgba(struct vl_compositor *c)
375 struct ureg_program *shader;
376 struct ureg_src tc;
377 struct ureg_src sampler;
378 struct ureg_dst fragment;
380 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
381 if (!shader)
382 return false;
384 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
385 sampler = ureg_DECL_sampler(shader, 0);
386 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
389 * fragment = tex(tc, sampler)
391 ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler);
392 ureg_END(shader);
394 return ureg_create_shader_and_destroy(shader, c->pipe);
397 static bool
398 init_shaders(struct vl_compositor *c)
400 assert(c);
402 c->vs = create_vert_shader(c);
403 if (!c->vs) {
404 debug_printf("Unable to create vertex shader.\n");
405 return false;
408 c->fs_palette.yuv = create_frag_shader_palette(c, true);
409 if (!c->fs_palette.yuv) {
410 debug_printf("Unable to create YUV-Palette-to-RGB fragment shader.\n");
411 return false;
414 c->fs_palette.rgb = create_frag_shader_palette(c, false);
415 if (!c->fs_palette.rgb) {
416 debug_printf("Unable to create RGB-Palette-to-RGB fragment shader.\n");
417 return false;
420 c->fs_rgba = create_frag_shader_rgba(c);
421 if (!c->fs_rgba) {
422 debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
423 return false;
426 return true;
429 static void cleanup_shaders(struct vl_compositor *c)
431 assert(c);
433 c->pipe->delete_vs_state(c->pipe, c->vs);
434 c->pipe->delete_fs_state(c->pipe, c->fs_palette.yuv);
435 c->pipe->delete_fs_state(c->pipe, c->fs_palette.rgb);
436 c->pipe->delete_fs_state(c->pipe, c->fs_rgba);
439 static bool
440 init_pipe_state(struct vl_compositor *c)
442 struct pipe_rasterizer_state rast;
443 struct pipe_sampler_state sampler;
444 struct pipe_blend_state blend;
445 struct pipe_depth_stencil_alpha_state dsa;
446 unsigned i;
448 assert(c);
450 c->fb_state.nr_cbufs = 1;
451 c->fb_state.zsbuf = NULL;
453 c->viewport.scale[2] = 1;
454 c->viewport.scale[3] = 1;
455 c->viewport.translate[2] = 0;
456 c->viewport.translate[3] = 0;
458 memset(&sampler, 0, sizeof(sampler));
459 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
460 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
461 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
462 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
463 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
464 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
465 sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
466 sampler.compare_func = PIPE_FUNC_ALWAYS;
467 sampler.normalized_coords = 1;
469 c->sampler_linear = c->pipe->create_sampler_state(c->pipe, &sampler);
471 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
472 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
473 c->sampler_nearest = c->pipe->create_sampler_state(c->pipe, &sampler);
475 memset(&blend, 0, sizeof blend);
476 blend.independent_blend_enable = 0;
477 blend.rt[0].blend_enable = 0;
478 blend.logicop_enable = 0;
479 blend.logicop_func = PIPE_LOGICOP_CLEAR;
480 blend.rt[0].colormask = PIPE_MASK_RGBA;
481 blend.dither = 0;
482 c->blend_clear = c->pipe->create_blend_state(c->pipe, &blend);
484 blend.rt[0].blend_enable = 1;
485 blend.rt[0].rgb_func = PIPE_BLEND_ADD;
486 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
487 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
488 blend.rt[0].alpha_func = PIPE_BLEND_ADD;
489 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
490 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
491 c->blend_add = c->pipe->create_blend_state(c->pipe, &blend);
493 memset(&rast, 0, sizeof rast);
494 rast.flatshade = 1;
495 rast.front_ccw = 1;
496 rast.cull_face = PIPE_FACE_NONE;
497 rast.fill_back = PIPE_POLYGON_MODE_FILL;
498 rast.fill_front = PIPE_POLYGON_MODE_FILL;
499 rast.scissor = 1;
500 rast.line_width = 1;
501 rast.point_size_per_vertex = 1;
502 rast.offset_units = 1;
503 rast.offset_scale = 1;
504 rast.gl_rasterization_rules = 1;
506 c->rast = c->pipe->create_rasterizer_state(c->pipe, &rast);
508 memset(&dsa, 0, sizeof dsa);
509 dsa.depth.enabled = 0;
510 dsa.depth.writemask = 0;
511 dsa.depth.func = PIPE_FUNC_ALWAYS;
512 for (i = 0; i < 2; ++i) {
513 dsa.stencil[i].enabled = 0;
514 dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
515 dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
516 dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
517 dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
518 dsa.stencil[i].valuemask = 0;
519 dsa.stencil[i].writemask = 0;
521 dsa.alpha.enabled = 0;
522 dsa.alpha.func = PIPE_FUNC_ALWAYS;
523 dsa.alpha.ref_value = 0;
524 c->dsa = c->pipe->create_depth_stencil_alpha_state(c->pipe, &dsa);
525 c->pipe->bind_depth_stencil_alpha_state(c->pipe, c->dsa);
527 return true;
530 static void cleanup_pipe_state(struct vl_compositor *c)
532 assert(c);
534 /* Asserted in softpipe_delete_fs_state() for some reason */
535 c->pipe->bind_vs_state(c->pipe, NULL);
536 c->pipe->bind_fs_state(c->pipe, NULL);
538 c->pipe->delete_depth_stencil_alpha_state(c->pipe, c->dsa);
539 c->pipe->delete_sampler_state(c->pipe, c->sampler_linear);
540 c->pipe->delete_sampler_state(c->pipe, c->sampler_nearest);
541 c->pipe->delete_blend_state(c->pipe, c->blend_clear);
542 c->pipe->delete_blend_state(c->pipe, c->blend_add);
543 c->pipe->delete_rasterizer_state(c->pipe, c->rast);
546 static bool
547 create_vertex_buffer(struct vl_compositor *c)
549 assert(c);
551 pipe_resource_reference(&c->vertex_buf.buffer, NULL);
552 c->vertex_buf.buffer = pipe_buffer_create
554 c->pipe->screen,
555 PIPE_BIND_VERTEX_BUFFER,
556 PIPE_USAGE_STREAM,
557 sizeof(struct vertex4f) * VL_COMPOSITOR_MAX_LAYERS * 4
560 return c->vertex_buf.buffer != NULL;
563 static bool
564 init_buffers(struct vl_compositor *c)
566 struct pipe_vertex_element vertex_elems[2];
568 assert(c);
571 * Create our vertex buffer and vertex buffer elements
573 c->vertex_buf.stride = sizeof(struct vertex4f);
574 c->vertex_buf.buffer_offset = 0;
575 create_vertex_buffer(c);
577 vertex_elems[0].src_offset = 0;
578 vertex_elems[0].instance_divisor = 0;
579 vertex_elems[0].vertex_buffer_index = 0;
580 vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
581 vertex_elems[1].src_offset = sizeof(struct vertex2f);
582 vertex_elems[1].instance_divisor = 0;
583 vertex_elems[1].vertex_buffer_index = 0;
584 vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
585 c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 2, vertex_elems);
588 * Create our fragment shader's constant buffer
589 * Const buffer contains the color conversion matrix and bias vectors
591 /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
592 c->csc_matrix = pipe_buffer_create
594 c->pipe->screen,
595 PIPE_BIND_CONSTANT_BUFFER,
596 PIPE_USAGE_STATIC,
597 sizeof(csc_matrix)
600 return true;
603 static void
604 cleanup_buffers(struct vl_compositor *c)
606 assert(c);
608 c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
609 pipe_resource_reference(&c->vertex_buf.buffer, NULL);
610 pipe_resource_reference(&c->csc_matrix, NULL);
613 static INLINE struct pipe_video_rect
614 default_rect(struct vl_compositor_layer *layer)
616 struct pipe_resource *res = layer->sampler_views[0]->texture;
617 struct pipe_video_rect rect = { 0, 0, res->width0, res->height0 };
618 return rect;
621 static INLINE struct vertex2f
622 calc_topleft(struct vertex2f size, struct pipe_video_rect rect)
624 struct vertex2f res = { rect.x / size.x, rect.y / size.y };
625 return res;
628 static INLINE struct vertex2f
629 calc_bottomright(struct vertex2f size, struct pipe_video_rect rect)
631 struct vertex2f res = { (rect.x + rect.w) / size.x, (rect.y + rect.h) / size.y };
632 return res;
635 static INLINE void
636 calc_src_and_dst(struct vl_compositor_layer *layer, unsigned width, unsigned height,
637 struct pipe_video_rect src, struct pipe_video_rect *dst)
639 struct vertex2f size_in = { width, height };
640 struct vertex2f size_out = { 1.f, 1.f };
642 layer->src.tl = calc_topleft(size_in, src);
643 layer->src.br = calc_bottomright(size_in, src);
644 if (dst) {
645 layer->dst.tl = calc_topleft(size_out, *dst);
646 layer->dst.br = calc_bottomright(size_out, *dst);
647 layer->custom_dest_rect = 1;
648 } else {
649 layer->dst.tl.x = layer->dst.tl.y = 0.f;
650 layer->dst.br.x = layer->dst.br.y = 1.f;
651 layer->custom_dest_rect = 0;
655 static void
656 gen_rect_verts(struct vertex4f *vb, struct vl_compositor_layer *layer, float w, float h)
658 assert(vb && layer);
660 vb[0].x = layer->dst.tl.x / w;
661 vb[0].y = layer->dst.tl.y / h;
662 vb[0].z = layer->src.tl.x;
663 vb[0].w = layer->src.tl.y;
665 vb[1].x = layer->dst.br.x / w;
666 vb[1].y = layer->dst.tl.y / h;
667 vb[1].z = layer->src.br.x;
668 vb[1].w = layer->src.tl.y;
670 vb[2].x = layer->dst.br.x / w;
671 vb[2].y = layer->dst.br.y / h;
672 vb[2].z = layer->src.br.x;
673 vb[2].w = layer->src.br.y;
675 vb[3].x = layer->dst.tl.x / w;
676 vb[3].y = layer->dst.br.y / h;
677 vb[3].z = layer->src.tl.x;
678 vb[3].w = layer->src.br.y;
681 static void
682 gen_vertex_data(struct vl_compositor *c, float w, float h)
684 struct vertex4f *vb;
685 struct pipe_transfer *buf_transfer;
686 unsigned i;
688 assert(c);
690 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
691 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_DONTBLOCK,
692 &buf_transfer);
694 if (!vb) {
695 // If buffer is still locked from last draw create a new one
696 create_vertex_buffer(c);
697 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
698 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
699 &buf_transfer);
702 for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; i++) {
703 if (c->used_layers & (1 << i)) {
704 struct vl_compositor_layer *layer = &c->layers[i];
705 if (layer->custom_dest_rect)
706 gen_rect_verts(vb, layer, w, h);
707 else
708 gen_rect_verts(vb, layer, 1.f, 1.f);
709 vb += 4;
711 if (layer->clearing &&
712 (!layer->custom_dest_rect ||
713 (c->dirty_tl.x >= layer->dst.tl.x/w &&
714 c->dirty_tl.y >= layer->dst.tl.y/h &&
715 c->dirty_br.x <= layer->dst.br.x/w &&
716 c->dirty_br.y <= layer->dst.br.y/h))) {
717 // We clear the dirty area anyway, no need for clear_render_target
718 c->dirty_tl.x = c->dirty_tl.y = 1.0f;
719 c->dirty_br.x = c->dirty_br.y = 0.0f;
724 pipe_buffer_unmap(c->pipe, buf_transfer);
727 static void
728 draw_layers(struct vl_compositor *c, float w, float h)
730 unsigned vb_index, i;
732 assert(c);
734 for (i = 0, vb_index = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
735 if (c->used_layers & (1 << i)) {
736 struct vl_compositor_layer *layer = &c->layers[i];
737 struct pipe_sampler_view **samplers = &layer->sampler_views[0];
738 unsigned num_sampler_views = !samplers[1] ? 1 : !samplers[2] ? 2 : 3;
740 c->pipe->bind_blend_state(c->pipe, layer->blend);
741 c->pipe->bind_fs_state(c->pipe, layer->fs);
742 c->pipe->bind_fragment_sampler_states(c->pipe, num_sampler_views, layer->samplers);
743 c->pipe->set_fragment_sampler_views(c->pipe, num_sampler_views, samplers);
744 util_draw_arrays(c->pipe, PIPE_PRIM_QUADS, vb_index * 4, 4);
745 vb_index++;
747 // Remember the currently drawn area as dirty for the next draw command
748 if (layer->custom_dest_rect) {
749 c->dirty_tl.x = MIN2(layer->dst.tl.x/w, c->dirty_tl.x);
750 c->dirty_tl.y = MIN2(layer->dst.tl.y/h, c->dirty_tl.y);
751 c->dirty_br.x = MAX2(layer->dst.br.x/w, c->dirty_br.x);
752 c->dirty_br.y = MAX2(layer->dst.br.y/h, c->dirty_br.y);
753 } else {
754 c->dirty_tl.x = 0.f;
755 c->dirty_tl.y = 0.f;
756 c->dirty_br.x = 1.f;
757 c->dirty_br.y = 1.f;
763 void
764 vl_compositor_reset_dirty_area(struct vl_compositor *c)
766 assert(c);
768 c->dirty_tl.x = c->dirty_tl.y = 0.0f;
769 c->dirty_br.x = c->dirty_br.y = 1.0f;
772 void
773 vl_compositor_set_clear_color(struct vl_compositor *c, union pipe_color_union *color)
775 assert(c);
777 c->clear_color = *color;
780 void
781 vl_compositor_get_clear_color(struct vl_compositor *c, union pipe_color_union *color)
783 assert(c);
784 assert(color);
786 *color = c->clear_color;
789 void
790 vl_compositor_clear_layers(struct vl_compositor *c)
792 unsigned i, j;
794 assert(c);
796 c->used_layers = 0;
797 for ( i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
798 c->layers[i].clearing = i ? false : true;
799 c->layers[i].blend = i ? c->blend_add : c->blend_clear;
800 c->layers[i].fs = NULL;
801 for ( j = 0; j < 3; j++)
802 pipe_sampler_view_reference(&c->layers[i].sampler_views[j], NULL);
806 static void
807 cleanup_video(struct vl_compositor *c)
809 unsigned i;
810 for (i = 0; i < Elements(c->video_res); ++i) {
811 pipe_sampler_view_reference(&c->video_sv[i], NULL);
812 pipe_surface_reference(&c->video_surf[i], NULL);
813 pipe_resource_reference(&c->video_res[i], NULL);
815 for (i = 0; i < Elements(c->fs_weave); ++i) {
816 if (!c->fs_weave[i])
817 continue;
818 c->pipe->delete_fs_state(c->pipe, c->fs_weave[i]);
819 c->fs_weave[i] = NULL;
821 if (c->fs_video_buffer2)
822 c->pipe->delete_fs_state(c->pipe, c->fs_video_buffer2);
823 if (c->fs_video_buffer3)
824 c->pipe->delete_fs_state(c->pipe, c->fs_video_buffer3);
825 c->fs_video_buffer2 = c->fs_video_buffer3 = NULL;
828 void
829 vl_compositor_cleanup(struct vl_compositor *c)
831 assert(c);
833 vl_compositor_clear_layers(c);
834 cleanup_buffers(c);
835 cleanup_shaders(c);
836 cleanup_pipe_state(c);
837 cleanup_video(c);
840 void
841 vl_compositor_set_csc_matrix(struct vl_compositor *c, const float matrix[16])
843 struct pipe_transfer *buf_transfer;
845 assert(c);
847 memcpy
849 pipe_buffer_map(c->pipe, c->csc_matrix,
850 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
851 &buf_transfer),
852 matrix,
853 sizeof(csc_matrix)
856 pipe_buffer_unmap(c->pipe, buf_transfer);
859 void
860 vl_compositor_set_layer_blend(struct vl_compositor *c,
861 unsigned layer, void *blend,
862 bool is_clearing)
864 assert(c && blend);
866 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
868 c->layers[layer].clearing = is_clearing;
869 c->layers[layer].blend = blend;
873 static void gen_vertex_data_video(struct vl_compositor *c) {
874 struct vertex4f *vb;
875 struct pipe_transfer *buf_transfer;
876 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
877 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_DONTBLOCK,
878 &buf_transfer);
880 if (!vb) {
881 // If buffer is still locked from last draw create a new one
882 create_vertex_buffer(c);
883 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
884 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
885 &buf_transfer);
887 vb[0].x = 0.f;
888 vb[0].y = 0.f;
889 vb[0].z = 0.f;
890 vb[0].w = 0.f;
892 vb[1].x = 0.f;
893 vb[1].y = 65535.f;
894 vb[1].z = 0.f;
895 vb[1].w = 65535.f;
897 vb[2].x = 65535.f;
898 vb[2].y = 0.f;
899 vb[2].z = 65535.f;
900 vb[2].w = 0.f;
901 pipe_buffer_unmap(c->pipe, buf_transfer);
904 static void
905 vl_compositor_render_sobel(struct vl_compositor *c)
907 struct pipe_scissor_state scissor;
908 struct pipe_sampler_view *sv = c->video_sv[0];
909 struct pipe_surface *dst_surface;
910 void *fs;
912 assert(c);
914 gen_vertex_data_video(c);
916 dst_surface = c->video_surf[3];
917 fs = c->fs_weave[5];
919 c->fb_state.width = dst_surface->width;
920 c->fb_state.height = dst_surface->height;
921 c->fb_state.cbufs[0] = dst_surface;
923 c->viewport.scale[0] = sv->texture->width0;
924 c->viewport.scale[1] = sv->texture->height0;
925 c->viewport.translate[0] = 0;
926 c->viewport.translate[1] = 0;
928 scissor.minx = 0;
929 scissor.miny = 0;
930 scissor.maxx = dst_surface->width;
931 scissor.maxy = dst_surface->height;
933 c->pipe->set_scissor_state(c->pipe, &scissor);
934 c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
935 c->pipe->set_viewport_state(c->pipe, &c->viewport);
936 c->pipe->bind_vs_state(c->pipe, c->vs);
937 c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf);
938 c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
939 c->pipe->bind_rasterizer_state(c->pipe, c->rast);
941 c->pipe->bind_blend_state(c->pipe, c->blend_clear);
942 c->pipe->bind_fs_state(c->pipe, fs);
943 c->pipe->bind_fragment_sampler_states(c->pipe, 1, &c->sampler_nearest);
944 c->pipe->set_fragment_sampler_views(c->pipe, 1, &sv);
945 util_draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, 0, 3);
948 static void
949 vl_compositor_render_video(struct vl_compositor *c,
950 struct pipe_sampler_view **sv,
951 unsigned interlaced)
953 struct pipe_scissor_state scissor;
954 void *samplers[4];
955 unsigned i;
956 for (i = 0; i < 4; ++i) {
957 if (!interlaced || i < 2 || c->chroma == PIPE_VIDEO_CHROMA_FORMAT_444)
958 samplers[i] = c->sampler_nearest;
959 else
960 samplers[i] = c->sampler_linear;
962 assert(c);
963 gen_vertex_data_video(c);
964 for (i = 0; i < 2; ++i) {
965 struct pipe_surface *dst_surface;
966 unsigned num_sampler_views;
967 void *fs;
968 if (!i) {
969 num_sampler_views = 2;
970 dst_surface = c->video_surf[0];
971 fs = c->fs_weave[0];
972 } else {
973 num_sampler_views = 2 + 2 * !!sv[2];
974 if (interlaced) {
975 dst_surface = c->video_surf[1];
976 fs = c->fs_weave[1 + !!sv[2]];
977 } else {
978 dst_surface = c->video_surf[2];
979 fs = c->fs_weave[3 + !!sv[2]];
983 assert(dst_surface);
984 c->fb_state.width = dst_surface->width;
985 c->fb_state.height = dst_surface->height;
986 c->fb_state.cbufs[0] = dst_surface;
988 c->viewport.scale[0] = sv[0]->texture->width0;
989 c->viewport.scale[1] = sv[0]->texture->height0 * 2;
990 if (i && c->chroma != PIPE_VIDEO_CHROMA_FORMAT_444 && interlaced)
991 c->viewport.scale[1] *= 2;
992 c->viewport.translate[0] = 0;
993 c->viewport.translate[1] = 0;
995 scissor.minx = 0;
996 scissor.miny = 0;
997 scissor.maxx = dst_surface->width;
998 scissor.maxy = dst_surface->height;
1000 c->pipe->set_scissor_state(c->pipe, &scissor);
1001 c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
1002 c->pipe->set_viewport_state(c->pipe, &c->viewport);
1003 c->pipe->bind_vs_state(c->pipe, c->vs);
1004 c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf);
1005 c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
1006 c->pipe->bind_rasterizer_state(c->pipe, c->rast);
1008 c->pipe->bind_blend_state(c->pipe, c->blend_clear);
1009 c->pipe->bind_fs_state(c->pipe, fs);
1010 c->pipe->bind_fragment_sampler_states(c->pipe, num_sampler_views, samplers);
1011 c->pipe->set_fragment_sampler_views(c->pipe, num_sampler_views, sv);
1012 sv += num_sampler_views;
1013 util_draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, 0, 3);
1017 void
1018 vl_compositor_set_buffer_layer(struct vl_compositor *c, unsigned layer,
1019 enum pipe_video_picture_structure field,
1020 struct pipe_video_buffer *buffer,
1021 struct pipe_video_rect *src_rect,
1022 struct pipe_video_rect *dst_rect,
1023 unsigned past_count,
1024 struct pipe_video_buffer **past,
1025 unsigned future_count,
1026 struct pipe_video_buffer **future)
1028 struct pipe_sampler_view **sampler_views, *sv[3];
1029 struct pipe_video_rect rect;
1030 unsigned i, half_h = 0;
1032 assert(c && buffer);
1033 assert(c->video_w <= buffer->width && c->video_h <= buffer->height);
1034 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
1036 if (field == PIPE_VIDEO_PICTURE_STRUCTURE_FRAME) {
1037 sampler_views = buffer->get_sampler_view_planes(buffer, 0);
1038 if (!sampler_views) {
1039 sampler_views = buffer->get_sampler_view_planes(buffer, 1);
1040 vl_compositor_render_video(c, sampler_views, 0);
1041 sv[0] = c->video_sv[0];
1042 if (DEBUG_CONTOUR) {
1043 sv[0] = c->video_sv[3];
1044 vl_compositor_render_sobel(c);
1046 sv[1] = c->video_sv[2];
1047 sv[2] = NULL;
1048 sampler_views = sv;
1050 } else {
1051 struct pipe_sampler_view **sv_cur, **sv_prev = NULL, *sv_weave[6];
1052 int top = field == PIPE_VIDEO_PICTURE_STRUCTURE_FIELD_TOP;
1053 sv_cur = buffer->get_sampler_view_planes(buffer, 1);
1054 if (past_count && past[0])
1055 sv_prev = buffer->get_sampler_view_planes(past[0], 1);
1056 if (sv_prev) {
1057 for (i = 0; i < 6; i += 2) {
1058 if (top) {
1059 sv_weave[i] = sv_cur[i];
1060 sv_weave[i+1] = sv_prev[i+1];
1061 } else {
1062 sv_weave[i] = sv_prev[i];
1063 sv_weave[i+1] = sv_cur[i+1];
1066 vl_compositor_render_video(c, sv_weave, 1);
1067 sv[0] = c->video_sv[0];
1068 sv[1] = c->video_sv[1];
1069 sv[2] = NULL;
1070 } else {
1071 for (i = 0; i < 3; ++i)
1072 sv[i] = sv_cur[2*i+!top];
1073 half_h = 1;
1075 sampler_views = sv;
1078 c->used_layers |= 1 << layer;
1079 if (!src_rect) {
1080 src_rect = &rect;
1081 rect.x = rect.y = 0;
1082 rect.w = c->video_w;
1083 rect.h = c->video_h;
1085 for (i = 0; i < 3; ++i) {
1086 c->layers[layer].samplers[i] = c->sampler_linear;
1087 pipe_sampler_view_reference(&c->layers[layer].sampler_views[i], sampler_views[i]);
1089 if (sampler_views[2])
1090 c->layers[layer].fs = c->fs_video_buffer3;
1091 else
1092 c->layers[layer].fs = c->fs_video_buffer2;
1093 assert(sampler_views[1]);
1095 calc_src_and_dst(&c->layers[layer],
1096 sampler_views[0]->texture->width0,
1097 sampler_views[0]->texture->height0 << half_h,
1098 *src_rect, dst_rect);
1101 void
1102 vl_compositor_set_palette_layer(struct vl_compositor *c,
1103 unsigned layer,
1104 struct pipe_sampler_view *indexes,
1105 struct pipe_sampler_view *palette,
1106 struct pipe_video_rect *src_rect,
1107 struct pipe_video_rect *dst_rect,
1108 bool include_color_conversion)
1110 assert(c && indexes && palette);
1112 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
1114 c->used_layers |= 1 << layer;
1116 c->layers[layer].fs = include_color_conversion ?
1117 c->fs_palette.yuv : c->fs_palette.rgb;
1119 c->layers[layer].samplers[0] = c->sampler_linear;
1120 c->layers[layer].samplers[1] = c->sampler_nearest;
1121 c->layers[layer].samplers[2] = NULL;
1122 pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], indexes);
1123 pipe_sampler_view_reference(&c->layers[layer].sampler_views[1], palette);
1124 pipe_sampler_view_reference(&c->layers[layer].sampler_views[2], NULL);
1125 calc_src_and_dst(&c->layers[layer], indexes->texture->width0, indexes->texture->height0,
1126 src_rect ? *src_rect : default_rect(&c->layers[layer]),
1127 dst_rect);
1130 void
1131 vl_compositor_set_rgba_layer(struct vl_compositor *c,
1132 unsigned layer,
1133 struct pipe_sampler_view *rgba,
1134 struct pipe_video_rect *src_rect,
1135 struct pipe_video_rect *dst_rect)
1137 assert(c && rgba);
1139 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
1141 c->used_layers |= 1 << layer;
1142 c->layers[layer].fs = c->fs_rgba;
1143 c->layers[layer].samplers[0] = c->sampler_linear;
1144 c->layers[layer].samplers[1] = NULL;
1145 c->layers[layer].samplers[2] = NULL;
1146 pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], rgba);
1147 pipe_sampler_view_reference(&c->layers[layer].sampler_views[1], NULL);
1148 pipe_sampler_view_reference(&c->layers[layer].sampler_views[2], NULL);
1149 calc_src_and_dst(&c->layers[layer], rgba->texture->width0, rgba->texture->height0,
1150 src_rect ? *src_rect : default_rect(&c->layers[layer]),
1151 dst_rect);
1154 void
1155 vl_compositor_render(struct vl_compositor *c,
1156 struct pipe_surface *dst_surface,
1157 struct pipe_video_rect *dst_area,
1158 struct pipe_video_rect *dst_clip,
1159 bool clear_dirty_area)
1161 struct pipe_scissor_state scissor;
1163 assert(c);
1164 assert(dst_surface);
1166 c->fb_state.width = dst_surface->width;
1167 c->fb_state.height = dst_surface->height;
1168 c->fb_state.cbufs[0] = dst_surface;
1170 if (dst_area) {
1171 c->viewport.scale[0] = dst_area->w;
1172 c->viewport.scale[1] = dst_area->h;
1173 c->viewport.translate[0] = dst_area->x;
1174 c->viewport.translate[1] = dst_area->y;
1175 } else {
1176 c->viewport.scale[0] = dst_surface->width;
1177 c->viewport.scale[1] = dst_surface->height;
1178 c->viewport.translate[0] = 0;
1179 c->viewport.translate[1] = 0;
1182 if (dst_clip) {
1183 scissor.minx = dst_clip->x;
1184 scissor.miny = dst_clip->y;
1185 scissor.maxx = dst_clip->x + dst_clip->w;
1186 scissor.maxy = dst_clip->y + dst_clip->h;
1187 } else {
1188 scissor.minx = 0;
1189 scissor.miny = 0;
1190 scissor.maxx = dst_surface->width;
1191 scissor.maxy = dst_surface->height;
1194 gen_vertex_data(c, dst_surface->width, dst_surface->height);
1196 if (clear_dirty_area && (c->dirty_tl.x < c->dirty_br.x ||
1197 c->dirty_tl.y < c->dirty_br.y)) {
1198 util_clear_render_target(c->pipe, dst_surface, &c->clear_color,
1199 0, 0, dst_surface->width, dst_surface->height);
1200 c->dirty_tl.x = c->dirty_tl.y = 1.0f;
1201 c->dirty_br.x = c->dirty_br.y = 0.0f;
1204 c->pipe->set_scissor_state(c->pipe, &scissor);
1205 c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
1206 c->pipe->set_viewport_state(c->pipe, &c->viewport);
1207 c->pipe->bind_vs_state(c->pipe, c->vs);
1208 c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf);
1209 c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
1210 c->pipe->set_constant_buffer(c->pipe, PIPE_SHADER_FRAGMENT, 0, c->csc_matrix);
1211 c->pipe->bind_rasterizer_state(c->pipe, c->rast);
1213 draw_layers(c, dst_surface->width, dst_surface->height);
1216 bool
1217 vl_compositor_init(struct vl_compositor *c, struct pipe_context *pipe)
1219 csc_matrix csc_matrix;
1221 c->pipe = pipe;
1223 if (!init_pipe_state(c))
1224 return false;
1226 if (!init_shaders(c)) {
1227 cleanup_pipe_state(c);
1228 return false;
1231 if (!init_buffers(c)) {
1232 cleanup_shaders(c);
1233 cleanup_pipe_state(c);
1234 return false;
1237 vl_compositor_clear_layers(c);
1239 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, csc_matrix);
1240 vl_compositor_set_csc_matrix(c, csc_matrix);
1242 c->clear_color.f[0] = c->clear_color.f[1] = 0.0f;
1243 c->clear_color.f[2] = c->clear_color.f[3] = 0.0f;
1244 vl_compositor_reset_dirty_area(c);
1246 return true;
1249 bool
1250 vl_compositor_init_video(struct vl_compositor *c, struct pipe_context *pipe,
1251 enum pipe_video_chroma_format chroma, unsigned w, unsigned h)
1253 struct pipe_resource templ;
1254 int i;
1255 if (!vl_compositor_init(c, pipe))
1256 return false;
1257 c->video_w = w;
1258 c->video_h = h;
1260 c->fs_video_buffer2 = create_frag_shader_video_buffer(c, 2);
1261 if (!c->fs_video_buffer2) {
1262 debug_printf("Unable to create YCbCr-to-RGB fragment shader for 2 planes.\n");
1263 goto fail;
1265 c->fs_video_buffer3 = create_frag_shader_video_buffer(c, 3);
1266 if (!c->fs_video_buffer3) {
1267 debug_printf("Unable to create YCbCr-to-RGB fragment shader for 3 planes.\n");
1268 goto fail;
1270 c->fs_weave[0] = create_frag_shader_weave(c, 1, 0, 1);
1271 c->fs_weave[1] = create_frag_shader_weave(c, 0, 1, 2); // CbCr woven interlaced
1272 c->fs_weave[2] = create_frag_shader_weave(c, 0, 1, 1); // Cb, Cr separate interlaced
1273 c->fs_weave[3] = create_frag_shader_weave(c, 0, 0, 2); // CbCr woven progressive
1274 c->fs_weave[4] = create_frag_shader_weave(c, 0, 0, 1); // Cb, Cr separate progressive
1275 if (DEBUG_CONTOUR)
1276 c->fs_weave[5] = create_frag_shader_sobel(c);
1277 for (i = 0; i < Elements(c->fs_weave) - !DEBUG_CONTOUR; ++i) {
1278 if (!c->fs_weave[i]) {
1279 debug_printf("Unable to create weave fragment shaders [%i].\n", i);
1280 goto fail;
1283 memset(&templ, 0, sizeof(templ));
1284 templ.target = PIPE_TEXTURE_2D;
1285 templ.format = PIPE_FORMAT_R8_UNORM;
1286 templ.width0 = w;
1287 templ.height0 = h;
1288 templ.depth0 = 1;
1289 templ.array_size = 1;
1290 templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
1291 templ.usage = PIPE_USAGE_STATIC;
1292 c->video_res[0] = pipe->screen->resource_create(pipe->screen, &templ);
1293 if (!c->video_res[0]) {
1294 debug_printf("Could not create weave temp frame for luma\n");
1295 goto fail;
1298 if (chroma == PIPE_VIDEO_CHROMA_FORMAT_420)
1299 templ.width0 /= 2;
1300 templ.format = PIPE_FORMAT_R8G8_UNORM;
1301 c->video_res[1] = pipe->screen->resource_create(pipe->screen, &templ);
1302 if (!c->video_res[1]) {
1303 debug_printf("Could not create interlaced temp frame for chroma\n");
1304 goto fail;
1307 if (chroma != PIPE_VIDEO_CHROMA_FORMAT_444)
1308 templ.height0 = h / 2;
1309 c->video_res[2] = pipe->screen->resource_create(pipe->screen, &templ);
1310 if (!c->video_res[2]) {
1311 debug_printf("Could not create deinterlaced temp frame for chroma\n");
1312 goto fail;
1315 if (DEBUG_CONTOUR) {
1316 c->video_res[3] = pipe->screen->resource_create(pipe->screen, c->video_res[0]);
1317 if (!c->video_res[3]) {
1318 debug_printf("Could not create sobel temp frame for luma\n");
1319 goto fail;
1323 for (i = 0; i < Elements(c->video_res) - !DEBUG_CONTOUR; ++i) {
1324 struct pipe_sampler_view sv_templ;
1325 struct pipe_surface surf_templ;
1327 memset(&sv_templ, 0, sizeof(sv_templ));
1328 u_sampler_view_default_template(&sv_templ, c->video_res[i], c->video_res[i]->format);
1329 if (c->video_res[i]->format == PIPE_FORMAT_R8_UNORM)
1330 sv_templ.swizzle_a = sv_templ.swizzle_b = sv_templ.swizzle_g = sv_templ.swizzle_r;
1331 else if (c->video_res[i]->format == PIPE_FORMAT_R8G8_UNORM) {
1332 sv_templ.swizzle_b = PIPE_SWIZZLE_GREEN;
1333 sv_templ.swizzle_g = PIPE_SWIZZLE_RED;
1334 } else assert(0);
1335 c->video_sv[i] = pipe->create_sampler_view(pipe, c->video_res[i], &sv_templ);
1337 if (!c->video_sv[i]) {
1338 debug_printf("Could not create temp video sampler views\n");
1339 goto fail;
1342 memset(&surf_templ, 0, sizeof(surf_templ));
1343 surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
1344 surf_templ.format = c->video_res[i]->format;
1345 c->video_surf[i] = pipe->create_surface(pipe, c->video_res[i], &surf_templ);
1346 if (!c->video_surf[i]) {
1347 debug_printf("Could not create temp video surface\n");
1348 goto fail;
1352 return true;
1354 fail:
1355 vl_compositor_cleanup(c);
1356 return false;