xorg_renderer.c revision f44b0ff84338c2184ef4f2cbb752bf62f4fff1fc
1#include "xorg_exa.h" 2#include "xorg_renderer.h" 3 4#include "xorg_exa_tgsi.h" 5 6#include "cso_cache/cso_context.h" 7#include "util/u_draw_quad.h" 8#include "util/u_format.h" 9#include "util/u_math.h" 10#include "util/u_memory.h" 11#include "util/u_rect.h" 12 13#include "pipe/p_inlines.h" 14 15#include <math.h> 16 17#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y))) 18#define floatIsZero(x) (floatsEqual((x) + 1, 1)) 19 20#define NUM_COMPONENTS 4 21 22static INLINE boolean is_affine(float *matrix) 23{ 24 return floatIsZero(matrix[2]) && floatIsZero(matrix[5]) 25 && floatsEqual(matrix[8], 1); 26} 27static INLINE void map_point(float *mat, float x, float y, 28 float *out_x, float *out_y) 29{ 30 if (!mat) { 31 *out_x = x; 32 *out_y = y; 33 return; 34 } 35 36 *out_x = mat[0]*x + mat[3]*y + mat[6]; 37 *out_y = mat[1]*x + mat[4]*y + mat[7]; 38 if (!is_affine(mat)) { 39 float w = 1/(mat[2]*x + mat[5]*y + mat[8]); 40 *out_x *= w; 41 *out_y *= w; 42 } 43} 44 45static INLINE struct pipe_buffer * 46renderer_buffer_create(struct xorg_renderer *r) 47{ 48 struct pipe_buffer *buf = 49 pipe_user_buffer_create(r->pipe->screen, 50 r->buffer, 51 sizeof(float)* 52 r->buffer_size); 53 r->buffer_size = 0; 54 55 return buf; 56} 57 58static INLINE void 59renderer_draw(struct xorg_renderer *r) 60{ 61 struct pipe_context *pipe = r->pipe; 62 struct pipe_buffer *buf = 0; 63 int num_verts = r->buffer_size/(r->attrs_per_vertex * NUM_COMPONENTS); 64 65 if (!r->buffer_size) 66 return; 67 68 buf = renderer_buffer_create(r); 69 70 71 if (buf) { 72 util_draw_vertex_buffer(pipe, buf, 0, 73 PIPE_PRIM_QUADS, 74 num_verts, /* verts */ 75 r->attrs_per_vertex); /* attribs/vert */ 76 77 pipe_buffer_reference(&buf, NULL); 78 } 79} 80 81static INLINE void 82renderer_draw_conditional(struct xorg_renderer *r, 83 int next_batch) 84{ 85 if (r->buffer_size + next_batch >= BUF_SIZE || 86 (next_batch == 0 && r->buffer_size)) { 87 renderer_draw(r); 88 } 89} 90 91static void 92renderer_init_state(struct xorg_renderer *r) 93{ 94 struct pipe_depth_stencil_alpha_state dsa; 95 struct pipe_rasterizer_state raster; 96 97 /* set common initial clip state */ 98 memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); 99 cso_set_depth_stencil_alpha(r->cso, &dsa); 100 101 102 /* XXX: move to renderer_init_state? */ 103 memset(&raster, 0, sizeof(struct pipe_rasterizer_state)); 104 raster.gl_rasterization_rules = 1; 105 cso_set_rasterizer(r->cso, &raster); 106 107} 108 109 110static INLINE void 111add_vertex_color(struct xorg_renderer *r, 112 float x, float y, 113 float color[4]) 114{ 115 float *vertex = r->buffer + r->buffer_size; 116 117 vertex[0] = x; 118 vertex[1] = y; 119 vertex[2] = 0.f; /*z*/ 120 vertex[3] = 1.f; /*w*/ 121 122 vertex[4] = color[0]; /*r*/ 123 vertex[5] = color[1]; /*g*/ 124 vertex[6] = color[2]; /*b*/ 125 vertex[7] = color[3]; /*a*/ 126 127 r->buffer_size += 8; 128} 129 130static INLINE void 131add_vertex_1tex(struct xorg_renderer *r, 132 float x, float y, float s, float t) 133{ 134 float *vertex = r->buffer + r->buffer_size; 135 136 vertex[0] = x; 137 vertex[1] = y; 138 vertex[2] = 0.f; /*z*/ 139 vertex[3] = 1.f; /*w*/ 140 141 vertex[4] = s; /*s*/ 142 vertex[5] = t; /*t*/ 143 vertex[6] = 0.f; /*r*/ 144 vertex[7] = 1.f; /*q*/ 145 146 r->buffer_size += 8; 147} 148 149static void 150add_vertex_data1(struct xorg_renderer *r, 151 float srcX, float srcY, float dstX, float dstY, 152 float width, float height, 153 struct pipe_texture *src, float *src_matrix) 154{ 155 float s0, t0, s1, t1, s2, t2, s3, t3; 156 float pt0[2], pt1[2], pt2[2], pt3[2]; 157 158 pt0[0] = srcX; 159 pt0[1] = srcY; 160 pt1[0] = (srcX + width); 161 pt1[1] = srcY; 162 pt2[0] = (srcX + width); 163 pt2[1] = (srcY + height); 164 pt3[0] = srcX; 165 pt3[1] = (srcY + height); 166 167 if (src_matrix) { 168 map_point(src_matrix, pt0[0], pt0[1], &pt0[0], &pt0[1]); 169 map_point(src_matrix, pt1[0], pt1[1], &pt1[0], &pt1[1]); 170 map_point(src_matrix, pt2[0], pt2[1], &pt2[0], &pt2[1]); 171 map_point(src_matrix, pt3[0], pt3[1], &pt3[0], &pt3[1]); 172 } 173 174 s0 = pt0[0] / src->width0; 175 s1 = pt1[0] / src->width0; 176 s2 = pt2[0] / src->width0; 177 s3 = pt3[0] / src->width0; 178 t0 = pt0[1] / src->height0; 179 t1 = pt1[1] / src->height0; 180 t2 = pt2[1] / src->height0; 181 t3 = pt3[1] / src->height0; 182 183 /* 1st vertex */ 184 add_vertex_1tex(r, dstX, dstY, s0, t0); 185 /* 2nd vertex */ 186 add_vertex_1tex(r, dstX + width, dstY, s1, t1); 187 /* 3rd vertex */ 188 add_vertex_1tex(r, dstX + width, dstY + height, s2, t2); 189 /* 4th vertex */ 190 add_vertex_1tex(r, dstX, dstY + height, s3, t3); 191} 192 193 194static INLINE void 195add_vertex_2tex(struct xorg_renderer *r, 196 float x, float y, 197 float s0, float t0, float s1, float t1) 198{ 199 float *vertex = r->buffer + r->buffer_size; 200 201 vertex[0] = x; 202 vertex[1] = y; 203 vertex[2] = 0.f; /*z*/ 204 vertex[3] = 1.f; /*w*/ 205 206 vertex[4] = s0; /*s*/ 207 vertex[5] = t0; /*t*/ 208 vertex[6] = 0.f; /*r*/ 209 vertex[7] = 1.f; /*q*/ 210 211 vertex[8] = s1; /*s*/ 212 vertex[9] = t1; /*t*/ 213 vertex[10] = 0.f; /*r*/ 214 vertex[11] = 1.f; /*q*/ 215 216 r->buffer_size += 12; 217} 218 219static void 220add_vertex_data2(struct xorg_renderer *r, 221 float srcX, float srcY, float maskX, float maskY, 222 float dstX, float dstY, float width, float height, 223 struct pipe_texture *src, 224 struct pipe_texture *mask, 225 float *src_matrix, float *mask_matrix) 226{ 227 float src_s0, src_t0, src_s1, src_t1; 228 float mask_s0, mask_t0, mask_s1, mask_t1; 229 float spt0[2], spt1[2]; 230 float mpt0[2], mpt1[2]; 231 232 spt0[0] = srcX; 233 spt0[1] = srcY; 234 spt1[0] = srcX + width; 235 spt1[1] = srcY + height; 236 237 mpt0[0] = maskX; 238 mpt0[1] = maskY; 239 mpt1[0] = maskX + width; 240 mpt1[1] = maskY + height; 241 242 if (src_matrix) { 243 map_point(src_matrix, spt0[0], spt0[1], &spt0[0], &spt0[1]); 244 map_point(src_matrix, spt1[0], spt1[1], &spt1[0], &spt1[1]); 245 } 246 247 if (mask_matrix) { 248 map_point(mask_matrix, mpt0[0], mpt0[1], &mpt0[0], &mpt0[1]); 249 map_point(mask_matrix, mpt1[0], mpt1[1], &mpt1[0], &mpt1[1]); 250 } 251 252 src_s0 = spt0[0] / src->width0; 253 src_t0 = spt0[1] / src->height0; 254 src_s1 = spt1[0] / src->width0; 255 src_t1 = spt1[1] / src->height0; 256 257 mask_s0 = mpt0[0] / mask->width0; 258 mask_t0 = mpt0[1] / mask->height0; 259 mask_s1 = mpt1[0] / mask->width0; 260 mask_t1 = mpt1[1] / mask->height0; 261 262 /* 1st vertex */ 263 add_vertex_2tex(r, dstX, dstY, 264 src_s0, src_t0, mask_s0, mask_t0); 265 /* 2nd vertex */ 266 add_vertex_2tex(r, dstX + width, dstY, 267 src_s1, src_t0, mask_s1, mask_t0); 268 /* 3rd vertex */ 269 add_vertex_2tex(r, dstX + width, dstY + height, 270 src_s1, src_t1, mask_s1, mask_t1); 271 /* 4th vertex */ 272 add_vertex_2tex(r, dstX, dstY + height, 273 src_s0, src_t1, mask_s0, mask_t1); 274} 275 276static struct pipe_buffer * 277setup_vertex_data_yuv(struct xorg_renderer *r, 278 float srcX, float srcY, float srcW, float srcH, 279 float dstX, float dstY, float dstW, float dstH, 280 struct pipe_texture **tex) 281{ 282 float s0, t0, s1, t1; 283 float spt0[2], spt1[2]; 284 285 spt0[0] = srcX; 286 spt0[1] = srcY; 287 spt1[0] = srcX + srcW; 288 spt1[1] = srcY + srcH; 289 290 s0 = spt0[0] / tex[0]->width0; 291 t0 = spt0[1] / tex[0]->height0; 292 s1 = spt1[0] / tex[0]->width0; 293 t1 = spt1[1] / tex[0]->height0; 294 295 /* 1st vertex */ 296 add_vertex_1tex(r, dstX, dstY, s0, t0); 297 /* 2nd vertex */ 298 add_vertex_1tex(r, dstX + dstW, dstY, 299 s1, t0); 300 /* 3rd vertex */ 301 add_vertex_1tex(r, dstX + dstW, dstY + dstH, 302 s1, t1); 303 /* 4th vertex */ 304 add_vertex_1tex(r, dstX, dstY + dstH, 305 s0, t1); 306 307 return renderer_buffer_create(r); 308} 309 310 311 312/* Set up framebuffer, viewport and vertex shader constant buffer 313 * state for a particular destinaton surface. In all our rendering, 314 * these concepts are linked. 315 */ 316void renderer_bind_destination(struct xorg_renderer *r, 317 struct pipe_surface *surface, 318 int width, 319 int height ) 320{ 321 322 struct pipe_framebuffer_state fb; 323 struct pipe_viewport_state viewport; 324 325 /* Framebuffer uses actual surface width/height 326 */ 327 memset(&fb, 0, sizeof fb); 328 fb.width = surface->width; 329 fb.height = surface->height; 330 fb.nr_cbufs = 1; 331 fb.cbufs[0] = surface; 332 fb.zsbuf = 0; 333 334 /* Viewport just touches the bit we're interested in: 335 */ 336 viewport.scale[0] = width / 2.f; 337 viewport.scale[1] = height / 2.f; 338 viewport.scale[2] = 1.0; 339 viewport.scale[3] = 1.0; 340 viewport.translate[0] = width / 2.f; 341 viewport.translate[1] = height / 2.f; 342 viewport.translate[2] = 0.0; 343 viewport.translate[3] = 0.0; 344 345 /* Constant buffer set up to match viewport dimensions: 346 */ 347 if (r->fb_width != width || 348 r->fb_height != height) 349 { 350 float vs_consts[8] = { 351 2.f/width, 2.f/height, 1, 1, 352 -1, -1, 0, 0 353 }; 354 355 r->fb_width = width; 356 r->fb_height = height; 357 358 renderer_set_constants(r, PIPE_SHADER_VERTEX, 359 vs_consts, sizeof vs_consts); 360 } 361 362 cso_set_framebuffer(r->cso, &fb); 363 cso_set_viewport(r->cso, &viewport); 364} 365 366 367struct xorg_renderer * renderer_create(struct pipe_context *pipe) 368{ 369 struct xorg_renderer *renderer = CALLOC_STRUCT(xorg_renderer); 370 371 renderer->pipe = pipe; 372 renderer->cso = cso_create_context(pipe); 373 renderer->shaders = xorg_shaders_create(renderer); 374 375 renderer_init_state(renderer); 376 377 return renderer; 378} 379 380void renderer_destroy(struct xorg_renderer *r) 381{ 382 struct pipe_buffer **vsbuf = &r->vs_const_buffer; 383 struct pipe_buffer **fsbuf = &r->fs_const_buffer; 384 385 if (*vsbuf) 386 pipe_buffer_reference(vsbuf, NULL); 387 388 if (*fsbuf) 389 pipe_buffer_reference(fsbuf, NULL); 390 391 if (r->shaders) { 392 xorg_shaders_destroy(r->shaders); 393 r->shaders = NULL; 394 } 395 396 if (r->cso) { 397 cso_release_all(r->cso); 398 cso_destroy_context(r->cso); 399 r->cso = NULL; 400 } 401} 402 403 404 405 406 407void renderer_set_constants(struct xorg_renderer *r, 408 int shader_type, 409 const float *params, 410 int param_bytes) 411{ 412 struct pipe_buffer **cbuf = 413 (shader_type == PIPE_SHADER_VERTEX) ? &r->vs_const_buffer : 414 &r->fs_const_buffer; 415 416 pipe_buffer_reference(cbuf, NULL); 417 *cbuf = pipe_buffer_create(r->pipe->screen, 16, 418 PIPE_BUFFER_USAGE_CONSTANT, 419 param_bytes); 420 421 if (*cbuf) { 422 pipe_buffer_write(r->pipe->screen, *cbuf, 423 0, param_bytes, params); 424 } 425 r->pipe->set_constant_buffer(r->pipe, shader_type, 0, *cbuf); 426} 427 428 429void renderer_copy_prepare(struct xorg_renderer *r, 430 struct pipe_surface *dst_surface, 431 struct pipe_texture *src_texture) 432{ 433 struct pipe_context *pipe = r->pipe; 434 struct pipe_screen *screen = pipe->screen; 435 struct xorg_shader shader; 436 437 assert(screen->is_format_supported(screen, dst_surface->format, 438 PIPE_TEXTURE_2D, 439 PIPE_TEXTURE_USAGE_RENDER_TARGET, 440 0)); 441 442 443 /* set misc state we care about */ 444 { 445 struct pipe_blend_state blend; 446 memset(&blend, 0, sizeof(blend)); 447 blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; 448 blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; 449 blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; 450 blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; 451 blend.colormask = PIPE_MASK_RGBA; 452 cso_set_blend(r->cso, &blend); 453 } 454 455 /* sampler */ 456 { 457 struct pipe_sampler_state sampler; 458 memset(&sampler, 0, sizeof(sampler)); 459 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 460 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 461 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 462 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 463 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; 464 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 465 sampler.normalized_coords = 1; 466 cso_single_sampler(r->cso, 0, &sampler); 467 cso_single_sampler_done(r->cso); 468 } 469 470 renderer_bind_destination(r, dst_surface, 471 dst_surface->width, 472 dst_surface->height); 473 474 /* texture */ 475 cso_set_sampler_textures(r->cso, 1, &src_texture); 476 477 /* shaders */ 478 shader = xorg_shaders_get(r->shaders, 479 VS_COMPOSITE, 480 FS_COMPOSITE); 481 cso_set_vertex_shader_handle(r->cso, shader.vs); 482 cso_set_fragment_shader_handle(r->cso, shader.fs); 483 484 r->buffer_size = 0; 485 r->attrs_per_vertex = 2; 486} 487 488struct pipe_texture * 489renderer_clone_texture(struct xorg_renderer *r, 490 struct pipe_texture *src) 491{ 492 enum pipe_format format; 493 struct pipe_context *pipe = r->pipe; 494 struct pipe_screen *screen = pipe->screen; 495 struct pipe_texture *pt; 496 struct pipe_texture templ; 497 498 if (pipe->is_texture_referenced(pipe, src, 0, 0) & 499 PIPE_REFERENCED_FOR_WRITE) 500 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 501 502 /* the coming in texture should already have that invariance */ 503 debug_assert(screen->is_format_supported(screen, src->format, 504 PIPE_TEXTURE_2D, 505 PIPE_TEXTURE_USAGE_SAMPLER, 0)); 506 507 format = src->format; 508 509 memset(&templ, 0, sizeof(templ)); 510 templ.target = PIPE_TEXTURE_2D; 511 templ.format = format; 512 templ.last_level = 0; 513 templ.width0 = src->width0; 514 templ.height0 = src->height0; 515 templ.depth0 = 1; 516 templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER; 517 518 pt = screen->texture_create(screen, &templ); 519 520 debug_assert(!pt || pipe_is_referenced(&pt->reference)); 521 522 if (!pt) 523 return NULL; 524 525 { 526 /* copy source framebuffer surface into texture */ 527 struct pipe_surface *ps_read = screen->get_tex_surface( 528 screen, src, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ); 529 struct pipe_surface *ps_tex = screen->get_tex_surface( 530 screen, pt, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE ); 531 if (pipe->surface_copy) { 532 pipe->surface_copy(pipe, 533 ps_tex, /* dest */ 534 0, 0, /* destx/y */ 535 ps_read, 536 0, 0, src->width0, src->height0); 537 } else { 538 util_surface_copy(pipe, FALSE, 539 ps_tex, /* dest */ 540 0, 0, /* destx/y */ 541 ps_read, 542 0, 0, src->width0, src->height0); 543 } 544 pipe_surface_reference(&ps_read, NULL); 545 pipe_surface_reference(&ps_tex, NULL); 546 } 547 548 return pt; 549} 550 551 552void renderer_copy_pixmap(struct xorg_renderer *r, 553 int dx, int dy, 554 int sx, int sy, 555 int width, int height, 556 float src_width, 557 float src_height) 558{ 559 float s0, t0, s1, t1; 560 float x0, y0, x1, y1; 561 562 563 /* XXX: could put the texcoord scaling calculation into the vertex 564 * shader. 565 */ 566 s0 = sx / src_width; 567 s1 = (sx + width) / src_width; 568 t0 = sy / src_height; 569 t1 = (sy + height) / src_height; 570 571 x0 = dx; 572 x1 = dx + width; 573 y0 = dy; 574 y1 = dy + height; 575 576 /* draw quad */ 577 renderer_draw_conditional(r, 4*8); 578 add_vertex_1tex(r, x0, y0, s0, t0); 579 add_vertex_1tex(r, x1, y0, s1, t0); 580 add_vertex_1tex(r, x1, y1, s1, t1); 581 add_vertex_1tex(r, x0, y1, s0, t1); 582} 583 584 585 586 587void renderer_draw_yuv(struct xorg_renderer *r, 588 int src_x, int src_y, int src_w, int src_h, 589 int dst_x, int dst_y, int dst_w, int dst_h, 590 struct pipe_texture **textures) 591{ 592 struct pipe_context *pipe = r->pipe; 593 struct pipe_buffer *buf = 0; 594 595 buf = setup_vertex_data_yuv(r, 596 src_x, src_y, src_w, src_h, 597 dst_x, dst_y, dst_w, dst_h, 598 textures); 599 600 if (buf) { 601 const int num_attribs = 2; /*pos + tex coord*/ 602 603 util_draw_vertex_buffer(pipe, buf, 0, 604 PIPE_PRIM_QUADS, 605 4, /* verts */ 606 num_attribs); /* attribs/vert */ 607 608 pipe_buffer_reference(&buf, NULL); 609 } 610} 611 612void renderer_begin_solid(struct xorg_renderer *r) 613{ 614 r->buffer_size = 0; 615 r->attrs_per_vertex = 2; 616} 617 618void renderer_solid(struct xorg_renderer *r, 619 int x0, int y0, 620 int x1, int y1, 621 float *color) 622{ 623 /* 624 debug_printf("solid rect[(%d, %d), (%d, %d)], rgba[%f, %f, %f, %f]\n", 625 x0, y0, x1, y1, color[0], color[1], color[2], color[3]);*/ 626 627 renderer_draw_conditional(r, 4 * 8); 628 629 /* 1st vertex */ 630 add_vertex_color(r, x0, y0, color); 631 /* 2nd vertex */ 632 add_vertex_color(r, x1, y0, color); 633 /* 3rd vertex */ 634 add_vertex_color(r, x1, y1, color); 635 /* 4th vertex */ 636 add_vertex_color(r, x0, y1, color); 637} 638 639void renderer_draw_flush(struct xorg_renderer *r) 640{ 641 renderer_draw_conditional(r, 0); 642} 643 644void renderer_begin_textures(struct xorg_renderer *r, 645 struct pipe_texture **textures, 646 int num_textures) 647{ 648 r->attrs_per_vertex = 1 + num_textures; 649 r->buffer_size = 0; 650} 651 652void renderer_texture(struct xorg_renderer *r, 653 int *pos, 654 int width, int height, 655 struct pipe_texture **textures, 656 int num_textures, 657 float *src_matrix, 658 float *mask_matrix) 659{ 660 661#if 0 662 if (src_matrix) { 663 debug_printf("src_matrix = \n"); 664 debug_printf("%f, %f, %f\n", src_matrix[0], src_matrix[1], src_matrix[2]); 665 debug_printf("%f, %f, %f\n", src_matrix[3], src_matrix[4], src_matrix[5]); 666 debug_printf("%f, %f, %f\n", src_matrix[6], src_matrix[7], src_matrix[8]); 667 } 668 if (mask_matrix) { 669 debug_printf("mask_matrix = \n"); 670 debug_printf("%f, %f, %f\n", mask_matrix[0], mask_matrix[1], mask_matrix[2]); 671 debug_printf("%f, %f, %f\n", mask_matrix[3], mask_matrix[4], mask_matrix[5]); 672 debug_printf("%f, %f, %f\n", mask_matrix[6], mask_matrix[7], mask_matrix[8]); 673 } 674#endif 675 676 switch(r->attrs_per_vertex) { 677 case 2: 678 renderer_draw_conditional(r, 4 * 8); 679 add_vertex_data1(r, 680 pos[0], pos[1], /* src */ 681 pos[4], pos[5], /* dst */ 682 width, height, 683 textures[0], src_matrix); 684 break; 685 case 3: 686 renderer_draw_conditional(r, 4 * 12); 687 add_vertex_data2(r, 688 pos[0], pos[1], /* src */ 689 pos[2], pos[3], /* mask */ 690 pos[4], pos[5], /* dst */ 691 width, height, 692 textures[0], textures[1], 693 src_matrix, mask_matrix); 694 break; 695 default: 696 debug_assert(!"Unsupported number of textures"); 697 break; 698 } 699} 700