g3dvl: Use sobel filter for chroma interpolation
[mesa/nouveau-pmpeg.git] / src / gallium / auxiliary / vl / vl_compositor.c
blobddb466be9ab61b94fa933f3528210a3cae0546f5
1 /**************************************************************************
3 * Copyright 2009 Younes Manton.
4 * Copyright 2011 Maarten Lankhorst
5 * All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
29 #include <assert.h>
31 #include "pipe/p_compiler.h"
32 #include "pipe/p_context.h"
34 #include "util/u_memory.h"
35 #include "util/u_draw.h"
36 #include "util/u_surface.h"
37 #include "util/u_sampler.h"
39 #include "tgsi/tgsi_ureg.h"
41 #include "vl_csc.h"
42 #include "vl_types.h"
43 #include "vl_compositor.h"
45 typedef float csc_matrix[16];
47 /* Set to 1 to run a contour shader for interpolation */
48 #define DEBUG_CONTOUR 1
50 /* Set to 1 to make all non-interpolated data in the contour shader black */
51 #define DEBUG_CONTOUR_CHROMA 0
53 static const float vl_contour_luma_threshold = .1f;
55 /* Set to non-zero half-pixel units for finding what would be affected by bicubic resizing */
56 #define DEBUG_BICUBIC 0
58 /* There's no point in using bicubic, it's not a good interpolation method for video when downscaling
59 * and for upscaling it's completely pointless until you get to a magnification of 4x or so
61 #define USE_BICUBIC 0
63 static void *
64 create_vert_shader(struct vl_compositor *c)
66 struct ureg_program *shader;
67 struct ureg_src vpos, vtex;
68 struct ureg_dst o_vpos, o_vtex;
70 shader = ureg_create(TGSI_PROCESSOR_VERTEX);
71 if (!shader)
72 return false;
74 vpos = ureg_DECL_vs_input(shader, 0);
75 vtex = ureg_DECL_vs_input(shader, 1);
76 o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0);
77 o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, 1);
80 * o_vpos = vpos
81 * o_vtex = vtex
83 ureg_MOV(shader, o_vpos, vpos);
84 ureg_MOV(shader, o_vtex, vtex);
86 ureg_END(shader);
88 return ureg_create_shader_and_destroy(shader, c->pipe);
91 static struct ureg_dst
92 calc_line(struct ureg_program *shader, struct ureg_src pos, unsigned nearest)
94 struct ureg_dst tmp;
96 tmp = ureg_DECL_temporary(shader);
99 * tmp.y = fraction(pos.y * .5) >= 0.5 ? 1 : 0
100 * however, for linear interpolation (chroma deinterlace) 2 pixels are required..
102 if (nearest)
103 ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.5f));
104 else
105 ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.25f));
106 ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp));
107 ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp), ureg_imm1f(shader, 0.5f));
109 return tmp;
112 static void *
113 create_frag_shader_video_buffer(struct vl_compositor *c)
115 struct ureg_program *shader;
116 struct ureg_src tc;
117 struct ureg_src csc[3];
118 struct ureg_src sampler[3];
119 struct ureg_dst texel;
120 struct ureg_dst fragment;
121 unsigned i;
123 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
124 if (!shader)
125 return false;
127 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
128 for (i = 0; i < 3; ++i) {
129 csc[i] = ureg_DECL_constant(shader, i);
130 sampler[i] = ureg_DECL_sampler(shader, i);
132 texel = ureg_DECL_temporary(shader);
133 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
136 * texel.xyz = tex(tc, sampler[i])
137 * fragment = csc * texel
139 for (i = 0; i < 3; ++i)
140 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, tc, sampler[i]);
141 ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
143 for (i = 0; i < 3; ++i)
144 ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
146 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
148 ureg_release_temporary(shader, texel);
149 ureg_END(shader);
151 return ureg_create_shader_and_destroy(shader, c->pipe);
154 static void *
155 create_frag_shader_sobel_video(struct vl_compositor *c)
157 struct ureg_program *shader;
158 struct ureg_src tc;
159 struct ureg_src csc[3];
160 struct ureg_src sampler[5], invsize, size;
161 struct ureg_dst texel, tmp, fragment;
162 unsigned i, label;
164 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
165 if (!shader)
166 return false;
168 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
169 for (i = 0; i < 3; ++i) {
170 csc[i] = ureg_DECL_constant(shader, i);
171 sampler[i] = ureg_DECL_sampler(shader, i);
173 for (; i < 5; ++i)
174 sampler[i] = ureg_DECL_sampler(shader, i);
175 size = ureg_DECL_constant(shader, 4);
176 invsize = ureg_DECL_constant(shader, 5);
178 texel = ureg_DECL_temporary(shader);
179 tmp = ureg_DECL_temporary(shader);
180 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
182 ureg_TEX(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, tc, sampler[3]);
183 ureg_SLE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(shader, 1.f));
184 ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(tmp), ureg_imm1f(shader, vl_contour_luma_threshold));
185 ureg_IF(shader, ureg_swizzle(ureg_src(tmp), TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y), &label);
187 ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), tc,
188 ureg_swizzle(size, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_W, TGSI_SWIZZLE_W, TGSI_SWIZZLE_W));
189 ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp), ureg_imm2f(shader, .5f, .5f));
190 ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp));
191 ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp), ureg_imm2f(shader, .5f, .5f));
192 ureg_SUB(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp), ureg_imm2f(shader, .5f, .5f));
193 // tmp.xy = -.5 for even x / y, .5 for odd x / y, this is then multiplied
194 // by absolute gradient previously calculated in the second sobel shader
195 // for the chroma offset
197 ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler[4]);
198 ureg_MUL(shader, tmp, ureg_src(texel),
199 ureg_swizzle(ureg_src(tmp), TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y));
201 ureg_MAD(shader, tmp, ureg_src(tmp),
202 ureg_swizzle(invsize, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_W, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_W),
203 ureg_swizzle(tc, TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y));
205 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, tc, sampler[0]);
206 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_Y), TGSI_TEXTURE_2D, ureg_src(tmp), sampler[1]);
207 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D,
208 ureg_swizzle(ureg_src(tmp), TGSI_SWIZZLE_Z, TGSI_SWIZZLE_W, TGSI_SWIZZLE_W, TGSI_SWIZZLE_W), sampler[2]);
210 // ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_X), ureg_imm3f(shader, 0.f, .5f, .5f));
211 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
213 ureg_ELSE(shader, &label);
215 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, tc, sampler[0]);
216 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_Y), TGSI_TEXTURE_2D, tc, sampler[1]);
217 ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D, tc, sampler[2]);
218 if (DEBUG_CONTOUR_CHROMA)
219 ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_XYZ), ureg_imm3f(shader, 0.f, .5f, .5f));
220 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
222 ureg_ENDIF(shader);
223 ureg_release_temporary(shader, tmp);
225 ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
227 for (i = 0; i < 3; ++i)
228 ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
230 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
232 ureg_release_temporary(shader, texel);
233 ureg_END(shader);
235 return ureg_create_shader_and_destroy(shader, c->pipe);
239 /* Deinterlace or weave NV12 or YV12 to a temporary video buffer
242 static void *
243 create_frag_shader_weave(struct vl_compositor *c, unsigned luma, unsigned interlaced)
245 struct ureg_program *shader;
246 struct ureg_src pos, tc, sampler[4];
247 struct ureg_dst field, fragment, swizcolor;
248 unsigned label, writemask, nearest;
250 if (luma)
251 writemask = TGSI_WRITEMASK_X;
252 else
253 writemask = TGSI_WRITEMASK_Y;
255 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
256 if (!shader)
257 return false;
259 pos = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_POSITION, 0, TGSI_INTERPOLATE_LINEAR);
260 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
261 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
262 sampler[0] = ureg_DECL_sampler(shader, 0);
263 sampler[1] = ureg_DECL_sampler(shader, 1);
264 if (!luma) {
265 sampler[2] = ureg_DECL_sampler(shader, 2);
266 sampler[3] = ureg_DECL_sampler(shader, 3);
269 nearest = luma || c->chroma != PIPE_VIDEO_CHROMA_FORMAT_420 || !interlaced;
270 field = calc_line(shader, pos, nearest);
271 swizcolor = ureg_DECL_temporary(shader);
273 /* field.y = fraction(coord/2) < . 5
275 * if (field.y)
276 * swiz = sampler[top];
277 * else
278 * swiz = sampler[bottom];
280 * if (LUMA)
281 * color.x = swiz;
282 * else
283 * color.xy = swiz.yz;
286 ureg_IF(shader, ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y), &label);
288 struct ureg_dst adjtc = ureg_DECL_temporary(shader);
289 if (!nearest) {
290 /* -2.0 / c->video_h (1 pixel up, chroma = half height, full height wouldn't need this)
291 * + .5 / c->video_h (.25 pixel down, since interlaced first pixel = .75 first
293 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_X), tc);
294 ureg_SUB(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_Y), ureg_scalar(tc, TGSI_SWIZZLE_Y),
295 ureg_imm1f(shader, 1.5f / c->video_h));
296 } else
297 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_XY), tc);
298 ureg_TEX(shader, ureg_writemask(swizcolor, writemask), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[1]);
299 if (!luma)
300 ureg_TEX(shader, ureg_writemask(swizcolor, TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[3]);
301 ureg_release_temporary(shader, adjtc);
302 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
304 ureg_ELSE(shader, &label);
306 struct ureg_dst adjtc = ureg_DECL_temporary(shader);
307 if (!nearest) {
308 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_X), tc);
309 ureg_ADD(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_Y), ureg_scalar(tc, TGSI_SWIZZLE_Y),
310 ureg_imm1f(shader, .5f / c->video_h));
311 } else
312 ureg_MOV(shader, ureg_writemask(adjtc, TGSI_WRITEMASK_XY), tc);
313 ureg_TEX(shader, ureg_writemask(swizcolor, writemask), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[0]);
314 if (!luma)
315 ureg_TEX(shader, ureg_writemask(swizcolor, TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D, ureg_src(adjtc), sampler[2]);
316 ureg_release_temporary(shader, adjtc);
317 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
319 ureg_ENDIF(shader);
321 if (luma)
322 ureg_MOV(shader, ureg_writemask(fragment, writemask), ureg_src(swizcolor));
323 else
324 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XY),
325 ureg_swizzle(ureg_src(swizcolor), TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z));
327 ureg_release_temporary(shader, swizcolor);
328 ureg_release_temporary(shader, field);
329 ureg_END(shader);
330 return ureg_create_shader_and_destroy(shader, c->pipe);
333 static void *
334 create_frag_shader_bicubic(struct vl_compositor *c) {
335 struct ureg_src sampler[3], lookup, cst, size, tc, csc[4];
336 struct ureg_dst fragment, tmp, hg_x, hg_y, color, coord[2][2], tex[2][2];
337 int i, j;
339 struct ureg_program *shader;
340 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
341 if (!shader)
342 return NULL;
344 ureg_property_fs_coord_pixel_center(shader, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
345 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
346 for (i = 0; i < 3; ++i)
347 csc[i] = ureg_DECL_constant(shader, i);
348 size = ureg_DECL_constant(shader, 4);
349 cst = ureg_DECL_constant(shader, 5);
351 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
352 for (i = 0; i < 3; ++i)
353 sampler[i] = ureg_DECL_sampler(shader, i);
354 lookup = ureg_DECL_sampler(shader, 3);
356 tmp = ureg_DECL_temporary(shader);
357 hg_x = ureg_DECL_temporary(shader);
358 hg_y = ureg_DECL_temporary(shader);
359 color = ureg_DECL_temporary(shader);
361 for (i = 0; i < 4; ++i) {
362 coord[i/2][i%2] = ureg_DECL_temporary(shader);
363 tex[i/2][i%2] = ureg_DECL_temporary(shader);
366 for (j = 0; j < 3; ++j) {
367 unsigned writemask, p = j >= 1;
368 writemask = TGSI_WRITEMASK_X << j;
370 if (j == 0 || (j == 1 && c->chroma != PIPE_VIDEO_CHROMA_FORMAT_444)) {
371 /* tmp.xy = tc * size[p].xy
372 * hg_x.xyz = tex1D(lookup, tmp.x);
373 * hg_y.xyz = tex1D(lookup, tmp.y);
375 ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY),
376 tc, ureg_swizzle(size, 2 * p, 2 * p + 1, 2 * p + 1, 2 * p + 1));
377 ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp));
378 ureg_TEX(shader, ureg_writemask(hg_x, TGSI_WRITEMASK_XYZ),
379 TGSI_TEXTURE_1D, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), lookup);
380 ureg_TEX(shader, ureg_writemask(hg_y, TGSI_WRITEMASK_XYZ),
381 TGSI_TEXTURE_1D, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), lookup);
383 #define e_x(x, p) ureg_scalar(x, 2 * p)
384 #define e_y(x, p) ureg_scalar(x, 2 * p + 1)
386 /* coord1X.x += hg_x.x * cst[p].x;
387 * coord0X.x -= hg_x.y * cst[p].x;
389 * coord11.y += hg_y.x * cst[p].w
390 * coord01.y += hg_y.x * cst[p].w
392 * coord10.y -= hg_y.y * cst[p].w
393 * coord00.y -= hg_y.y * cst[p].w
396 ureg_MAD(shader, ureg_writemask(coord[1][0], TGSI_WRITEMASK_X),
397 ureg_scalar(ureg_src(hg_x), TGSI_SWIZZLE_X),
398 e_x(cst, p), tc);
399 ureg_MAD(shader, ureg_writemask(coord[0][0], TGSI_WRITEMASK_X),
400 ureg_negate(ureg_scalar(ureg_src(hg_x), TGSI_SWIZZLE_Y)),
401 e_x(cst, p), tc);
403 for (i = 0; i < 2; ++i)
404 ureg_MOV(shader, ureg_writemask(coord[i][1], TGSI_WRITEMASK_X), ureg_src(coord[i][0]));
405 ureg_MAD(shader, ureg_writemask(coord[1][1], TGSI_WRITEMASK_Y),
406 ureg_scalar(ureg_src(hg_y), TGSI_SWIZZLE_X),
407 e_y(cst, p), tc);
408 ureg_MAD(shader, ureg_writemask(coord[0][1], TGSI_WRITEMASK_Y),
409 ureg_scalar(ureg_src(hg_y), TGSI_SWIZZLE_X),
410 e_y(cst, p), tc);
412 ureg_MAD(shader, ureg_writemask(coord[1][0], TGSI_WRITEMASK_Y),
413 ureg_negate(ureg_scalar(ureg_src(hg_y), TGSI_SWIZZLE_Y)),
414 e_y(cst, p), tc);
415 ureg_MAD(shader, ureg_writemask(coord[0][0], TGSI_WRITEMASK_Y),
416 ureg_negate(ureg_scalar(ureg_src(hg_y), TGSI_SWIZZLE_Y)),
417 e_y(cst, p), tc);
419 #undef e_y
420 #undef e_x
423 for (i = 0; i < 4; ++i) {
424 ureg_TEX(shader, ureg_writemask(tex[i/2][i%2], writemask),
425 TGSI_TEXTURE_2D, ureg_src(coord[i/2][i%2]), sampler[j]);
428 for (i = 0; i < 2; ++i)
429 ureg_LRP(shader, ureg_writemask(tex[i][0], writemask),
430 ureg_scalar(ureg_src(hg_y), TGSI_SWIZZLE_Z),
431 ureg_src(tex[i][0]), ureg_src(tex[i][1]));
433 ureg_LRP(shader, ureg_writemask(color, writemask),
434 ureg_scalar(ureg_src(hg_x), TGSI_SWIZZLE_Z),
435 ureg_src(tex[0][0]), ureg_src(tex[1][0]));
438 for (i = 3; i >= 0; --i) {
439 ureg_release_temporary(shader, tex[i/2][i%2]);
440 ureg_release_temporary(shader, coord[i/2][i%2]);
442 ureg_release_temporary(shader, hg_y);
443 ureg_release_temporary(shader, hg_x);
444 ureg_release_temporary(shader, tmp);
446 ureg_MOV(shader, ureg_writemask(color, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
448 if (DEBUG_BICUBIC) {
449 struct ureg_dst lincolor = ureg_DECL_temporary(shader);
450 unsigned label;
451 float val = ((float)DEBUG_BICUBIC) / 512.f;
452 ureg_TEX(shader, ureg_writemask(lincolor, TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, tc, sampler[0]);
453 ureg_TEX(shader, ureg_writemask(lincolor, TGSI_WRITEMASK_Y),
454 TGSI_TEXTURE_2D, tc, sampler[1]);
455 ureg_TEX(shader, ureg_writemask(lincolor, TGSI_WRITEMASK_Z),
456 TGSI_TEXTURE_2D, tc, sampler[2]);
457 /* lincolor.xyz = tex2D(...);
458 * lincolor.xyz = |color - lincolor|
459 * lincolor.xyz = lincolor >= DEBUG_BICUBIC / 512.f
460 * if (lincolor.xyz)
461 * color.xyz = { 1.f, .5f, .5f }
462 * endif
464 ureg_SUB(shader, ureg_writemask(lincolor, TGSI_WRITEMASK_XYZ), ureg_src(color), ureg_src(lincolor));
465 ureg_ABS(shader, ureg_writemask(lincolor, TGSI_WRITEMASK_XYZ), ureg_src(lincolor));
466 ureg_SGE(shader, ureg_writemask(lincolor, TGSI_WRITEMASK_XYZ), ureg_src(lincolor), ureg_imm3f(shader, val, val, val));
467 ureg_IF(shader, ureg_swizzle(ureg_src(lincolor), TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_W, TGSI_SWIZZLE_Z), &label);
468 ureg_MOV(shader, ureg_writemask(color, TGSI_WRITEMASK_XYZ), ureg_imm3f(shader, 1.f, .5f, .5f));
469 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
470 ureg_ENDIF(shader);
471 ureg_release_temporary(shader, lincolor);
474 for (i = 0; i < 3; ++i)
475 ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(color));
476 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
478 ureg_release_temporary(shader, color);
480 ureg_END(shader);
481 return ureg_create_shader_and_destroy(shader, c->pipe);
484 static void *
485 create_frag_shader_sobel(struct vl_compositor *c, unsigned planes)
487 struct ureg_program *shader;
488 struct ureg_src tc, sampler[3];
489 struct ureg_dst fragment, color[4], tctmp, ly, lx;
490 float v[2] = { -.5f, .5f }, wmul = 1.f, hmul = 1.f;
491 int i;
492 unsigned label, writemask = TGSI_WRITEMASK_X;
493 if (planes > 1) {
494 if (c->chroma != PIPE_VIDEO_CHROMA_FORMAT_444)
495 wmul = 2.f;
496 if (c->chroma == PIPE_VIDEO_CHROMA_FORMAT_420)
497 hmul = 2.f;
498 writemask = TGSI_WRITEMASK_YZ;
501 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
502 if (!shader)
503 return NULL;
505 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
506 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
507 tctmp = ureg_DECL_temporary(shader);
509 sampler[0] = ureg_DECL_sampler(shader, 0);
510 if (planes) {
511 for (i = 1; i < planes; ++i)
512 sampler[i] = ureg_DECL_sampler(shader, i);
514 ureg_TEX(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, tc, sampler[0]);
515 ureg_SGE(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_X), ureg_src(tctmp), ureg_imm1f(shader, vl_contour_luma_threshold));
516 ureg_IF(shader, ureg_scalar(ureg_src(tctmp), TGSI_SWIZZLE_X), &label);
519 lx = ureg_DECL_temporary(shader);
520 ly = ureg_DECL_temporary(shader);
521 for (i = 0; i < Elements(color); ++i)
522 color[i] = ureg_DECL_temporary(shader);
524 /* Sobel, calculate textures for Ly, each point is sampling 4 others */
525 /* Weighting matrix in y direction (roughly):
527 * 0 .125 0.5 .125 0
528 * 0 .500 2.0 .500 0
529 * 4 divided by 2 weightings => multiply by 2
531 for (i = 0; i < 4; ++i) {
532 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_XY), tc, ureg_imm2f(shader, .5 * wmul * v[i%2]/(float)c->video_w, hmul * 2.25f * v[i/2]/(float)c->video_h));
533 if (planes < 3)
534 ureg_TEX(shader, ureg_writemask(color[i], writemask), TGSI_TEXTURE_2D, ureg_src(tctmp), sampler[!!planes]);
535 else {
536 ureg_TEX(shader, ureg_writemask(color[i], TGSI_WRITEMASK_Y), TGSI_TEXTURE_2D, ureg_src(tctmp), sampler[1]);
537 ureg_TEX(shader, ureg_writemask(color[i], TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D, ureg_src(tctmp), sampler[2]);
541 /* Ly.xyz = wtop - wbottom */
542 ureg_ADD(shader, ureg_writemask(color[0], writemask), ureg_src(color[0]), ureg_src(color[1]));
543 ureg_ADD(shader, ureg_writemask(color[1], writemask), ureg_src(color[2]), ureg_src(color[3]));
544 ureg_SUB(shader, ureg_writemask(ly, writemask), ureg_src(color[0]), ureg_src(color[1]));
546 for (i = 0; i < 4; ++i) {
547 ureg_ADD(shader, ureg_writemask(tctmp, TGSI_WRITEMASK_XY), tc, ureg_imm2f(shader, wmul * 2.25f * v[i/2]/(float)c->video_w, .5 * hmul * v[i%2]/(float)c->video_h));
548 if (planes < 3)
549 ureg_TEX(shader, ureg_writemask(color[i], writemask), TGSI_TEXTURE_2D, ureg_src(tctmp), sampler[!!planes]);
550 else {
551 ureg_TEX(shader, ureg_writemask(color[i], TGSI_WRITEMASK_Y), TGSI_TEXTURE_2D, ureg_src(tctmp), sampler[1]);
552 ureg_TEX(shader, ureg_writemask(color[i], TGSI_WRITEMASK_Z), TGSI_TEXTURE_2D, ureg_src(tctmp), sampler[2]);
556 ureg_ADD(shader, ureg_writemask(color[0], writemask), ureg_src(color[0]), ureg_src(color[1]));
557 ureg_ADD(shader, ureg_writemask(color[1], writemask), ureg_src(color[2]), ureg_src(color[3]));
558 ureg_SUB(shader, ureg_writemask(lx, writemask), ureg_src(color[0]), ureg_src(color[1]));
559 /* Lx.xyz = wleft - wright */
561 if (!planes) {
562 /* tmp.xyz = |Lx|**2 + |Ly|**2 */
563 ureg_MUL(shader, ureg_writemask(tctmp, writemask), ureg_src(lx), ureg_src(lx));
564 ureg_MAD(shader, ureg_writemask(tctmp, writemask), ureg_src(ly), ureg_src(ly), ureg_src(tctmp));
565 ureg_MUL(shader, ureg_writemask(fragment, writemask), ureg_src(tctmp), ureg_imm1f(shader, 2.f));
566 } else {
567 static const float s = 2.f;
568 ureg_ABS(shader, ureg_writemask(lx, writemask), ureg_src(lx));
569 ureg_ABS(shader, ureg_writemask(ly, writemask), ureg_src(ly));
570 ureg_MUL(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XZ),
571 ureg_swizzle(ureg_src(lx), TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z),
572 ureg_imm4f(shader, s, s, s, s));
573 ureg_MUL(shader, ureg_writemask(fragment, TGSI_WRITEMASK_YW),
574 ureg_swizzle(ureg_src(ly), TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z),
575 ureg_imm4f(shader, s, s, s, s));
578 for (i = 0; i < Elements(color); ++i)
579 ureg_release_temporary(shader, color[i]);
580 ureg_release_temporary(shader, ly);
581 ureg_release_temporary(shader, lx);
583 if (planes) {
584 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
585 ureg_ELSE(shader, &label);
586 ureg_MOV(shader, fragment, ureg_imm4f(shader, 0.f, 0.f, 0.f, 0.f));
587 ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
588 ureg_ENDIF(shader);
590 ureg_release_temporary(shader, tctmp);
591 ureg_END(shader);
592 return ureg_create_shader_and_destroy(shader, c->pipe);
595 static void *
596 create_frag_shader_palette(struct vl_compositor *c, bool include_cc)
598 struct ureg_program *shader;
599 struct ureg_src csc[3];
600 struct ureg_src tc;
601 struct ureg_src sampler;
602 struct ureg_src palette;
603 struct ureg_dst texel;
604 struct ureg_dst fragment;
605 unsigned i;
607 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
608 if (!shader)
609 return false;
611 for (i = 0; include_cc && i < 3; ++i)
612 csc[i] = ureg_DECL_constant(shader, i);
614 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
615 sampler = ureg_DECL_sampler(shader, 0);
616 palette = ureg_DECL_sampler(shader, 1);
618 texel = ureg_DECL_temporary(shader);
619 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
622 * texel = tex(tc, sampler)
623 * fragment.xyz = tex(texel, palette) * csc
624 * fragment.a = texel.a
626 ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
627 ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(texel));
629 if (include_cc) {
630 ureg_TEX(shader, texel, TGSI_TEXTURE_1D, ureg_src(texel), palette);
631 for (i = 0; i < 3; ++i)
632 ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
633 } else {
634 ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ),
635 TGSI_TEXTURE_1D, ureg_src(texel), palette);
638 ureg_release_temporary(shader, texel);
639 ureg_END(shader);
641 return ureg_create_shader_and_destroy(shader, c->pipe);
644 static void *
645 create_frag_shader_rgba(struct vl_compositor *c)
647 struct ureg_program *shader;
648 struct ureg_src tc;
649 struct ureg_src sampler;
650 struct ureg_dst fragment;
652 shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
653 if (!shader)
654 return false;
656 tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
657 sampler = ureg_DECL_sampler(shader, 0);
658 fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
661 * fragment = tex(tc, sampler)
663 ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler);
664 ureg_END(shader);
666 return ureg_create_shader_and_destroy(shader, c->pipe);
669 static bool
670 init_shaders(struct vl_compositor *c)
672 assert(c);
674 c->vs = create_vert_shader(c);
675 if (!c->vs) {
676 debug_printf("Unable to create vertex shader.\n");
677 return false;
680 c->fs_palette.yuv = create_frag_shader_palette(c, true);
681 if (!c->fs_palette.yuv) {
682 debug_printf("Unable to create YUV-Palette-to-RGB fragment shader.\n");
683 return false;
686 c->fs_palette.rgb = create_frag_shader_palette(c, false);
687 if (!c->fs_palette.rgb) {
688 debug_printf("Unable to create RGB-Palette-to-RGB fragment shader.\n");
689 return false;
692 c->fs_rgba = create_frag_shader_rgba(c);
693 if (!c->fs_rgba) {
694 debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
695 return false;
698 return true;
701 static void cleanup_shaders(struct vl_compositor *c)
703 assert(c);
705 c->pipe->delete_vs_state(c->pipe, c->vs);
706 c->pipe->delete_fs_state(c->pipe, c->fs_palette.yuv);
707 c->pipe->delete_fs_state(c->pipe, c->fs_palette.rgb);
708 c->pipe->delete_fs_state(c->pipe, c->fs_rgba);
711 static bool
712 init_pipe_state(struct vl_compositor *c)
714 struct pipe_rasterizer_state rast;
715 struct pipe_sampler_state sampler;
716 struct pipe_blend_state blend;
717 struct pipe_depth_stencil_alpha_state dsa;
718 unsigned i;
720 assert(c);
722 c->fb_state.nr_cbufs = 1;
723 c->fb_state.zsbuf = NULL;
725 c->viewport.scale[2] = 1;
726 c->viewport.scale[3] = 1;
727 c->viewport.translate[2] = 0;
728 c->viewport.translate[3] = 0;
730 memset(&sampler, 0, sizeof(sampler));
731 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
732 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
733 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
734 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
735 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
736 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
737 sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
738 sampler.compare_func = PIPE_FUNC_ALWAYS;
739 sampler.normalized_coords = 1;
741 c->sampler_linear = c->pipe->create_sampler_state(c->pipe, &sampler);
743 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
744 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
745 c->sampler_nearest = c->pipe->create_sampler_state(c->pipe, &sampler);
747 sampler.wrap_s = sampler.wrap_t = sampler.wrap_r = PIPE_TEX_WRAP_REPEAT;
748 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
749 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
750 c->sampler_repeat = c->pipe->create_sampler_state(c->pipe, &sampler);
752 memset(&blend, 0, sizeof blend);
753 blend.independent_blend_enable = 0;
754 blend.rt[0].blend_enable = 0;
755 blend.logicop_enable = 0;
756 blend.logicop_func = PIPE_LOGICOP_CLEAR;
757 blend.rt[0].colormask = PIPE_MASK_RGBA;
758 blend.dither = 0;
759 c->blend_clear = c->pipe->create_blend_state(c->pipe, &blend);
761 blend.rt[0].blend_enable = 1;
762 blend.rt[0].rgb_func = PIPE_BLEND_ADD;
763 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
764 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
765 blend.rt[0].alpha_func = PIPE_BLEND_ADD;
766 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
767 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
768 c->blend_add = c->pipe->create_blend_state(c->pipe, &blend);
770 memset(&rast, 0, sizeof rast);
771 rast.flatshade = 1;
772 rast.front_ccw = 1;
773 rast.cull_face = PIPE_FACE_NONE;
774 rast.fill_back = PIPE_POLYGON_MODE_FILL;
775 rast.fill_front = PIPE_POLYGON_MODE_FILL;
776 rast.scissor = 1;
777 rast.line_width = 1;
778 rast.point_size_per_vertex = 1;
779 rast.offset_units = 1;
780 rast.offset_scale = 1;
781 rast.gl_rasterization_rules = 1;
783 c->rast = c->pipe->create_rasterizer_state(c->pipe, &rast);
785 memset(&dsa, 0, sizeof dsa);
786 dsa.depth.enabled = 0;
787 dsa.depth.writemask = 0;
788 dsa.depth.func = PIPE_FUNC_ALWAYS;
789 for (i = 0; i < 2; ++i) {
790 dsa.stencil[i].enabled = 0;
791 dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
792 dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
793 dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
794 dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
795 dsa.stencil[i].valuemask = 0;
796 dsa.stencil[i].writemask = 0;
798 dsa.alpha.enabled = 0;
799 dsa.alpha.func = PIPE_FUNC_ALWAYS;
800 dsa.alpha.ref_value = 0;
801 c->dsa = c->pipe->create_depth_stencil_alpha_state(c->pipe, &dsa);
802 c->pipe->bind_depth_stencil_alpha_state(c->pipe, c->dsa);
804 return true;
807 static void cleanup_pipe_state(struct vl_compositor *c)
809 assert(c);
811 /* Asserted in softpipe_delete_fs_state() for some reason */
812 c->pipe->bind_vs_state(c->pipe, NULL);
813 c->pipe->bind_fs_state(c->pipe, NULL);
815 c->pipe->delete_depth_stencil_alpha_state(c->pipe, c->dsa);
816 c->pipe->delete_sampler_state(c->pipe, c->sampler_linear);
817 c->pipe->delete_sampler_state(c->pipe, c->sampler_nearest);
818 c->pipe->delete_sampler_state(c->pipe, c->sampler_repeat);
819 c->pipe->delete_blend_state(c->pipe, c->blend_clear);
820 c->pipe->delete_blend_state(c->pipe, c->blend_add);
821 c->pipe->delete_rasterizer_state(c->pipe, c->rast);
824 static bool
825 create_vertex_buffer(struct vl_compositor *c)
827 assert(c);
829 pipe_resource_reference(&c->vertex_buf.buffer, NULL);
830 c->vertex_buf.buffer = pipe_buffer_create
832 c->pipe->screen,
833 PIPE_BIND_VERTEX_BUFFER,
834 PIPE_USAGE_STREAM,
835 sizeof(struct vertex4f) * VL_COMPOSITOR_MAX_LAYERS * 4
838 return c->vertex_buf.buffer != NULL;
841 static bool
842 init_buffers(struct vl_compositor *c)
844 struct pipe_vertex_element vertex_elems[2];
846 assert(c);
849 * Create our vertex buffer and vertex buffer elements
851 c->vertex_buf.stride = sizeof(struct vertex4f);
852 c->vertex_buf.buffer_offset = 0;
853 create_vertex_buffer(c);
855 vertex_elems[0].src_offset = 0;
856 vertex_elems[0].instance_divisor = 0;
857 vertex_elems[0].vertex_buffer_index = 0;
858 vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
859 vertex_elems[1].src_offset = sizeof(struct vertex2f);
860 vertex_elems[1].instance_divisor = 0;
861 vertex_elems[1].vertex_buffer_index = 0;
862 vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
863 c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 2, vertex_elems);
866 * Create our fragment shader's constant buffer
867 * Const buffer contains the color conversion matrix and bias vectors
869 /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
870 c->csc_matrix = pipe_buffer_create
872 c->pipe->screen,
873 PIPE_BIND_CONSTANT_BUFFER,
874 PIPE_USAGE_STATIC,
875 sizeof(csc_matrix) + sizeof(c->original_sizes)
877 assert((Elements(c->csc) + Elements(c->original_sizes))/4 == 7); // amount of constants
879 return true;
882 static void
883 cleanup_buffers(struct vl_compositor *c)
885 assert(c);
887 c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
888 pipe_resource_reference(&c->vertex_buf.buffer, NULL);
889 pipe_resource_reference(&c->csc_matrix, NULL);
892 static INLINE struct pipe_video_rect
893 default_rect(struct vl_compositor_layer *layer)
895 struct pipe_resource *res = layer->sampler_views[0]->texture;
896 struct pipe_video_rect rect = { 0, 0, res->width0, res->height0 };
897 return rect;
900 static INLINE struct vertex2f
901 calc_topleft(struct vertex2f size, struct pipe_video_rect rect)
903 struct vertex2f res = { rect.x / size.x, rect.y / size.y };
904 return res;
907 static INLINE struct vertex2f
908 calc_bottomright(struct vertex2f size, struct pipe_video_rect rect)
910 struct vertex2f res = { (rect.x + rect.w) / size.x, (rect.y + rect.h) / size.y };
911 return res;
914 static INLINE void
915 calc_src_and_dst(struct vl_compositor_layer *layer, unsigned width, unsigned height,
916 struct pipe_video_rect src, struct pipe_video_rect *dst)
918 struct vertex2f size_in = { width, height };
919 struct vertex2f size_out = { 1.f, 1.f };
921 layer->src.tl = calc_topleft(size_in, src);
922 layer->src.br = calc_bottomright(size_in, src);
923 if (dst) {
924 layer->dst.tl = calc_topleft(size_out, *dst);
925 layer->dst.br = calc_bottomright(size_out, *dst);
926 layer->custom_dest_rect = 1;
927 } else {
928 layer->dst.tl.x = layer->dst.tl.y = 0.f;
929 layer->dst.br.x = layer->dst.br.y = 1.f;
930 layer->custom_dest_rect = 0;
934 static void
935 gen_rect_verts(struct vertex4f *vb, struct vl_compositor_layer *layer, float w, float h)
937 assert(vb && layer);
939 vb[0].x = layer->dst.tl.x / w;
940 vb[0].y = layer->dst.tl.y / h;
941 vb[0].z = layer->src.tl.x;
942 vb[0].w = layer->src.tl.y;
944 vb[1].x = layer->dst.br.x / w;
945 vb[1].y = layer->dst.tl.y / h;
946 vb[1].z = layer->src.br.x;
947 vb[1].w = layer->src.tl.y;
949 vb[2].x = layer->dst.br.x / w;
950 vb[2].y = layer->dst.br.y / h;
951 vb[2].z = layer->src.br.x;
952 vb[2].w = layer->src.br.y;
954 vb[3].x = layer->dst.tl.x / w;
955 vb[3].y = layer->dst.br.y / h;
956 vb[3].z = layer->src.tl.x;
957 vb[3].w = layer->src.br.y;
960 static void
961 gen_vertex_data(struct vl_compositor *c, float w, float h)
963 struct vertex4f *vb;
964 struct pipe_transfer *buf_transfer;
965 unsigned i;
967 assert(c);
969 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
970 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_DONTBLOCK,
971 &buf_transfer);
973 if (!vb) {
974 // If buffer is still locked from last draw create a new one
975 create_vertex_buffer(c);
976 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
977 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
978 &buf_transfer);
981 for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; i++) {
982 if (c->used_layers & (1 << i)) {
983 struct vl_compositor_layer *layer = &c->layers[i];
984 if (layer->custom_dest_rect)
985 gen_rect_verts(vb, layer, w, h);
986 else
987 gen_rect_verts(vb, layer, 1.f, 1.f);
988 vb += 4;
990 if (layer->clearing &&
991 (!layer->custom_dest_rect ||
992 (c->dirty_tl.x >= layer->dst.tl.x/w &&
993 c->dirty_tl.y >= layer->dst.tl.y/h &&
994 c->dirty_br.x <= layer->dst.br.x/w &&
995 c->dirty_br.y <= layer->dst.br.y/h))) {
996 // We clear the dirty area anyway, no need for clear_render_target
997 c->dirty_tl.x = c->dirty_tl.y = 1.0f;
998 c->dirty_br.x = c->dirty_br.y = 0.0f;
1003 pipe_buffer_unmap(c->pipe, buf_transfer);
1006 static void
1007 draw_layers(struct vl_compositor *c, float w, float h)
1009 unsigned vb_index, i;
1011 assert(c);
1013 for (i = 0, vb_index = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
1014 if (c->used_layers & (1 << i)) {
1015 struct vl_compositor_layer *layer = &c->layers[i];
1016 struct pipe_sampler_view **samplers = &layer->sampler_views[0];
1017 unsigned num_sampler_views = !samplers[1] ? 1 : !samplers[2] ? 2 : !samplers[3] ? 3 : !samplers[4] ? 4 : 5;
1019 c->pipe->bind_blend_state(c->pipe, layer->blend);
1020 c->pipe->bind_fs_state(c->pipe, layer->fs);
1021 c->pipe->bind_fragment_sampler_states(c->pipe, num_sampler_views, layer->samplers);
1022 c->pipe->set_fragment_sampler_views(c->pipe, num_sampler_views, samplers);
1023 util_draw_arrays(c->pipe, PIPE_PRIM_QUADS, vb_index * 4, 4);
1024 vb_index++;
1026 // Remember the currently drawn area as dirty for the next draw command
1027 if (layer->custom_dest_rect) {
1028 c->dirty_tl.x = MIN2(layer->dst.tl.x/w, c->dirty_tl.x);
1029 c->dirty_tl.y = MIN2(layer->dst.tl.y/h, c->dirty_tl.y);
1030 c->dirty_br.x = MAX2(layer->dst.br.x/w, c->dirty_br.x);
1031 c->dirty_br.y = MAX2(layer->dst.br.y/h, c->dirty_br.y);
1032 } else {
1033 c->dirty_tl.x = 0.f;
1034 c->dirty_tl.y = 0.f;
1035 c->dirty_br.x = 1.f;
1036 c->dirty_br.y = 1.f;
1042 void
1043 vl_compositor_reset_dirty_area(struct vl_compositor *c)
1045 assert(c);
1047 c->dirty_tl.x = c->dirty_tl.y = 0.0f;
1048 c->dirty_br.x = c->dirty_br.y = 1.0f;
1051 void
1052 vl_compositor_set_clear_color(struct vl_compositor *c, union pipe_color_union *color)
1054 assert(c);
1056 c->clear_color = *color;
1059 void
1060 vl_compositor_get_clear_color(struct vl_compositor *c, union pipe_color_union *color)
1062 assert(c);
1063 assert(color);
1065 *color = c->clear_color;
1068 void
1069 vl_compositor_clear_layers(struct vl_compositor *c)
1071 unsigned i, j;
1073 assert(c);
1075 c->used_layers = 0;
1076 for ( i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
1077 c->layers[i].clearing = i ? false : true;
1078 c->layers[i].blend = i ? c->blend_add : c->blend_clear;
1079 c->layers[i].fs = NULL;
1080 for ( j = 0; j < 3; j++)
1081 pipe_sampler_view_reference(&c->layers[i].sampler_views[j], NULL);
1085 static void
1086 cleanup_video(struct vl_compositor *c)
1088 unsigned i;
1089 for (i = 0; i < Elements(c->video_res); ++i) {
1090 pipe_sampler_view_reference(&c->video_sv[i], NULL);
1091 pipe_surface_reference(&c->video_surf[i], NULL);
1092 pipe_resource_reference(&c->video_res[i], NULL);
1094 for (i = 0; i < Elements(c->fs_weave); ++i) {
1095 if (!c->fs_weave[i])
1096 continue;
1097 c->pipe->delete_fs_state(c->pipe, c->fs_weave[i]);
1098 c->fs_weave[i] = NULL;
1101 for (i = 0; i < Elements(c->fs_video_buffer); ++i) {
1102 if (c->fs_video_buffer[i])
1103 c->pipe->delete_fs_state(c->pipe, c->fs_video_buffer[i]);
1104 c->fs_video_buffer[i] = NULL;
1108 void
1109 vl_compositor_cleanup(struct vl_compositor *c)
1111 assert(c);
1113 vl_compositor_clear_layers(c);
1114 cleanup_buffers(c);
1115 cleanup_shaders(c);
1116 cleanup_pipe_state(c);
1117 cleanup_video(c);
1120 void
1121 vl_compositor_set_csc_matrix(struct vl_compositor *c, const float matrix[16])
1123 struct pipe_transfer *buf_transfer;
1124 float *map;
1126 assert(c);
1128 map = pipe_buffer_map(c->pipe, c->csc_matrix,
1129 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
1130 &buf_transfer);
1131 memcpy(map, matrix, sizeof(csc_matrix));
1132 memcpy(map + Elements(c->csc), c->original_sizes, sizeof(c->original_sizes));
1133 memcpy(c->csc, matrix, sizeof(csc_matrix));
1134 pipe_buffer_unmap(c->pipe, buf_transfer);
1137 void
1138 vl_compositor_set_layer_blend(struct vl_compositor *c,
1139 unsigned layer, void *blend,
1140 bool is_clearing)
1142 assert(c && blend);
1144 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
1146 c->layers[layer].clearing = is_clearing;
1147 c->layers[layer].blend = blend;
1151 static void gen_vertex_data_video(struct vl_compositor *c) {
1152 struct vertex4f *vb;
1153 struct pipe_transfer *buf_transfer;
1154 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
1155 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_DONTBLOCK,
1156 &buf_transfer);
1158 if (!vb) {
1159 // If buffer is still locked from last draw create a new one
1160 create_vertex_buffer(c);
1161 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
1162 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
1163 &buf_transfer);
1165 vb[0].x = 0.f;
1166 vb[0].y = 0.f;
1167 vb[0].z = 0.f;
1168 vb[0].w = 0.f;
1170 vb[1].x = 0.f;
1171 vb[1].y = 65535.f;
1172 vb[1].z = 0.f;
1173 vb[1].w = 65535.f;
1175 vb[2].x = 65535.f;
1176 vb[2].y = 0.f;
1177 vb[2].z = 65535.f;
1178 vb[2].w = 0.f;
1179 pipe_buffer_unmap(c->pipe, buf_transfer);
1182 static void
1183 vl_compositor_render_sobel(struct vl_compositor *c, struct pipe_sampler_view **sv)
1185 struct pipe_scissor_state scissor;
1186 struct pipe_surface *dst_surface;
1187 void *samplers[3];
1188 struct pipe_sampler_view *sv_render[3];
1189 int i;
1190 for (i = 0; i < 3; ++i) {
1191 sv_render[i] = sv[i];
1192 samplers[i] = c->sampler_linear;
1195 assert(c);
1197 gen_vertex_data_video(c);
1199 c->pipe->bind_vs_state(c->pipe, c->vs);
1200 c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf);
1201 c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
1202 c->pipe->bind_rasterizer_state(c->pipe, c->rast);
1203 c->pipe->bind_blend_state(c->pipe, c->blend_clear);
1204 c->pipe->bind_fragment_sampler_states(c->pipe, 3, samplers);
1206 for (i = 0; i < 2; ++i) {
1207 if (i)
1208 sv_render[0] = c->video_sv[3];
1209 c->pipe->set_fragment_sampler_views(c->pipe, 3, sv_render);
1211 c->viewport.scale[0] = sv[i]->texture->width0;
1212 c->viewport.scale[1] = sv[i]->texture->height0;
1213 c->viewport.translate[0] = 0;
1214 c->viewport.translate[1] = 0;
1215 c->pipe->set_viewport_state(c->pipe, &c->viewport);
1217 c->pipe->bind_fs_state(c->pipe, c->fs_weave[3+i]);
1218 dst_surface = c->video_surf[3 + i];
1220 c->fb_state.width = dst_surface->width;
1221 c->fb_state.height = dst_surface->height;
1222 c->fb_state.cbufs[0] = dst_surface;
1224 scissor.minx = 0;
1225 scissor.miny = 0;
1226 scissor.maxx = dst_surface->width;
1227 scissor.maxy = dst_surface->height;
1229 c->pipe->set_scissor_state(c->pipe, &scissor);
1230 c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
1231 util_draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, 0, 3);
1235 static void
1236 vl_compositor_render_video(struct vl_compositor *c,
1237 struct pipe_sampler_view **sv,
1238 unsigned interlaced)
1240 struct pipe_scissor_state scissor;
1241 void *samplers[4];
1242 unsigned i;
1243 for (i = 0; i < 4; ++i) {
1244 if (!interlaced || i < 2 || c->chroma != PIPE_VIDEO_CHROMA_FORMAT_420)
1245 samplers[i] = c->sampler_nearest;
1246 else
1247 samplers[i] = c->sampler_linear;
1249 assert(c);
1250 gen_vertex_data_video(c);
1251 for (i = 0; i < 2; ++i) {
1252 struct pipe_surface *dst_surface;
1253 unsigned num_sampler_views;
1254 void *fs;
1255 if (!i) {
1256 num_sampler_views = 2;
1257 dst_surface = c->video_surf[0];
1258 fs = c->fs_weave[0];
1259 } else {
1260 num_sampler_views = 4;
1261 if (interlaced) {
1262 dst_surface = c->video_surf[1];
1263 fs = c->fs_weave[1];
1264 } else {
1265 dst_surface = c->video_surf[2];
1266 fs = c->fs_weave[2];
1270 assert(dst_surface);
1271 c->fb_state.width = dst_surface->width;
1272 c->fb_state.height = dst_surface->height;
1273 c->fb_state.cbufs[0] = dst_surface;
1275 c->viewport.scale[0] = sv[0]->texture->width0;
1276 c->viewport.scale[1] = sv[0]->texture->height0 * 2;
1277 if (i && c->chroma == PIPE_VIDEO_CHROMA_FORMAT_420 && interlaced)
1278 c->viewport.scale[1] *= 2;
1279 c->viewport.translate[0] = 0;
1280 c->viewport.translate[1] = 0;
1282 scissor.minx = 0;
1283 scissor.miny = 0;
1284 scissor.maxx = dst_surface->width;
1285 scissor.maxy = dst_surface->height;
1287 c->pipe->set_scissor_state(c->pipe, &scissor);
1288 c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
1289 c->pipe->set_viewport_state(c->pipe, &c->viewport);
1290 c->pipe->bind_vs_state(c->pipe, c->vs);
1291 c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf);
1292 c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
1293 c->pipe->bind_rasterizer_state(c->pipe, c->rast);
1295 c->pipe->bind_blend_state(c->pipe, c->blend_clear);
1296 c->pipe->bind_fs_state(c->pipe, fs);
1297 c->pipe->bind_fragment_sampler_states(c->pipe, num_sampler_views, samplers);
1298 c->pipe->set_fragment_sampler_views(c->pipe, num_sampler_views, sv);
1299 sv += num_sampler_views;
1300 util_draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, 0, 3);
1304 void
1305 vl_compositor_set_buffer_layer(struct vl_compositor *c, unsigned layer,
1306 enum pipe_video_picture_structure field,
1307 struct pipe_video_buffer *buffer,
1308 struct pipe_video_rect *src_rect,
1309 struct pipe_video_rect *dst_rect,
1310 unsigned past_count,
1311 struct pipe_video_buffer **past,
1312 unsigned future_count,
1313 struct pipe_video_buffer **future)
1315 struct pipe_sampler_view **sampler_views, *sv_weave[6], *sv[VL_COMPOSITOR_SAMPLERS] = {};
1316 struct pipe_video_rect rect;
1317 unsigned i, half_h = 0;
1319 assert(c && buffer);
1320 assert(c->video_w <= buffer->width && c->video_h <= buffer->height);
1321 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
1323 if (field == PIPE_VIDEO_PICTURE_STRUCTURE_FRAME) {
1324 sampler_views = buffer->get_sampler_view_planes(buffer, 0);
1325 if (!sampler_views) {
1326 sampler_views = buffer->get_sampler_view_planes(buffer, 1);
1327 for (i = 0; i < 6; ++i)
1328 sv_weave[i] = sampler_views[i];
1329 if (!sv_weave[4])
1330 sv_weave[4] = sv_weave[2];
1331 if (!sv_weave[5])
1332 sv_weave[5] = sv_weave[3];
1333 vl_compositor_render_video(c, sv_weave, 0);
1334 sv[0] = c->video_sv[0];
1335 sv[2] = sv[1] = c->video_sv[2];
1336 } else {
1337 for (i = 0; i < 3; ++i)
1338 sv[i] = sampler_views[i];
1339 if (!sv[2])
1340 sv[2] = sv[1];
1342 } else {
1343 struct pipe_sampler_view **sv_cur, **sv_prev = NULL;
1344 int top = field == PIPE_VIDEO_PICTURE_STRUCTURE_FIELD_TOP;
1345 sv_cur = buffer->get_sampler_view_planes(buffer, 1);
1346 if (past_count && past[0])
1347 sv_prev = buffer->get_sampler_view_planes(past[0], 1);
1348 if (sv_prev) {
1349 for (i = 0; i < 6; i += 2) {
1350 if (top) {
1351 sv_weave[i] = sv_cur[i];
1352 sv_weave[i+1] = sv_prev[i+1];
1353 } else {
1354 sv_weave[i] = sv_prev[i];
1355 sv_weave[i+1] = sv_cur[i+1];
1358 if (!sv_weave[4])
1359 sv_weave[4] = sv_weave[2];
1360 if (!sv_weave[5])
1361 sv_weave[5] = sv_weave[3];
1362 vl_compositor_render_video(c, sv_weave, 1);
1363 sv[0] = c->video_sv[0];
1364 sv[2] = sv[1] = c->video_sv[1];
1365 } else {
1366 for (i = 0; i < 3; ++i)
1367 sv[i] = sv_cur[2*i+!top];
1368 if (!sv[2])
1369 sv[2] = sv[1];
1370 half_h = 1;
1373 assert(sv[2] && sv[1] && sv[0]);
1375 if (DEBUG_CONTOUR && !half_h)
1376 vl_compositor_render_sobel(c, sv);
1378 c->used_layers |= 1 << layer;
1379 if (!src_rect) {
1380 src_rect = &rect;
1381 rect.x = rect.y = 0;
1382 rect.w = c->video_w;
1383 rect.h = c->video_h;
1385 if (DEBUG_CONTOUR && !half_h) {
1386 c->layers[layer].fs = c->fs_video_buffer[1];
1387 sv[3] = c->video_sv[3];
1388 sv[4] = c->video_sv[4];
1389 } else
1390 c->layers[layer].fs = c->fs_video_buffer[0];
1392 for (i = 0; i < VL_COMPOSITOR_SAMPLERS; ++i) {
1393 c->layers[layer].samplers[i] = c->sampler_linear;
1394 pipe_sampler_view_reference(&c->layers[layer].sampler_views[i], sv[i]);
1396 if (USE_BICUBIC) {
1397 pipe_sampler_view_reference(&c->layers[layer].sampler_views[3], c->video_sv[4]);
1398 c->layers[layer].samplers[3] = c->sampler_repeat;
1401 if (c->original_sizes[0] != (float)sv[0]->texture->width0 ||
1402 c->original_sizes[1] != (float)sv[0]->texture->height0 ||
1403 c->original_sizes[2] != (float)sv[1]->texture->width0 ||
1404 c->original_sizes[3] != (float)sv[1]->texture->height0) {
1405 struct pipe_transfer *buf_transfer;
1406 float *map = pipe_buffer_map(c->pipe, c->csc_matrix,
1407 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
1408 &buf_transfer);
1409 c->original_sizes[0] = (float)sv[0]->texture->width0;
1410 c->original_sizes[1] = (float)sv[0]->texture->height0;
1411 c->original_sizes[2] = (float)sv[1]->texture->width0;
1412 c->original_sizes[3] = (float)sv[1]->texture->height0;
1413 c->original_sizes[4] = 1.f/(float)sv[0]->texture->width0;
1414 c->original_sizes[5] = 1.f/(float)sv[0]->texture->height0;
1415 c->original_sizes[6] = 1.f/(float)sv[1]->texture->width0;
1416 c->original_sizes[7] = 1.f/(float)sv[1]->texture->height0;
1417 c->original_sizes[8] = .5f/(float)sv[0]->texture->width0;
1418 c->original_sizes[9] = .5f/(float)sv[0]->texture->height0;
1419 c->original_sizes[10] = .5f/(float)sv[1]->texture->width0;
1420 c->original_sizes[11] = .5f/(float)sv[1]->texture->height0;
1421 memcpy(map, c->csc, sizeof(c->csc));
1422 memcpy(map + Elements(c->csc), c->original_sizes, sizeof(c->original_sizes));
1423 pipe_buffer_unmap(c->pipe, buf_transfer);
1426 calc_src_and_dst(&c->layers[layer],
1427 sv[0]->texture->width0,
1428 sv[0]->texture->height0 << half_h,
1429 *src_rect, dst_rect);
1432 void
1433 vl_compositor_set_palette_layer(struct vl_compositor *c,
1434 unsigned layer,
1435 struct pipe_sampler_view *indexes,
1436 struct pipe_sampler_view *palette,
1437 struct pipe_video_rect *src_rect,
1438 struct pipe_video_rect *dst_rect,
1439 bool include_color_conversion)
1441 assert(c && indexes && palette);
1442 int i;
1444 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
1446 c->used_layers |= 1 << layer;
1448 c->layers[layer].fs = include_color_conversion ?
1449 c->fs_palette.yuv : c->fs_palette.rgb;
1451 c->layers[layer].samplers[0] = c->sampler_linear;
1452 c->layers[layer].samplers[1] = c->sampler_nearest;
1453 pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], indexes);
1454 pipe_sampler_view_reference(&c->layers[layer].sampler_views[1], palette);
1455 for (i = 2; i < VL_COMPOSITOR_SAMPLERS; ++i) {
1456 pipe_sampler_view_reference(&c->layers[layer].sampler_views[i], NULL);
1457 c->layers[layer].samplers[i] = NULL;
1459 calc_src_and_dst(&c->layers[layer], indexes->texture->width0, indexes->texture->height0,
1460 src_rect ? *src_rect : default_rect(&c->layers[layer]),
1461 dst_rect);
1464 void
1465 vl_compositor_set_rgba_layer(struct vl_compositor *c,
1466 unsigned layer,
1467 struct pipe_sampler_view *rgba,
1468 struct pipe_video_rect *src_rect,
1469 struct pipe_video_rect *dst_rect)
1471 assert(c && rgba);
1472 int i;
1474 assert(layer < VL_COMPOSITOR_MAX_LAYERS);
1476 c->used_layers |= 1 << layer;
1477 c->layers[layer].fs = c->fs_rgba;
1478 c->layers[layer].samplers[0] = c->sampler_linear;
1479 pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], rgba);
1480 for (i = 1; i < VL_COMPOSITOR_SAMPLERS; ++i) {
1481 pipe_sampler_view_reference(&c->layers[layer].sampler_views[i], NULL);
1482 c->layers[layer].samplers[i] = NULL;
1484 calc_src_and_dst(&c->layers[layer], rgba->texture->width0, rgba->texture->height0,
1485 src_rect ? *src_rect : default_rect(&c->layers[layer]),
1486 dst_rect);
1489 void
1490 vl_compositor_render(struct vl_compositor *c,
1491 struct pipe_surface *dst_surface,
1492 struct pipe_video_rect *dst_area,
1493 struct pipe_video_rect *dst_clip,
1494 bool clear_dirty_area)
1496 struct pipe_scissor_state scissor;
1498 assert(c);
1499 assert(dst_surface);
1501 c->fb_state.width = dst_surface->width;
1502 c->fb_state.height = dst_surface->height;
1503 c->fb_state.cbufs[0] = dst_surface;
1505 if (dst_area) {
1506 c->viewport.scale[0] = dst_area->w;
1507 c->viewport.scale[1] = dst_area->h;
1508 c->viewport.translate[0] = dst_area->x;
1509 c->viewport.translate[1] = dst_area->y;
1510 } else {
1511 c->viewport.scale[0] = dst_surface->width;
1512 c->viewport.scale[1] = dst_surface->height;
1513 c->viewport.translate[0] = 0;
1514 c->viewport.translate[1] = 0;
1517 if (dst_clip) {
1518 scissor.minx = dst_clip->x;
1519 scissor.miny = dst_clip->y;
1520 scissor.maxx = dst_clip->x + dst_clip->w;
1521 scissor.maxy = dst_clip->y + dst_clip->h;
1522 } else {
1523 scissor.minx = 0;
1524 scissor.miny = 0;
1525 scissor.maxx = dst_surface->width;
1526 scissor.maxy = dst_surface->height;
1529 gen_vertex_data(c, dst_surface->width, dst_surface->height);
1531 if (clear_dirty_area && (c->dirty_tl.x < c->dirty_br.x ||
1532 c->dirty_tl.y < c->dirty_br.y)) {
1533 util_clear_render_target(c->pipe, dst_surface, &c->clear_color,
1534 0, 0, dst_surface->width, dst_surface->height);
1535 c->dirty_tl.x = c->dirty_tl.y = 1.0f;
1536 c->dirty_br.x = c->dirty_br.y = 0.0f;
1539 c->pipe->set_scissor_state(c->pipe, &scissor);
1540 c->pipe->set_framebuffer_state(c->pipe, &c->fb_state);
1541 c->pipe->set_viewport_state(c->pipe, &c->viewport);
1542 c->pipe->bind_vs_state(c->pipe, c->vs);
1543 c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf);
1544 c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state);
1545 c->pipe->set_constant_buffer(c->pipe, PIPE_SHADER_FRAGMENT, 0, c->csc_matrix);
1546 c->pipe->bind_rasterizer_state(c->pipe, c->rast);
1548 draw_layers(c, dst_surface->width, dst_surface->height);
1551 bool
1552 vl_compositor_init(struct vl_compositor *c, struct pipe_context *pipe)
1554 csc_matrix csc_matrix;
1556 c->pipe = pipe;
1558 if (!init_pipe_state(c))
1559 return false;
1561 if (!init_shaders(c)) {
1562 cleanup_pipe_state(c);
1563 return false;
1566 if (!init_buffers(c)) {
1567 cleanup_shaders(c);
1568 cleanup_pipe_state(c);
1569 return false;
1572 vl_compositor_clear_layers(c);
1574 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, csc_matrix);
1575 vl_compositor_set_csc_matrix(c, c->csc);
1577 c->clear_color.f[0] = c->clear_color.f[1] = 0.0f;
1578 c->clear_color.f[2] = c->clear_color.f[3] = 0.0f;
1579 vl_compositor_reset_dirty_area(c);
1581 return true;
1584 bool
1585 vl_compositor_init_video(struct vl_compositor *c, struct pipe_context *pipe,
1586 enum pipe_video_chroma_format chroma, unsigned w, unsigned h)
1588 struct pipe_resource templ;
1589 int i;
1590 if (!vl_compositor_init(c, pipe))
1591 return false;
1592 c->video_w = w;
1593 c->video_h = h;
1595 if (USE_BICUBIC)
1596 c->fs_video_buffer[0] = create_frag_shader_bicubic(c);
1597 else
1598 c->fs_video_buffer[0] = create_frag_shader_video_buffer(c);
1599 if (DEBUG_CONTOUR)
1600 c->fs_video_buffer[1] = create_frag_shader_sobel_video(c);
1602 for (i = 0; i < Elements(c->fs_video_buffer); ++i) {
1603 if (i == 1 && !DEBUG_CONTOUR) continue;
1604 if (!c->fs_video_buffer[i]) {
1605 debug_printf("Unable to create YCbCr-to-RGB fragment shader %i.\n", i);
1606 goto fail;
1609 c->fs_weave[0] = create_frag_shader_weave(c, 1, 0);
1610 c->fs_weave[1] = create_frag_shader_weave(c, 0, 1); // interlaced
1611 c->fs_weave[2] = create_frag_shader_weave(c, 0, 0); // progressive
1612 if (DEBUG_CONTOUR) {
1613 c->fs_weave[3] = create_frag_shader_sobel(c, 0);
1614 c->fs_weave[4] = create_frag_shader_sobel(c, 3);
1616 for (i = 0; i < Elements(c->fs_weave); ++i) {
1617 if (!DEBUG_CONTOUR && (i >= 3 && i <= 4)) continue;
1618 if (!c->fs_weave[i]) {
1619 debug_printf("Unable to create weave fragment shaders [%i].\n", i);
1620 goto fail;
1623 memset(&templ, 0, sizeof(templ));
1624 templ.target = PIPE_TEXTURE_2D;
1625 templ.format = PIPE_FORMAT_R8_UNORM;
1626 templ.width0 = w;
1627 templ.height0 = h;
1628 templ.depth0 = 1;
1629 templ.array_size = 1;
1630 templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
1631 templ.usage = PIPE_USAGE_STATIC;
1632 c->video_res[0] = pipe->screen->resource_create(pipe->screen, &templ);
1633 if (!c->video_res[0]) {
1634 debug_printf("Could not create weave temp frame for luma\n");
1635 goto fail;
1638 if (chroma != PIPE_VIDEO_CHROMA_FORMAT_444)
1639 templ.width0 /= 2;
1640 templ.format = PIPE_FORMAT_R8G8_UNORM;
1641 c->video_res[1] = pipe->screen->resource_create(pipe->screen, &templ);
1642 if (!c->video_res[1]) {
1643 debug_printf("Could not create interlaced temp frame for chroma\n");
1644 goto fail;
1647 if (chroma == PIPE_VIDEO_CHROMA_FORMAT_420)
1648 templ.height0 = h / 2;
1649 c->video_res[2] = pipe->screen->resource_create(pipe->screen, &templ);
1650 if (!c->video_res[2]) {
1651 debug_printf("Could not create deinterlaced temp frame for chroma\n");
1652 goto fail;
1655 if (DEBUG_CONTOUR) {
1656 c->video_res[3] = pipe->screen->resource_create(pipe->screen, c->video_res[0]);
1657 if (!c->video_res[3]) {
1658 debug_printf("Could not create sobel temp frame for luma\n");
1659 goto fail;
1661 templ.format = PIPE_FORMAT_R8G8B8A8_UNORM;
1662 c->video_res[4] = pipe->screen->resource_create(pipe->screen, &templ);
1663 if (!c->video_res[4]) {
1664 debug_printf("Could not create sobel temp frame for chroma\n");
1665 goto fail;
1669 if (USE_BICUBIC) {
1670 memset(&templ, 0, sizeof(templ));
1671 templ.target = PIPE_TEXTURE_1D;
1672 templ.format = PIPE_FORMAT_R16G16B16A16_UNORM;
1673 templ.width0 = 256;
1674 templ.height0 = 1;
1675 templ.depth0 = 1;
1676 templ.array_size = 1;
1677 templ.bind = PIPE_BIND_SAMPLER_VIEW;
1678 templ.usage = PIPE_USAGE_STATIC;
1679 c->video_res[5] = pipe->screen->resource_create(pipe->screen, &templ);
1680 if (!c->video_res[5]) {
1681 debug_printf("Could not generate lookup texture\n");
1682 goto fail;
1685 if (c->video_res[5]) {
1686 struct pipe_transfer *buf_transfer;
1687 unsigned short *map = pipe_buffer_map(c->pipe, c->video_res[4],
1688 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
1689 &buf_transfer);
1691 for (i = 0; i < templ.width0; ++i, map += 4) {
1692 float weight[4], h0, h1, g0;
1693 float alpha = (float)i / (float)templ.width0;
1694 float alpha2 = alpha * alpha;
1695 float alpha3 = alpha2 * alpha;
1696 float mul = (float)((sizeof(*map)<<8)-1);
1698 weight[0] = (-alpha3 + 3.f * alpha2 - 3.f * alpha + 1.f) / 6.f;
1699 weight[1] = (3.f * alpha3 - 6.f * alpha2 + 4.f) / 6.f;
1700 weight[2] = (-3.f * alpha3 + 3.f * alpha2 + 3.f * alpha + 1.f) / 6.f;
1701 weight[3] = alpha3 / 6.f;
1702 h0 = 1.f + alpha - weight[1] / (weight[0] + weight[1]);
1703 h1 = 1.f - alpha + weight[3] / (weight[2] + weight[3]);
1704 g0 = weight[0] + weight[1];
1705 map[0] = h0 * mul;
1706 map[1] = h1 * mul;
1707 map[2] = g0 * mul;
1708 map[3] = 0;
1710 pipe_buffer_unmap(c->pipe, buf_transfer);
1713 for (i = 0; i < Elements(c->video_res); ++i) {
1714 struct pipe_sampler_view sv_templ;
1715 struct pipe_surface surf_templ;
1716 if (!c->video_res[i]) continue;
1718 memset(&sv_templ, 0, sizeof(sv_templ));
1719 u_sampler_view_default_template(&sv_templ, c->video_res[i], c->video_res[i]->format);
1720 if (c->video_res[i]->format == PIPE_FORMAT_R8_UNORM)
1721 sv_templ.swizzle_a = sv_templ.swizzle_b = sv_templ.swizzle_g = sv_templ.swizzle_r;
1722 else if (c->video_res[i]->format == PIPE_FORMAT_R8G8_UNORM) {
1723 sv_templ.swizzle_b = PIPE_SWIZZLE_GREEN;
1724 sv_templ.swizzle_g = PIPE_SWIZZLE_RED;
1726 c->video_sv[i] = pipe->create_sampler_view(pipe, c->video_res[i], &sv_templ);
1728 if (!c->video_sv[i]) {
1729 debug_printf("Could not create temp video sampler views\n");
1730 goto fail;
1733 memset(&surf_templ, 0, sizeof(surf_templ));
1734 surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
1735 surf_templ.format = c->video_res[i]->format;
1736 c->video_surf[i] = pipe->create_surface(pipe, c->video_res[i], &surf_templ);
1737 if (!c->video_surf[i]) {
1738 debug_printf("Could not create temp video surface\n");
1739 goto fail;
1743 return true;
1745 fail:
1746 vl_compositor_cleanup(c);
1747 return false;