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