1 /**************************************************************************
2  *
3  * Copyright 2009 Younes Manton.
4  * All Rights Reserved.
5  *
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:
13  *
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.
17  *
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.
25  *
26  **************************************************************************/
27 
28 #include <assert.h>
29 
30 #include "pipe/p_context.h"
31 
32 #include "util/u_sampler.h"
33 #include "util/u_draw.h"
34 
35 #include "tgsi/tgsi_ureg.h"
36 
37 #include "vl_defines.h"
38 #include "vl_vertex_buffers.h"
39 #include "vl_mc.h"
40 #include "vl_idct.h"
41 
42 enum VS_OUTPUT
43 {
44    VS_O_VPOS = 0,
45    VS_O_VTOP = 0,
46    VS_O_VBOTTOM,
47 
48    VS_O_FLAGS = VS_O_VTOP,
49    VS_O_VTEX = VS_O_VBOTTOM
50 };
51 
52 static struct ureg_dst
calc_position(struct vl_mc * r,struct ureg_program * shader,struct ureg_src block_scale)53 calc_position(struct vl_mc *r, struct ureg_program *shader, struct ureg_src block_scale)
54 {
55    struct ureg_src vrect, vpos;
56    struct ureg_dst t_vpos;
57    struct ureg_dst o_vpos;
58 
59    vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
60    vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
61 
62    t_vpos = ureg_DECL_temporary(shader);
63 
64    o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
65 
66    /*
67     * block_scale = (VL_MACROBLOCK_WIDTH, VL_MACROBLOCK_HEIGHT) / (dst.width, dst.height)
68     *
69     * t_vpos = (vpos + vrect) * block_scale
70     * o_vpos.xy = t_vpos
71     * o_vpos.zw = vpos
72     */
73    ureg_ADD(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), vpos, vrect);
74    ureg_MUL(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos), block_scale);
75    ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos));
76    ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f));
77 
78    return t_vpos;
79 }
80 
81 static struct ureg_dst
calc_line(struct ureg_program * shader)82 calc_line(struct ureg_program *shader)
83 {
84    struct ureg_dst tmp;
85    struct ureg_src pos;
86 
87    tmp = ureg_DECL_temporary(shader);
88 
89    pos = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS, TGSI_INTERPOLATE_LINEAR);
90 
91    /*
92     * tmp.y = fraction(pos.y / 2) >= 0.5 ? 1 : 0
93     */
94    ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.5f));
95    ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp));
96    ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp), ureg_imm1f(shader, 0.5f));
97 
98    return tmp;
99 }
100 
101 static void *
create_ref_vert_shader(struct vl_mc * r)102 create_ref_vert_shader(struct vl_mc *r)
103 {
104    struct ureg_program *shader;
105    struct ureg_src mv_scale;
106    struct ureg_src vmv[2];
107    struct ureg_dst t_vpos;
108    struct ureg_dst o_vmv[2];
109    unsigned i;
110 
111    shader = ureg_create(TGSI_PROCESSOR_VERTEX);
112    if (!shader)
113       return NULL;
114 
115    vmv[0] = ureg_DECL_vs_input(shader, VS_I_MV_TOP);
116    vmv[1] = ureg_DECL_vs_input(shader, VS_I_MV_BOTTOM);
117 
118    t_vpos = calc_position(r, shader, ureg_imm2f(shader,
119       (float)VL_MACROBLOCK_WIDTH / r->buffer_width,
120       (float)VL_MACROBLOCK_HEIGHT / r->buffer_height)
121    );
122 
123    o_vmv[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP);
124    o_vmv[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM);
125 
126    /*
127     * mv_scale.xy = 0.5 / (dst.width, dst.height);
128     * mv_scale.z = 1.0f / 4.0f
129     * mv_scale.w = 1.0f / 255.0f
130     *
131     * // Apply motion vectors
132     * o_vmv[0..1].xy = vmv[0..1] * mv_scale + t_vpos
133     * o_vmv[0..1].zw = vmv[0..1] * mv_scale
134     *
135     */
136 
137    mv_scale = ureg_imm4f(shader,
138       0.5f / r->buffer_width,
139       0.5f / r->buffer_height,
140       1.0f / 4.0f,
141       1.0f / PIPE_VIDEO_MV_WEIGHT_MAX);
142 
143    for (i = 0; i < 2; ++i) {
144       ureg_MAD(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_XY), mv_scale, vmv[i], ureg_src(t_vpos));
145       ureg_MUL(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_ZW), mv_scale, vmv[i]);
146    }
147 
148    ureg_release_temporary(shader, t_vpos);
149 
150    ureg_END(shader);
151 
152    return ureg_create_shader_and_destroy(shader, r->pipe);
153 }
154 
155 static void *
create_ref_frag_shader(struct vl_mc * r)156 create_ref_frag_shader(struct vl_mc *r)
157 {
158    const float y_scale =
159       r->buffer_height / 2 *
160       r->macroblock_size / VL_MACROBLOCK_HEIGHT;
161 
162    struct ureg_program *shader;
163    struct ureg_src tc[2], sampler;
164    struct ureg_dst ref, field;
165    struct ureg_dst fragment;
166    unsigned label;
167 
168    shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
169    if (!shader)
170       return NULL;
171 
172    tc[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP, TGSI_INTERPOLATE_LINEAR);
173    tc[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM, TGSI_INTERPOLATE_LINEAR);
174 
175    sampler = ureg_DECL_sampler(shader, 0);
176    ref = ureg_DECL_temporary(shader);
177 
178    fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
179 
180    field = calc_line(shader);
181 
182    /*
183     * ref = field.z ? tc[1] : tc[0]
184     *
185     * // Adjust tc acording to top/bottom field selection
186     * if (|ref.z|) {
187     *    ref.y *= y_scale
188     *    ref.y = floor(ref.y)
189     *    ref.y += ref.z
190     *    ref.y /= y_scale
191     * }
192     * fragment.xyz = tex(ref, sampler[0])
193     */
194    ureg_CMP(shader, ureg_writemask(ref, TGSI_WRITEMASK_XYZ),
195             ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
196             tc[1], tc[0]);
197    ureg_CMP(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W),
198             ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
199             tc[1], tc[0]);
200 
201    ureg_IF(shader, ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z), &label);
202 
203       ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
204                ureg_src(ref), ureg_imm1f(shader, y_scale));
205       ureg_FLR(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), ureg_src(ref));
206       ureg_ADD(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
207                ureg_src(ref), ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z));
208       ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
209                ureg_src(ref), ureg_imm1f(shader, 1.0f / y_scale));
210 
211    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
212    ureg_ENDIF(shader);
213 
214    ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), TGSI_TEXTURE_2D, ureg_src(ref), sampler);
215 
216    ureg_release_temporary(shader, ref);
217 
218    ureg_release_temporary(shader, field);
219    ureg_END(shader);
220 
221    return ureg_create_shader_and_destroy(shader, r->pipe);
222 }
223 
224 static void *
create_ycbcr_vert_shader(struct vl_mc * r,vl_mc_ycbcr_vert_shader vs_callback,void * callback_priv)225 create_ycbcr_vert_shader(struct vl_mc *r, vl_mc_ycbcr_vert_shader vs_callback, void *callback_priv)
226 {
227    struct ureg_program *shader;
228 
229    struct ureg_src vrect, vpos;
230    struct ureg_dst t_vpos, t_vtex;
231    struct ureg_dst o_vpos, o_flags;
232 
233    struct vertex2f scale = {
234       (float)VL_BLOCK_WIDTH / r->buffer_width * VL_MACROBLOCK_WIDTH / r->macroblock_size,
235       (float)VL_BLOCK_HEIGHT / r->buffer_height * VL_MACROBLOCK_HEIGHT / r->macroblock_size
236    };
237 
238    unsigned label;
239 
240    shader = ureg_create(TGSI_PROCESSOR_VERTEX);
241    if (!shader)
242       return NULL;
243 
244    vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
245    vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
246 
247    t_vpos = calc_position(r, shader, ureg_imm2f(shader, scale.x, scale.y));
248    t_vtex = ureg_DECL_temporary(shader);
249 
250    o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
251    o_flags = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS);
252 
253    /*
254     * o_vtex.xy = t_vpos
255     * o_flags.z = intra * 0.5
256     *
257     * if(interlaced) {
258     *    t_vtex.xy = vrect.y ? { 0, scale.y } : { -scale.y : 0 }
259     *    t_vtex.z = vpos.y % 2
260     *    t_vtex.y = t_vtex.z ? t_vtex.x : t_vtex.y
261     *    o_vpos.y = t_vtex.y + t_vpos.y
262     *
263     *    o_flags.w = t_vtex.z ? 0 : 1
264     * }
265     *
266     */
267 
268    vs_callback(callback_priv, r, shader, VS_O_VTEX, t_vpos);
269 
270    ureg_MUL(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_Z),
271             ureg_scalar(vpos, TGSI_SWIZZLE_Z), ureg_imm1f(shader, 0.5f));
272    ureg_MOV(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W), ureg_imm1f(shader, -1.0f));
273 
274    if (r->macroblock_size == VL_MACROBLOCK_HEIGHT) { //TODO
275       ureg_IF(shader, ureg_scalar(vpos, TGSI_SWIZZLE_W), &label);
276 
277          ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_XY),
278                   ureg_negate(ureg_scalar(vrect, TGSI_SWIZZLE_Y)),
279                   ureg_imm2f(shader, 0.0f, scale.y),
280                   ureg_imm2f(shader, -scale.y, 0.0f));
281          ureg_MUL(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z),
282                   ureg_scalar(vpos, TGSI_SWIZZLE_Y), ureg_imm1f(shader, 0.5f));
283 
284          ureg_FRC(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z), ureg_src(t_vtex));
285 
286          ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Y),
287                   ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
288                   ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_X),
289                   ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Y));
290          ureg_ADD(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_Y),
291                   ureg_src(t_vpos), ureg_src(t_vtex));
292 
293          ureg_CMP(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W),
294                   ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
295                   ureg_imm1f(shader, 0.0f), ureg_imm1f(shader, 1.0f));
296 
297       ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
298       ureg_ENDIF(shader);
299    }
300 
301    ureg_release_temporary(shader, t_vtex);
302    ureg_release_temporary(shader, t_vpos);
303 
304    ureg_END(shader);
305 
306    return ureg_create_shader_and_destroy(shader, r->pipe);
307 }
308 
309 static void *
create_ycbcr_frag_shader(struct vl_mc * r,float scale,bool invert,vl_mc_ycbcr_frag_shader fs_callback,void * callback_priv)310 create_ycbcr_frag_shader(struct vl_mc *r, float scale, bool invert,
311                          vl_mc_ycbcr_frag_shader fs_callback, void *callback_priv)
312 {
313    struct ureg_program *shader;
314    struct ureg_src flags;
315    struct ureg_dst tmp;
316    struct ureg_dst fragment;
317    unsigned label;
318 
319    shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
320    if (!shader)
321       return NULL;
322 
323    flags = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS, TGSI_INTERPOLATE_LINEAR);
324 
325    fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
326 
327    tmp = calc_line(shader);
328 
329    /*
330     * if (field == tc.w)
331     *    kill();
332     * else {
333     *    fragment.xyz  = tex(tc, sampler) * scale + tc.z
334     *    fragment.w = 1.0f
335     * }
336     */
337 
338    ureg_SEQ(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y),
339             ureg_scalar(flags, TGSI_SWIZZLE_W), ureg_src(tmp));
340 
341    ureg_IF(shader, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), &label);
342 
343       ureg_KILP(shader);
344 
345    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
346    ureg_ELSE(shader, &label);
347 
348       fs_callback(callback_priv, r, shader, VS_O_VTEX, tmp);
349 
350       if (scale != 1.0f)
351          ureg_MAD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
352                   ureg_src(tmp), ureg_imm1f(shader, scale),
353                   ureg_scalar(flags, TGSI_SWIZZLE_Z));
354       else
355          ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
356                   ureg_src(tmp), ureg_scalar(flags, TGSI_SWIZZLE_Z));
357 
358       ureg_MUL(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(tmp), ureg_imm1f(shader, invert ? -1.0f : 1.0f));
359       ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
360 
361    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
362    ureg_ENDIF(shader);
363 
364    ureg_release_temporary(shader, tmp);
365 
366    ureg_END(shader);
367 
368    return ureg_create_shader_and_destroy(shader, r->pipe);
369 }
370 
371 static bool
init_pipe_state(struct vl_mc * r)372 init_pipe_state(struct vl_mc *r)
373 {
374    struct pipe_sampler_state sampler;
375    struct pipe_blend_state blend;
376    struct pipe_rasterizer_state rs_state;
377    unsigned i;
378 
379    assert(r);
380 
381    memset(&sampler, 0, sizeof(sampler));
382    sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
383    sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
384    sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
385    sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
386    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
387    sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
388    sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
389    sampler.compare_func = PIPE_FUNC_ALWAYS;
390    sampler.normalized_coords = 1;
391    r->sampler_ref = r->pipe->create_sampler_state(r->pipe, &sampler);
392    if (!r->sampler_ref)
393       goto error_sampler_ref;
394 
395    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
396       memset(&blend, 0, sizeof blend);
397       blend.independent_blend_enable = 0;
398       blend.rt[0].blend_enable = 1;
399       blend.rt[0].rgb_func = PIPE_BLEND_ADD;
400       blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
401       blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
402       blend.rt[0].alpha_func = PIPE_BLEND_ADD;
403       blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
404       blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
405       blend.logicop_enable = 0;
406       blend.logicop_func = PIPE_LOGICOP_CLEAR;
407       blend.rt[0].colormask = i;
408       blend.dither = 0;
409       r->blend_clear[i] = r->pipe->create_blend_state(r->pipe, &blend);
410       if (!r->blend_clear[i])
411          goto error_blend;
412 
413       blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
414       blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
415       r->blend_add[i] = r->pipe->create_blend_state(r->pipe, &blend);
416       if (!r->blend_add[i])
417          goto error_blend;
418 
419       blend.rt[0].rgb_func = PIPE_BLEND_REVERSE_SUBTRACT;
420       blend.rt[0].alpha_dst_factor = PIPE_BLEND_REVERSE_SUBTRACT;
421       r->blend_sub[i] = r->pipe->create_blend_state(r->pipe, &blend);
422       if (!r->blend_sub[i])
423          goto error_blend;
424    }
425 
426    memset(&rs_state, 0, sizeof(rs_state));
427    /*rs_state.sprite_coord_enable */
428    rs_state.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
429    rs_state.point_quad_rasterization = true;
430    rs_state.point_size = VL_BLOCK_WIDTH;
431    rs_state.gl_rasterization_rules = true;
432    rs_state.depth_clip = 1;
433    r->rs_state = r->pipe->create_rasterizer_state(r->pipe, &rs_state);
434    if (!r->rs_state)
435       goto error_rs_state;
436 
437    return true;
438 
439 error_rs_state:
440 error_blend:
441    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
442       if (r->blend_sub[i])
443          r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
444 
445       if (r->blend_add[i])
446          r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
447 
448       if (r->blend_clear[i])
449          r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
450    }
451 
452    r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
453 
454 error_sampler_ref:
455    return false;
456 }
457 
458 static void
cleanup_pipe_state(struct vl_mc * r)459 cleanup_pipe_state(struct vl_mc *r)
460 {
461    unsigned i;
462 
463    assert(r);
464 
465    r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
466    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
467       r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
468       r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
469       r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
470    }
471    r->pipe->delete_rasterizer_state(r->pipe, r->rs_state);
472 }
473 
474 bool
vl_mc_init(struct vl_mc * renderer,struct pipe_context * pipe,unsigned buffer_width,unsigned buffer_height,unsigned macroblock_size,float scale,vl_mc_ycbcr_vert_shader vs_callback,vl_mc_ycbcr_frag_shader fs_callback,void * callback_priv)475 vl_mc_init(struct vl_mc *renderer, struct pipe_context *pipe,
476            unsigned buffer_width, unsigned buffer_height,
477            unsigned macroblock_size, float scale,
478            vl_mc_ycbcr_vert_shader vs_callback,
479            vl_mc_ycbcr_frag_shader fs_callback,
480            void *callback_priv)
481 {
482    assert(renderer);
483    assert(pipe);
484 
485    memset(renderer, 0, sizeof(struct vl_mc));
486 
487    renderer->pipe = pipe;
488    renderer->buffer_width = buffer_width;
489    renderer->buffer_height = buffer_height;
490    renderer->macroblock_size = macroblock_size;
491 
492    if (!init_pipe_state(renderer))
493       goto error_pipe_state;
494 
495    renderer->vs_ref = create_ref_vert_shader(renderer);
496    if (!renderer->vs_ref)
497       goto error_vs_ref;
498 
499    renderer->vs_ycbcr = create_ycbcr_vert_shader(renderer, vs_callback, callback_priv);
500    if (!renderer->vs_ycbcr)
501       goto error_vs_ycbcr;
502 
503    renderer->fs_ref = create_ref_frag_shader(renderer);
504    if (!renderer->fs_ref)
505       goto error_fs_ref;
506 
507    renderer->fs_ycbcr = create_ycbcr_frag_shader(renderer, scale, false, fs_callback, callback_priv);
508    if (!renderer->fs_ycbcr)
509       goto error_fs_ycbcr;
510 
511    renderer->fs_ycbcr_sub = create_ycbcr_frag_shader(renderer, scale, true, fs_callback, callback_priv);
512    if (!renderer->fs_ycbcr_sub)
513       goto error_fs_ycbcr_sub;
514 
515    return true;
516 
517 error_fs_ycbcr_sub:
518    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
519 
520 error_fs_ycbcr:
521    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
522 
523 error_fs_ref:
524    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
525 
526 error_vs_ycbcr:
527    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
528 
529 error_vs_ref:
530    cleanup_pipe_state(renderer);
531 
532 error_pipe_state:
533    return false;
534 }
535 
536 void
vl_mc_cleanup(struct vl_mc * renderer)537 vl_mc_cleanup(struct vl_mc *renderer)
538 {
539    assert(renderer);
540 
541    cleanup_pipe_state(renderer);
542 
543    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
544    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
545    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
546    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
547    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
548 }
549 
550 bool
vl_mc_init_buffer(struct vl_mc * renderer,struct vl_mc_buffer * buffer)551 vl_mc_init_buffer(struct vl_mc *renderer, struct vl_mc_buffer *buffer)
552 {
553    assert(renderer && buffer);
554 
555    buffer->viewport.scale[2] = 1;
556    buffer->viewport.scale[3] = 1;
557    buffer->viewport.translate[0] = 0;
558    buffer->viewport.translate[1] = 0;
559    buffer->viewport.translate[2] = 0;
560    buffer->viewport.translate[3] = 0;
561 
562    buffer->fb_state.nr_cbufs = 1;
563    buffer->fb_state.zsbuf = NULL;
564 
565    return true;
566 }
567 
568 void
vl_mc_cleanup_buffer(struct vl_mc_buffer * buffer)569 vl_mc_cleanup_buffer(struct vl_mc_buffer *buffer)
570 {
571    assert(buffer);
572 }
573 
574 void
vl_mc_set_surface(struct vl_mc_buffer * buffer,struct pipe_surface * surface)575 vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface)
576 {
577    assert(buffer && surface);
578 
579    buffer->surface_cleared = false;
580 
581    buffer->viewport.scale[0] = surface->width;
582    buffer->viewport.scale[1] = surface->height;
583 
584    buffer->fb_state.width = surface->width;
585    buffer->fb_state.height = surface->height;
586    buffer->fb_state.cbufs[0] = surface;
587 }
588 
589 static void
prepare_pipe_4_rendering(struct vl_mc * renderer,struct vl_mc_buffer * buffer,unsigned mask)590 prepare_pipe_4_rendering(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned mask)
591 {
592    assert(buffer);
593 
594    renderer->pipe->bind_rasterizer_state(renderer->pipe, renderer->rs_state);
595 
596    if (buffer->surface_cleared)
597       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_add[mask]);
598    else
599       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_clear[mask]);
600 
601    renderer->pipe->set_framebuffer_state(renderer->pipe, &buffer->fb_state);
602    renderer->pipe->set_viewport_state(renderer->pipe, &buffer->viewport);
603 }
604 
605 void
vl_mc_render_ref(struct vl_mc * renderer,struct vl_mc_buffer * buffer,struct pipe_sampler_view * ref)606 vl_mc_render_ref(struct vl_mc *renderer, struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref)
607 {
608    assert(buffer && ref);
609 
610    prepare_pipe_4_rendering(renderer, buffer, PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B);
611 
612    renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ref);
613    renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ref);
614 
615    renderer->pipe->set_fragment_sampler_views(renderer->pipe, 1, &ref);
616    renderer->pipe->bind_fragment_sampler_states(renderer->pipe, 1, &renderer->sampler_ref);
617 
618    util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0,
619                               renderer->buffer_width / VL_MACROBLOCK_WIDTH *
620                               renderer->buffer_height / VL_MACROBLOCK_HEIGHT);
621 
622    buffer->surface_cleared = true;
623 }
624 
625 void
vl_mc_render_ycbcr(struct vl_mc * renderer,struct vl_mc_buffer * buffer,unsigned component,unsigned num_instances)626 vl_mc_render_ycbcr(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned component, unsigned num_instances)
627 {
628    unsigned mask = 1 << component;
629 
630    assert(buffer);
631 
632    if (num_instances == 0)
633       return;
634 
635    prepare_pipe_4_rendering(renderer, buffer, mask);
636 
637    renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ycbcr);
638    renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr);
639 
640    util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
641 
642    if (buffer->surface_cleared) {
643       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_sub[mask]);
644       renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
645       util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
646    }
647 }
648