vl_compositor.c revision 133add9c508f9e94e04c45a6cfa3a9dd6a2518d0
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 + 2) * 6 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 341#if 0 342void vl_compositor_set_background(struct vl_compositor *compositor, 343 struct pipe_surface *bg, struct pipe_video_rect *bg_src_rect) 344{ 345 assert(compositor); 346 assert((bg && bg_src_rect) || (!bg && !bg_src_rect)); 347 348 if (compositor->bg != bg || 349 !u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect)) { 350 pipe_surface_reference(&compositor->bg, bg); 351 /*if (!u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect))*/ 352 compositor->bg_src_rect = *bg_src_rect; 353 compositor->dirty_bg = true; 354 } 355} 356#endif 357 358void vl_compositor_set_layers(struct vl_compositor *compositor, 359 struct pipe_sampler_view *layers[], 360 struct pipe_video_rect *src_rects[], 361 struct pipe_video_rect *dst_rects[], 362 unsigned num_layers) 363{ 364 unsigned i; 365 366 assert(compositor); 367 assert(num_layers <= VL_COMPOSITOR_MAX_LAYERS); 368 369 for (i = 0; i < num_layers; ++i) 370 { 371 assert((layers[i] && src_rects[i] && dst_rects[i]) || 372 (!layers[i] && !src_rects[i] && !dst_rects[i])); 373 374 if (compositor->layers[i] != layers[i] || 375 !u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]) || 376 !u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i])) 377 { 378 pipe_sampler_view_reference(&compositor->layers[i], layers[i]); 379 compositor->layer_src_rects[i] = *src_rects[i]; 380 compositor->layer_dst_rects[i] = *dst_rects[i]; 381 compositor->dirty_layers |= 1 << i; 382 } 383 384 if (layers[i]) 385 compositor->dirty_layers |= 1 << i; 386 } 387 388 for (; i < VL_COMPOSITOR_MAX_LAYERS; ++i) 389 pipe_sampler_view_reference(&compositor->layers[i], NULL); 390} 391 392static void gen_rect_verts(unsigned pos, 393 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(pos < VL_COMPOSITOR_MAX_LAYERS + 2); 400 assert(src_rect); 401 assert(src_inv_size); 402 assert((dst_rect && dst_inv_size) /*|| (!dst_rect && !dst_inv_size)*/); 403 assert(vb); 404 405 vb[pos * 6 + 0].x = dst_rect->x * dst_inv_size->x; 406 vb[pos * 6 + 0].y = dst_rect->y * dst_inv_size->y; 407 vb[pos * 6 + 0].z = src_rect->x * src_inv_size->x; 408 vb[pos * 6 + 0].w = src_rect->y * src_inv_size->y; 409 410 vb[pos * 6 + 1].x = dst_rect->x * dst_inv_size->x; 411 vb[pos * 6 + 1].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y; 412 vb[pos * 6 + 1].z = src_rect->x * src_inv_size->x; 413 vb[pos * 6 + 1].w = (src_rect->y + src_rect->h) * src_inv_size->y; 414 415 vb[pos * 6 + 2].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x; 416 vb[pos * 6 + 2].y = dst_rect->y * dst_inv_size->y; 417 vb[pos * 6 + 2].z = (src_rect->x + src_rect->w) * src_inv_size->x; 418 vb[pos * 6 + 2].w = src_rect->y * src_inv_size->y; 419 420 vb[pos * 6 + 3].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x; 421 vb[pos * 6 + 3].y = dst_rect->y * dst_inv_size->y; 422 vb[pos * 6 + 3].z = (src_rect->x + src_rect->w) * src_inv_size->x; 423 vb[pos * 6 + 3].w = src_rect->y * src_inv_size->y; 424 425 vb[pos * 6 + 4].x = dst_rect->x * dst_inv_size->x; 426 vb[pos * 6 + 4].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y; 427 vb[pos * 6 + 4].z = src_rect->x * src_inv_size->x; 428 vb[pos * 6 + 4].w = (src_rect->y + src_rect->h) * src_inv_size->y; 429 430 vb[pos * 6 + 5].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x; 431 vb[pos * 6 + 5].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y; 432 vb[pos * 6 + 5].z = (src_rect->x + src_rect->w) * src_inv_size->x; 433 vb[pos * 6 + 5].w = (src_rect->y + src_rect->h) * src_inv_size->y; 434} 435 436static unsigned gen_data(struct vl_compositor *c, 437 struct pipe_sampler_view *src_surface, 438 struct pipe_video_rect *src_rect, 439 struct pipe_video_rect *dst_rect, 440 struct pipe_sampler_view **textures, 441 void **frag_shaders) 442{ 443 void *vb; 444 struct pipe_transfer *buf_transfer; 445 unsigned num_rects = 0; 446 unsigned i; 447 448 assert(c); 449 assert(src_surface); 450 assert(src_rect); 451 assert(dst_rect); 452 assert(textures); 453 454 vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer, 455 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, 456 &buf_transfer); 457 458 if (!vb) 459 return 0; 460 461 { 462 struct vertex2f src_inv_size = { 1.0f / src_surface->texture->width0, 1.0f / src_surface->texture->height0}; 463 gen_rect_verts(num_rects, src_rect, &src_inv_size, dst_rect, &c->fb_inv_size, vb); 464 textures[num_rects] = src_surface; 465 /* XXX: Hack, sort of */ 466 frag_shaders[num_rects] = c->fragment_shader.ycbcr_2_rgb; 467 ++num_rects; 468 } 469 470 for (i = 0; c->dirty_layers > 0; i++) { 471 assert(i < VL_COMPOSITOR_MAX_LAYERS); 472 473 if (c->dirty_layers & (1 << i)) { 474 struct vertex2f layer_inv_size = {1.0f / c->layers[i]->texture->width0, 1.0f / c->layers[i]->texture->height0}; 475 gen_rect_verts(num_rects, &c->layer_src_rects[i], &layer_inv_size, 476 &c->layer_dst_rects[i], &c->fb_inv_size, vb); 477 textures[num_rects] = c->layers[i]; 478 /* XXX: Hack */ 479 frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb; 480 ++num_rects; 481 c->dirty_layers &= ~(1 << i); 482 } 483 } 484 485 pipe_buffer_unmap(c->pipe, buf_transfer); 486 487 return num_rects; 488} 489 490static void draw_layers(struct vl_compositor *c, 491 struct pipe_sampler_view *src_surface, 492 struct pipe_video_rect *src_rect, 493 struct pipe_video_rect *dst_rect) 494{ 495 unsigned num_rects; 496 struct pipe_sampler_view *src_surfaces[VL_COMPOSITOR_MAX_LAYERS + 1]; 497 void *frag_shaders[VL_COMPOSITOR_MAX_LAYERS + 1]; 498 unsigned i; 499 500 assert(c); 501 assert(src_surface); 502 assert(src_rect); 503 assert(dst_rect); 504 505 num_rects = gen_data(c, src_surface, src_rect, dst_rect, src_surfaces, frag_shaders); 506 507 for (i = 0; i < num_rects; ++i) { 508 c->pipe->bind_fs_state(c->pipe, frag_shaders[i]); 509 c->pipe->set_fragment_sampler_views(c->pipe, 1, &src_surfaces[i]); 510 511 util_draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, i * 6, 6); 512 } 513} 514 515void vl_compositor_render(struct vl_compositor *compositor, 516 struct pipe_sampler_view *src_surface, 517 enum pipe_mpeg12_picture_type picture_type, 518 struct pipe_video_rect *src_area, 519 struct pipe_surface *dst_surface, 520 struct pipe_video_rect *dst_area, 521 struct pipe_fence_handle **fence) 522{ 523 assert(compositor); 524 assert(src_surface); 525 assert(src_area); 526 assert(dst_surface); 527 assert(dst_area); 528 assert(picture_type == PIPE_MPEG12_PICTURE_TYPE_FRAME); 529 530 if (compositor->fb_state.width != dst_surface->width) { 531 compositor->fb_inv_size.x = 1.0f / dst_surface->width; 532 compositor->fb_state.width = dst_surface->width; 533 } 534 if (compositor->fb_state.height != dst_surface->height) { 535 compositor->fb_inv_size.y = 1.0f / dst_surface->height; 536 compositor->fb_state.height = dst_surface->height; 537 } 538 539 compositor->fb_state.cbufs[0] = dst_surface; 540 541 compositor->viewport.scale[0] = compositor->fb_state.width; 542 compositor->viewport.scale[1] = compositor->fb_state.height; 543 compositor->viewport.scale[2] = 1; 544 compositor->viewport.scale[3] = 1; 545 compositor->viewport.translate[0] = 0; 546 compositor->viewport.translate[1] = 0; 547 compositor->viewport.translate[2] = 0; 548 compositor->viewport.translate[3] = 0; 549 550 compositor->pipe->set_framebuffer_state(compositor->pipe, &compositor->fb_state); 551 compositor->pipe->set_viewport_state(compositor->pipe, &compositor->viewport); 552 compositor->pipe->bind_fragment_sampler_states(compositor->pipe, 1, &compositor->sampler); 553 compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader); 554 compositor->pipe->set_vertex_buffers(compositor->pipe, 1, &compositor->vertex_buf); 555 compositor->pipe->bind_vertex_elements_state(compositor->pipe, compositor->vertex_elems_state); 556 compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, compositor->fs_const_buf); 557 558 draw_layers(compositor, src_surface, src_area, dst_area); 559 560 assert(!compositor->dirty_layers); 561 compositor->pipe->flush(compositor->pipe, fence); 562} 563 564void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat) 565{ 566 struct pipe_transfer *buf_transfer; 567 568 assert(compositor); 569 570 memcpy 571 ( 572 pipe_buffer_map(compositor->pipe, compositor->fs_const_buf, 573 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, 574 &buf_transfer), 575 mat, 576 sizeof(struct fragment_shader_consts) 577 ); 578 579 pipe_buffer_unmap(compositor->pipe, buf_transfer); 580} 581