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