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