vl_compositor.c revision 05a2c182f1410a6c09eba70877311ceaf80c19c5
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[4];
108   struct ureg_src sampler;
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 < 4; ++i)
119      csc[i] = ureg_DECL_constant(shader, i);
120   sampler = ureg_DECL_sampler(shader, 0);
121   texel = ureg_DECL_temporary(shader);
122   fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
123
124   /*
125    * texel = tex(tc, sampler)
126    * fragment = csc * texel
127    */
128   ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
129   for (i = 0; i < 4; ++i)
130      ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
131
132   ureg_release_temporary(shader, texel);
133   ureg_END(shader);
134
135   c->fragment_shader.ycbcr_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
136   if (!c->fragment_shader.ycbcr_2_rgb)
137      return false;
138
139   return true;
140}
141
142static bool
143create_frag_shader_rgb_2_rgb(struct vl_compositor *c)
144{
145   struct ureg_program *shader;
146   struct ureg_src tc;
147   struct ureg_src sampler;
148   struct ureg_dst fragment;
149
150   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
151   if (!shader)
152      return false;
153
154   tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
155   sampler = ureg_DECL_sampler(shader, 0);
156   fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
157
158   /*
159    * fragment = tex(tc, sampler)
160    */
161   ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler);
162   ureg_END(shader);
163
164   c->fragment_shader.rgb_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
165   if (!c->fragment_shader.rgb_2_rgb)
166      return false;
167
168   return true;
169}
170
171static bool
172init_pipe_state(struct vl_compositor *c)
173{
174   struct pipe_sampler_state sampler;
175
176   assert(c);
177
178   c->fb_state.nr_cbufs = 1;
179   c->fb_state.zsbuf = NULL;
180
181   memset(&sampler, 0, sizeof(sampler));
182   sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
183   sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
184   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
185   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
186   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
187   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
188   sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
189   sampler.compare_func = PIPE_FUNC_ALWAYS;
190   sampler.normalized_coords = 1;
191   /*sampler.lod_bias = ;*/
192   /*sampler.min_lod = ;*/
193   /*sampler.max_lod = ;*/
194   /*sampler.border_color[i] = ;*/
195   /*sampler.max_anisotropy = ;*/
196   c->sampler = c->pipe->create_sampler_state(c->pipe, &sampler);
197
198   return true;
199}
200
201static void cleanup_pipe_state(struct vl_compositor *c)
202{
203   assert(c);
204
205   c->pipe->delete_sampler_state(c->pipe, c->sampler);
206}
207
208static bool
209init_shaders(struct vl_compositor *c)
210{
211   assert(c);
212
213   if (!create_vert_shader(c)) {
214      debug_printf("Unable to create vertex shader.\n");
215      return false;
216   }
217   if (!create_frag_shader_ycbcr_2_rgb(c)) {
218      debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
219      return false;
220   }
221   if (!create_frag_shader_rgb_2_rgb(c)) {
222      debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
223      return false;
224   }
225
226   return true;
227}
228
229static void cleanup_shaders(struct vl_compositor *c)
230{
231   assert(c);
232
233   c->pipe->delete_vs_state(c->pipe, c->vertex_shader);
234   c->pipe->delete_fs_state(c->pipe, c->fragment_shader.ycbcr_2_rgb);
235   c->pipe->delete_fs_state(c->pipe, c->fragment_shader.rgb_2_rgb);
236}
237
238static bool
239init_buffers(struct vl_compositor *c)
240{
241   struct fragment_shader_consts fsc;
242   struct pipe_vertex_element vertex_elems[2];
243
244   assert(c);
245
246   /*
247    * Create our vertex buffer and vertex buffer elements
248    */
249   c->vertex_buf.stride = sizeof(struct vertex4f);
250   c->vertex_buf.buffer_offset = 0;
251   /* XXX: Create with DYNAMIC or STREAM */
252   c->vertex_buf.buffer = pipe_buffer_create
253   (
254      c->pipe->screen,
255      PIPE_BIND_VERTEX_BUFFER,
256      PIPE_USAGE_STATIC,
257      sizeof(struct vertex4f) * (VL_COMPOSITOR_MAX_LAYERS + 1) * 4
258   );
259
260   vertex_elems[0].src_offset = 0;
261   vertex_elems[0].instance_divisor = 0;
262   vertex_elems[0].vertex_buffer_index = 0;
263   vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
264   vertex_elems[1].src_offset = sizeof(struct vertex2f);
265   vertex_elems[1].instance_divisor = 0;
266   vertex_elems[1].vertex_buffer_index = 0;
267   vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
268   c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 2, vertex_elems);
269
270   /*
271    * Create our fragment shader's constant buffer
272    * Const buffer contains the color conversion matrix and bias vectors
273    */
274   /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
275   c->fs_const_buf = pipe_buffer_create
276   (
277      c->pipe->screen,
278      PIPE_BIND_CONSTANT_BUFFER,
279      PIPE_USAGE_STATIC,
280      sizeof(struct fragment_shader_consts)
281   );
282
283   vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, fsc.matrix);
284
285   vl_compositor_set_csc_matrix(c, fsc.matrix);
286
287   return true;
288}
289
290static void
291cleanup_buffers(struct vl_compositor *c)
292{
293   assert(c);
294
295   c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
296   pipe_resource_reference(&c->vertex_buf.buffer, NULL);
297   pipe_resource_reference(&c->fs_const_buf, NULL);
298}
299
300bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe)
301{
302   unsigned i;
303
304   assert(compositor);
305
306   memset(compositor, 0, sizeof(struct vl_compositor));
307
308   compositor->pipe = pipe;
309
310   if (!init_pipe_state(compositor))
311      return false;
312
313   if (!init_shaders(compositor)) {
314      cleanup_pipe_state(compositor);
315      return false;
316   }
317   if (!init_buffers(compositor)) {
318      cleanup_shaders(compositor);
319      cleanup_pipe_state(compositor);
320      return false;
321   }
322
323   compositor->fb_state.width = 0;
324   compositor->fb_state.height = 0;
325   for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
326      compositor->layers[i] = NULL;
327   compositor->dirty_layers = 0;
328
329   return true;
330}
331
332void vl_compositor_cleanup(struct vl_compositor *compositor)
333{
334   assert(compositor);
335
336   cleanup_buffers(compositor);
337   cleanup_shaders(compositor);
338   cleanup_pipe_state(compositor);
339}
340
341void vl_compositor_set_layers(struct vl_compositor *compositor,
342                              struct pipe_sampler_view *layers[],
343                              struct pipe_video_rect *src_rects[],
344                              struct pipe_video_rect *dst_rects[],
345                              unsigned num_layers)
346{
347   unsigned i;
348
349   assert(compositor);
350   assert(num_layers <= VL_COMPOSITOR_MAX_LAYERS);
351
352   for (i = 0; i < num_layers; ++i)
353   {
354      assert((layers[i] && src_rects[i] && dst_rects[i]) ||
355             (!layers[i] && !src_rects[i] && !dst_rects[i]));
356
357      if (compositor->layers[i] != layers[i] ||
358          !u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]) ||
359          !u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))
360      {
361         pipe_sampler_view_reference(&compositor->layers[i], layers[i]);
362         compositor->layer_src_rects[i] = *src_rects[i];
363         compositor->layer_dst_rects[i] = *dst_rects[i];
364         compositor->dirty_layers |= 1 << i;
365      }
366
367      if (layers[i])
368         compositor->dirty_layers |= 1 << i;
369   }
370
371   for (; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
372      pipe_sampler_view_reference(&compositor->layers[i], NULL);
373}
374
375static void gen_rect_verts(unsigned pos,
376                           struct pipe_video_rect *src_rect,
377                           struct vertex2f *src_inv_size,
378                           struct pipe_video_rect *dst_rect,
379                           struct vertex2f *dst_inv_size,
380                           struct vertex4f *vb)
381{
382   assert(pos < VL_COMPOSITOR_MAX_LAYERS + 1);
383   assert(src_rect);
384   assert(src_inv_size);
385   assert((dst_rect && dst_inv_size) /*|| (!dst_rect && !dst_inv_size)*/);
386   assert(vb);
387
388   vb += pos * 4;
389
390   vb[0].x = dst_rect->x * dst_inv_size->x;
391   vb[0].y = dst_rect->y * dst_inv_size->y;
392   vb[0].z = src_rect->x * src_inv_size->x;
393   vb[0].w = src_rect->y * src_inv_size->y;
394
395   vb[1].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
396   vb[1].y = dst_rect->y * dst_inv_size->y;
397   vb[1].z = (src_rect->x + src_rect->w) * src_inv_size->x;
398   vb[1].w = src_rect->y * src_inv_size->y;
399
400   vb[2].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
401   vb[2].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
402   vb[2].z = (src_rect->x + src_rect->w) * src_inv_size->x;
403   vb[2].w = (src_rect->y + src_rect->h) * src_inv_size->y;
404
405   vb[3].x = dst_rect->x * dst_inv_size->x;
406   vb[3].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
407   vb[3].z = src_rect->x * src_inv_size->x;
408   vb[3].w = (src_rect->y + src_rect->h) * src_inv_size->y;
409}
410
411static unsigned gen_data(struct vl_compositor *c,
412                         struct pipe_sampler_view *src_surface,
413                         struct pipe_video_rect *src_rect,
414                         struct pipe_video_rect *dst_rect,
415                         struct pipe_sampler_view **textures,
416                         void **frag_shaders)
417{
418   void *vb;
419   struct pipe_transfer *buf_transfer;
420   unsigned num_rects = 0;
421   unsigned i;
422
423   assert(c);
424   assert(src_surface);
425   assert(src_rect);
426   assert(dst_rect);
427   assert(textures);
428
429   vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
430                        PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
431                        &buf_transfer);
432
433   if (!vb)
434      return 0;
435
436   {
437      struct vertex2f src_inv_size = { 1.0f / src_surface->texture->width0, 1.0f / src_surface->texture->height0};
438      gen_rect_verts(num_rects, src_rect, &src_inv_size, dst_rect, &c->fb_inv_size, vb);
439      textures[num_rects] = src_surface;
440      /* XXX: Hack, sort of */
441      frag_shaders[num_rects] = c->fragment_shader.ycbcr_2_rgb;
442      ++num_rects;
443   }
444
445   for (i = 0; c->dirty_layers > 0; i++) {
446      assert(i < VL_COMPOSITOR_MAX_LAYERS);
447
448      if (c->dirty_layers & (1 << i)) {
449         struct vertex2f layer_inv_size = {1.0f / c->layers[i]->texture->width0, 1.0f / c->layers[i]->texture->height0};
450         gen_rect_verts(num_rects, &c->layer_src_rects[i], &layer_inv_size,
451                        &c->layer_dst_rects[i], &c->fb_inv_size, vb);
452         textures[num_rects] = c->layers[i];
453         /* XXX: Hack */
454         frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
455         ++num_rects;
456         c->dirty_layers &= ~(1 << i);
457      }
458   }
459
460   pipe_buffer_unmap(c->pipe, buf_transfer);
461
462   return num_rects;
463}
464
465static void draw_layers(struct vl_compositor *c,
466                        struct pipe_sampler_view *src_surface,
467                        struct pipe_video_rect *src_rect,
468                        struct pipe_video_rect *dst_rect)
469{
470   unsigned num_rects;
471   struct pipe_sampler_view *src_surfaces[VL_COMPOSITOR_MAX_LAYERS + 1];
472   void *frag_shaders[VL_COMPOSITOR_MAX_LAYERS + 1];
473   unsigned i;
474
475   assert(c);
476   assert(src_surface);
477   assert(src_rect);
478   assert(dst_rect);
479
480   num_rects = gen_data(c, src_surface, src_rect, dst_rect, src_surfaces, frag_shaders);
481
482   for (i = 0; i < num_rects; ++i) {
483      c->pipe->bind_fs_state(c->pipe, frag_shaders[i]);
484      c->pipe->set_fragment_sampler_views(c->pipe, 1, &src_surfaces[i]);
485
486      util_draw_arrays(c->pipe, PIPE_PRIM_QUADS, i * 4, 4);
487   }
488}
489
490void vl_compositor_render(struct vl_compositor          *compositor,
491                          struct pipe_sampler_view      *src_surface,
492                          enum pipe_mpeg12_picture_type picture_type,
493                          struct pipe_video_rect        *src_area,
494                          struct pipe_surface           *dst_surface,
495                          struct pipe_video_rect        *dst_area,
496                          struct pipe_fence_handle      **fence)
497{
498   assert(compositor);
499   assert(src_surface);
500   assert(src_area);
501   assert(dst_surface);
502   assert(dst_area);
503   assert(picture_type == PIPE_MPEG12_PICTURE_TYPE_FRAME);
504
505   if (compositor->fb_state.width != dst_surface->width) {
506      compositor->fb_inv_size.x = 1.0f / dst_surface->width;
507      compositor->fb_state.width = dst_surface->width;
508   }
509   if (compositor->fb_state.height != dst_surface->height) {
510      compositor->fb_inv_size.y = 1.0f / dst_surface->height;
511      compositor->fb_state.height = dst_surface->height;
512   }
513
514   compositor->fb_state.cbufs[0] = dst_surface;
515
516   compositor->viewport.scale[0] = compositor->fb_state.width;
517   compositor->viewport.scale[1] = compositor->fb_state.height;
518   compositor->viewport.scale[2] = 1;
519   compositor->viewport.scale[3] = 1;
520   compositor->viewport.translate[0] = 0;
521   compositor->viewport.translate[1] = 0;
522   compositor->viewport.translate[2] = 0;
523   compositor->viewport.translate[3] = 0;
524
525   compositor->pipe->set_framebuffer_state(compositor->pipe, &compositor->fb_state);
526   compositor->pipe->set_viewport_state(compositor->pipe, &compositor->viewport);
527   compositor->pipe->bind_fragment_sampler_states(compositor->pipe, 1, &compositor->sampler);
528   compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader);
529   compositor->pipe->set_vertex_buffers(compositor->pipe, 1, &compositor->vertex_buf);
530   compositor->pipe->bind_vertex_elements_state(compositor->pipe, compositor->vertex_elems_state);
531   compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, compositor->fs_const_buf);
532
533   draw_layers(compositor, src_surface, src_area, dst_area);
534
535   assert(!compositor->dirty_layers);
536   compositor->pipe->flush(compositor->pipe, fence);
537}
538
539void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat)
540{
541   struct pipe_transfer *buf_transfer;
542
543   assert(compositor);
544
545   memcpy
546   (
547      pipe_buffer_map(compositor->pipe, compositor->fs_const_buf,
548                      PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
549                      &buf_transfer),
550		mat,
551		sizeof(struct fragment_shader_consts)
552   );
553
554   pipe_buffer_unmap(compositor->pipe, buf_transfer);
555}
556