vl_compositor.c revision 1f3a85ec7931c5d67fce0ec1e845d6c91048e599
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 "vl_compositor.h"
29#include "util/u_draw.h"
30#include <assert.h>
31#include <pipe/p_context.h>
32#include <util/u_inlines.h>
33#include <util/u_memory.h>
34#include <util/u_keymap.h>
35#include <util/u_draw.h>
36#include <util/u_sampler.h>
37#include <tgsi/tgsi_ureg.h>
38#include "vl_csc.h"
39
40struct vertex_shader_consts
41{
42   struct vertex4f dst_scale;
43   struct vertex4f dst_trans;
44   struct vertex4f src_scale;
45   struct vertex4f src_trans;
46};
47
48struct fragment_shader_consts
49{
50   float matrix[16];
51};
52
53static bool
54u_video_rects_equal(struct pipe_video_rect *a, struct pipe_video_rect *b)
55{
56   assert(a && b);
57
58   if (a->x != b->x)
59      return false;
60   if (a->y != b->y)
61      return false;
62   if (a->w != b->w)
63      return false;
64   if (a->h != b->h)
65      return false;
66
67   return true;
68}
69
70static bool
71create_vert_shader(struct vl_compositor *c)
72{
73   struct ureg_program *shader;
74   struct ureg_src vpos, vtex;
75   struct ureg_dst o_vpos, o_vtex;
76
77   shader = ureg_create(TGSI_PROCESSOR_VERTEX);
78   if (!shader)
79      return false;
80
81   vpos = ureg_DECL_vs_input(shader, 0);
82   vtex = ureg_DECL_vs_input(shader, 1);
83   o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0);
84   o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, 1);
85
86   /*
87    * o_vpos = vpos
88    * o_vtex = vtex
89    */
90   ureg_MOV(shader, o_vpos, vpos);
91   ureg_MOV(shader, o_vtex, vtex);
92
93   ureg_END(shader);
94
95   c->vertex_shader = ureg_create_shader_and_destroy(shader, c->pipe);
96   if (!c->vertex_shader)
97      return false;
98
99   return true;
100}
101
102static bool
103create_frag_shader_ycbcr_2_rgb(struct vl_compositor *c)
104{
105   struct ureg_program *shader;
106   struct ureg_src tc;
107   struct ureg_src csc[3];
108   struct ureg_src sampler[3];
109   struct ureg_dst texel;
110   struct ureg_dst fragment;
111   unsigned i;
112
113   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
114   if (!shader)
115      return false;
116
117   tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
118   for (i = 0; i < 3; ++i) {
119      csc[i] = ureg_DECL_constant(shader, i);
120      sampler[i] = ureg_DECL_sampler(shader, i);
121   }
122   texel = ureg_DECL_temporary(shader);
123   fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
124
125   /*
126    * texel.xyz = tex(tc, sampler[i])
127    * fragment = csc * texel
128    */
129   for (i = 0; i < 3; ++i)
130      ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, tc, sampler[i]);
131
132   ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
133
134   for (i = 0; i < 3; ++i)
135      ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
136
137   ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
138
139   ureg_release_temporary(shader, texel);
140   ureg_END(shader);
141
142   c->fragment_shader.ycbcr_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
143   if (!c->fragment_shader.ycbcr_2_rgb)
144      return false;
145
146   return true;
147}
148
149static bool
150create_frag_shader_palette_2_rgb(struct vl_compositor *c)
151{
152   struct ureg_program *shader;
153   struct ureg_src tc;
154   struct ureg_src sampler;
155   struct ureg_src palette;
156   struct ureg_dst texel;
157   struct ureg_dst fragment;
158
159   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
160   if (!shader)
161      return false;
162
163   tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
164   sampler = ureg_DECL_sampler(shader, 0);
165   palette = ureg_DECL_sampler(shader, 1);
166   fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
167   texel = ureg_DECL_temporary(shader);
168
169   /*
170    * fragment = tex(tc, sampler)
171    */
172   ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
173   ureg_TEX(shader, fragment, TGSI_TEXTURE_1D, ureg_src(texel), palette);
174   ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(texel));
175
176   ureg_release_temporary(shader, texel);
177   ureg_END(shader);
178
179   c->fragment_shader.palette_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
180   if (!c->fragment_shader.palette_2_rgb)
181      return false;
182
183   return true;
184}
185
186static bool
187create_frag_shader_rgb_2_rgb(struct vl_compositor *c)
188{
189   struct ureg_program *shader;
190   struct ureg_src tc;
191   struct ureg_src sampler;
192   struct ureg_dst fragment;
193
194   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
195   if (!shader)
196      return false;
197
198   tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
199   sampler = ureg_DECL_sampler(shader, 0);
200   fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
201
202   /*
203    * fragment = tex(tc, sampler)
204    */
205   ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler);
206   ureg_END(shader);
207
208   c->fragment_shader.rgb_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
209   if (!c->fragment_shader.rgb_2_rgb)
210      return false;
211
212   return true;
213}
214
215static bool
216init_pipe_state(struct vl_compositor *c)
217{
218   struct pipe_sampler_state sampler;
219   struct pipe_blend_state blend;
220
221   assert(c);
222
223   c->fb_state.nr_cbufs = 1;
224   c->fb_state.zsbuf = NULL;
225
226   memset(&sampler, 0, sizeof(sampler));
227   sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
228   sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
229   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
230   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
231   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
232   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
233   sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
234   sampler.compare_func = PIPE_FUNC_ALWAYS;
235   sampler.normalized_coords = 1;
236   /*sampler.lod_bias = ;*/
237   /*sampler.min_lod = ;*/
238   /*sampler.max_lod = ;*/
239   /*sampler.border_color[i] = ;*/
240   /*sampler.max_anisotropy = ;*/
241   c->sampler = c->pipe->create_sampler_state(c->pipe, &sampler);
242
243   memset(&blend, 0, sizeof blend);
244   blend.independent_blend_enable = 0;
245   blend.rt[0].blend_enable = 1;
246   blend.rt[0].rgb_func = PIPE_BLEND_ADD;
247   blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
248   blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
249   blend.rt[0].alpha_func = PIPE_BLEND_ADD;
250   blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
251   blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
252   blend.logicop_enable = 0;
253   blend.logicop_func = PIPE_LOGICOP_CLEAR;
254   blend.rt[0].colormask = PIPE_MASK_RGBA;
255   blend.dither = 0;
256   c->blend = c->pipe->create_blend_state(c->pipe, &blend);
257
258   return true;
259}
260
261static void cleanup_pipe_state(struct vl_compositor *c)
262{
263   assert(c);
264
265   c->pipe->delete_sampler_state(c->pipe, c->sampler);
266   c->pipe->delete_blend_state(c->pipe, c->blend);
267}
268
269static bool
270init_shaders(struct vl_compositor *c)
271{
272   assert(c);
273
274   if (!create_vert_shader(c)) {
275      debug_printf("Unable to create vertex shader.\n");
276      return false;
277   }
278   if (!create_frag_shader_ycbcr_2_rgb(c)) {
279      debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
280      return false;
281   }
282   if (!create_frag_shader_palette_2_rgb(c)) {
283      debug_printf("Unable to create Palette-to-RGB fragment shader.\n");
284      return false;
285   }
286   if (!create_frag_shader_rgb_2_rgb(c)) {
287      debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
288      return false;
289   }
290
291   return true;
292}
293
294static void cleanup_shaders(struct vl_compositor *c)
295{
296   assert(c);
297
298   c->pipe->delete_vs_state(c->pipe, c->vertex_shader);
299   c->pipe->delete_fs_state(c->pipe, c->fragment_shader.ycbcr_2_rgb);
300   c->pipe->delete_fs_state(c->pipe, c->fragment_shader.palette_2_rgb);
301   c->pipe->delete_fs_state(c->pipe, c->fragment_shader.rgb_2_rgb);
302}
303
304static bool
305init_buffers(struct vl_compositor *c)
306{
307   struct fragment_shader_consts fsc;
308   struct pipe_vertex_element vertex_elems[2];
309
310   assert(c);
311
312   /*
313    * Create our vertex buffer and vertex buffer elements
314    */
315   c->vertex_buf.stride = sizeof(struct vertex4f);
316   c->vertex_buf.buffer_offset = 0;
317   /* XXX: Create with DYNAMIC or STREAM */
318   c->vertex_buf.buffer = pipe_buffer_create
319   (
320      c->pipe->screen,
321      PIPE_BIND_VERTEX_BUFFER,
322      PIPE_USAGE_STATIC,
323      sizeof(struct vertex4f) * (VL_COMPOSITOR_MAX_LAYERS + 1) * 4
324   );
325
326   vertex_elems[0].src_offset = 0;
327   vertex_elems[0].instance_divisor = 0;
328   vertex_elems[0].vertex_buffer_index = 0;
329   vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
330   vertex_elems[1].src_offset = sizeof(struct vertex2f);
331   vertex_elems[1].instance_divisor = 0;
332   vertex_elems[1].vertex_buffer_index = 0;
333   vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
334   c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 2, vertex_elems);
335
336   /*
337    * Create our fragment shader's constant buffer
338    * Const buffer contains the color conversion matrix and bias vectors
339    */
340   /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
341   c->fs_const_buf = pipe_buffer_create
342   (
343      c->pipe->screen,
344      PIPE_BIND_CONSTANT_BUFFER,
345      PIPE_USAGE_STATIC,
346      sizeof(struct fragment_shader_consts)
347   );
348
349   vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, fsc.matrix);
350
351   vl_compositor_set_csc_matrix(c, fsc.matrix);
352
353   return true;
354}
355
356static void
357cleanup_buffers(struct vl_compositor *c)
358{
359   assert(c);
360
361   c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
362   pipe_resource_reference(&c->vertex_buf.buffer, NULL);
363   pipe_resource_reference(&c->fs_const_buf, NULL);
364}
365
366bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe)
367{
368   unsigned i;
369
370   assert(compositor);
371
372   memset(compositor, 0, sizeof(struct vl_compositor));
373
374   compositor->pipe = pipe;
375
376   if (!init_pipe_state(compositor))
377      return false;
378
379   if (!init_shaders(compositor)) {
380      cleanup_pipe_state(compositor);
381      return false;
382   }
383   if (!init_buffers(compositor)) {
384      cleanup_shaders(compositor);
385      cleanup_pipe_state(compositor);
386      return false;
387   }
388
389   compositor->fb_state.width = 0;
390   compositor->fb_state.height = 0;
391   for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
392      compositor->layers[i] = NULL;
393   compositor->dirty_layers = 0;
394
395   return true;
396}
397
398void vl_compositor_cleanup(struct vl_compositor *compositor)
399{
400   assert(compositor);
401
402   cleanup_buffers(compositor);
403   cleanup_shaders(compositor);
404   cleanup_pipe_state(compositor);
405}
406
407void vl_compositor_set_layers(struct vl_compositor *compositor,
408                              struct pipe_sampler_view *layers[],
409                              struct pipe_sampler_view *palettes[],
410                              struct pipe_video_rect *src_rects[],
411                              struct pipe_video_rect *dst_rects[],
412                              unsigned num_layers)
413{
414   unsigned i;
415
416   assert(compositor);
417   assert(num_layers <= VL_COMPOSITOR_MAX_LAYERS);
418
419   for (i = 0; i < num_layers; ++i)
420   {
421      assert((layers[i] && src_rects[i] && dst_rects[i]) ||
422             (!layers[i] && !src_rects[i] && !dst_rects[i]));
423
424      if (compositor->layers[i] != layers[i] ||
425          compositor->palettes[i] != palettes[i] ||
426          !u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]) ||
427          !u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))
428      {
429         pipe_sampler_view_reference(&compositor->layers[i], layers[i]);
430         pipe_sampler_view_reference(&compositor->palettes[i], palettes[i]);
431         compositor->layer_src_rects[i] = *src_rects[i];
432         compositor->layer_dst_rects[i] = *dst_rects[i];
433         compositor->dirty_layers |= 1 << i;
434      }
435
436      if (layers[i])
437         compositor->dirty_layers |= 1 << i;
438   }
439
440   for (; i < VL_COMPOSITOR_MAX_LAYERS; ++i) {
441      pipe_sampler_view_reference(&compositor->layers[i], NULL);
442      pipe_sampler_view_reference(&compositor->palettes[i], NULL);
443   }
444}
445
446static void gen_rect_verts(struct pipe_video_rect *src_rect,
447                           struct vertex2f *src_inv_size,
448                           struct pipe_video_rect *dst_rect,
449                           struct vertex2f *dst_inv_size,
450                           struct vertex4f *vb)
451{
452   assert(src_rect);
453   assert(src_inv_size);
454   assert((dst_rect && dst_inv_size) /*|| (!dst_rect && !dst_inv_size)*/);
455   assert(vb);
456
457   vb[0].x = dst_rect->x * dst_inv_size->x;
458   vb[0].y = dst_rect->y * dst_inv_size->y;
459   vb[0].z = src_rect->x * src_inv_size->x;
460   vb[0].w = src_rect->y * src_inv_size->y;
461
462   vb[1].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
463   vb[1].y = dst_rect->y * dst_inv_size->y;
464   vb[1].z = (src_rect->x + src_rect->w) * src_inv_size->x;
465   vb[1].w = src_rect->y * src_inv_size->y;
466
467   vb[2].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
468   vb[2].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
469   vb[2].z = (src_rect->x + src_rect->w) * src_inv_size->x;
470   vb[2].w = (src_rect->y + src_rect->h) * src_inv_size->y;
471
472   vb[3].x = dst_rect->x * dst_inv_size->x;
473   vb[3].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
474   vb[3].z = src_rect->x * src_inv_size->x;
475   vb[3].w = (src_rect->y + src_rect->h) * src_inv_size->y;
476}
477
478static unsigned gen_data(struct vl_compositor *c,
479                         struct pipe_sampler_view *src_surface,
480                         struct pipe_video_rect *src_rect,
481                         struct pipe_video_rect *dst_rect,
482                         struct pipe_sampler_view *textures[VL_COMPOSITOR_MAX_LAYERS + 1][2],
483                         void **frag_shaders)
484{
485   struct vertex4f *vb;
486   struct pipe_transfer *buf_transfer;
487   unsigned num_rects = 0;
488   unsigned i;
489
490   assert(c);
491   assert(src_surface);
492   assert(src_rect);
493   assert(dst_rect);
494   assert(textures);
495
496   vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
497                        PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
498                        &buf_transfer);
499
500   if (!vb)
501      return 0;
502
503   {
504      struct vertex2f src_inv_size = { 1.0f / src_surface->texture->width0, 1.0f / src_surface->texture->height0};
505      gen_rect_verts(src_rect, &src_inv_size, dst_rect, &c->fb_inv_size, vb);
506      textures[num_rects][0] = src_surface;
507      textures[num_rects][1] = NULL;
508      /* XXX: Hack, sort of */
509      frag_shaders[num_rects] = c->fragment_shader.ycbcr_2_rgb;
510      ++num_rects;
511      vb += 4;
512   }
513
514   for (i = 0; c->dirty_layers > 0; i++) {
515      assert(i < VL_COMPOSITOR_MAX_LAYERS);
516
517      if (c->dirty_layers & (1 << i)) {
518         struct vertex2f layer_inv_size = {1.0f / c->layers[i]->texture->width0, 1.0f / c->layers[i]->texture->height0};
519         gen_rect_verts(&c->layer_src_rects[i], &layer_inv_size, &c->layer_dst_rects[i], &layer_inv_size, vb);
520         textures[num_rects][0] = c->layers[i];
521         textures[num_rects][1] = c->palettes[i];
522
523         if (c->palettes[i])
524            frag_shaders[num_rects] = c->fragment_shader.palette_2_rgb;
525         else
526            frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
527
528         ++num_rects;
529         vb += 4;
530         c->dirty_layers &= ~(1 << i);
531      }
532   }
533
534   pipe_buffer_unmap(c->pipe, buf_transfer);
535
536   return num_rects;
537}
538
539static void draw_layers(struct vl_compositor *c,
540                        struct vl_ycbcr_sampler_views *src_sampler,
541                        struct pipe_video_rect *src_rect,
542                        struct pipe_video_rect *dst_rect)
543{
544   unsigned num_rects;
545   struct pipe_sampler_view *surfaces[VL_COMPOSITOR_MAX_LAYERS + 1][2];
546   void *frag_shaders[VL_COMPOSITOR_MAX_LAYERS + 1];
547   unsigned i;
548
549   assert(c);
550   assert(src_sampler);
551   assert(src_rect);
552   assert(dst_rect);
553
554   num_rects = gen_data(c, src_sampler->y, src_rect, dst_rect, surfaces, frag_shaders);
555
556   c->pipe->bind_blend_state(c->pipe, c->blend);
557   for (i = 0; i < num_rects; ++i) {
558      c->pipe->bind_fs_state(c->pipe, frag_shaders[i]);
559      if (i == 0) {
560         c->pipe->set_fragment_sampler_views(c->pipe, 3, &src_sampler->y);
561      } else {
562         c->pipe->set_fragment_sampler_views(c->pipe, surfaces[i][1] ? 2 : 1, &surfaces[i][0]);
563      }
564
565      util_draw_arrays(c->pipe, PIPE_PRIM_QUADS, i * 4, 4);
566   }
567}
568
569void vl_compositor_render(struct vl_compositor          *compositor,
570                          struct vl_ycbcr_sampler_views *src_sampler,
571                          struct pipe_video_rect        *src_area,
572                          struct pipe_surface           *dst_surface,
573                          struct pipe_video_rect        *dst_area,
574                          struct pipe_fence_handle      **fence)
575{
576   void *samplers[3];
577
578   assert(compositor);
579   assert(src_sampler);
580   assert(src_area);
581   assert(dst_surface);
582   assert(dst_area);
583
584   if (compositor->fb_state.width != dst_surface->width) {
585      compositor->fb_inv_size.x = 1.0f / dst_surface->width;
586      compositor->fb_state.width = dst_surface->width;
587   }
588   if (compositor->fb_state.height != dst_surface->height) {
589      compositor->fb_inv_size.y = 1.0f / dst_surface->height;
590      compositor->fb_state.height = dst_surface->height;
591   }
592
593   compositor->fb_state.cbufs[0] = dst_surface;
594
595   compositor->viewport.scale[0] = compositor->fb_state.width;
596   compositor->viewport.scale[1] = compositor->fb_state.height;
597   compositor->viewport.scale[2] = 1;
598   compositor->viewport.scale[3] = 1;
599   compositor->viewport.translate[0] = 0;
600   compositor->viewport.translate[1] = 0;
601   compositor->viewport.translate[2] = 0;
602   compositor->viewport.translate[3] = 0;
603
604   samplers[0] = samplers[1] = samplers[2] = compositor->sampler;
605
606   compositor->pipe->set_framebuffer_state(compositor->pipe, &compositor->fb_state);
607   compositor->pipe->set_viewport_state(compositor->pipe, &compositor->viewport);
608   compositor->pipe->bind_fragment_sampler_states(compositor->pipe, 3, &samplers[0]);
609   compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader);
610   compositor->pipe->set_vertex_buffers(compositor->pipe, 1, &compositor->vertex_buf);
611   compositor->pipe->bind_vertex_elements_state(compositor->pipe, compositor->vertex_elems_state);
612   compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, compositor->fs_const_buf);
613
614   draw_layers(compositor, src_sampler, src_area, dst_area);
615
616   assert(!compositor->dirty_layers);
617   compositor->pipe->flush(compositor->pipe, fence);
618}
619
620void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat)
621{
622   struct pipe_transfer *buf_transfer;
623
624   assert(compositor);
625
626   memcpy
627   (
628      pipe_buffer_map(compositor->pipe, compositor->fs_const_buf,
629                      PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
630                      &buf_transfer),
631		mat,
632		sizeof(struct fragment_shader_consts)
633   );
634
635   pipe_buffer_unmap(compositor->pipe, buf_transfer);
636}
637