xa_renderer.c revision aa7d7656f50f5c49734e3b0fad0f20a89cd5eb5b
1/********************************************************** 2 * Copyright 2009-2011 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 ********************************************************* 25 * Authors: 26 * Zack Rusin <zackr-at-vmware-dot-com> 27 */ 28 29#include "xa_context.h" 30#include "xa_priv.h" 31#include <math.h> 32#include "cso_cache/cso_context.h" 33#include "util/u_inlines.h" 34#include "util/u_sampler.h" 35#include "util/u_draw_quad.h" 36 37#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y))) 38#define floatIsZero(x) (floatsEqual((x) + 1, 1)) 39 40#define NUM_COMPONENTS 4 41 42void 43 44 45renderer_set_constants(struct xa_context *r, 46 int shader_type, const float *params, int param_bytes); 47 48static INLINE boolean 49is_affine(float *matrix) 50{ 51 return floatIsZero(matrix[2]) && floatIsZero(matrix[5]) 52 && floatsEqual(matrix[8], 1); 53} 54 55static INLINE void 56map_point(float *mat, float x, float y, float *out_x, float *out_y) 57{ 58 if (!mat) { 59 *out_x = x; 60 *out_y = y; 61 return; 62 } 63 64 *out_x = mat[0] * x + mat[3] * y + mat[6]; 65 *out_y = mat[1] * x + mat[4] * y + mat[7]; 66 if (!is_affine(mat)) { 67 float w = 1 / (mat[2] * x + mat[5] * y + mat[8]); 68 69 *out_x *= w; 70 *out_y *= w; 71 } 72} 73 74static INLINE struct pipe_resource * 75renderer_buffer_create(struct xa_context *r) 76{ 77 struct pipe_resource *buf = pipe_user_buffer_create(r->pipe->screen, 78 r->buffer, 79 sizeof(float) * 80 r->buffer_size, 81 PIPE_BIND_VERTEX_BUFFER); 82 83 r->buffer_size = 0; 84 85 return buf; 86} 87 88static INLINE void 89renderer_draw(struct xa_context *r) 90{ 91 struct pipe_context *pipe = r->pipe; 92 struct pipe_resource *buf = 0; 93 int num_verts = r->buffer_size / (r->attrs_per_vertex * NUM_COMPONENTS); 94 95 if (!r->buffer_size) 96 return; 97 98 buf = renderer_buffer_create(r); 99 100 if (buf) { 101 cso_set_vertex_elements(r->cso, r->attrs_per_vertex, r->velems); 102 103 util_draw_vertex_buffer(pipe, r->cso, buf, 0, PIPE_PRIM_QUADS, num_verts, /* verts */ 104 r->attrs_per_vertex); /* attribs/vert */ 105 106 pipe_resource_reference(&buf, NULL); 107 } 108} 109 110static INLINE void 111renderer_draw_conditional(struct xa_context *r, int next_batch) 112{ 113 if (r->buffer_size + next_batch >= XA_VB_SIZE || 114 (next_batch == 0 && r->buffer_size)) { 115 renderer_draw(r); 116 } 117} 118 119void 120renderer_init_state(struct xa_context *r) 121{ 122 struct pipe_depth_stencil_alpha_state dsa; 123 struct pipe_rasterizer_state raster; 124 unsigned i; 125 126 /* set common initial clip state */ 127 memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); 128 cso_set_depth_stencil_alpha(r->cso, &dsa); 129 130 /* XXX: move to renderer_init_state? */ 131 memset(&raster, 0, sizeof(struct pipe_rasterizer_state)); 132 raster.gl_rasterization_rules = 1; 133 cso_set_rasterizer(r->cso, &raster); 134 135 /* vertex elements state */ 136 memset(&r->velems[0], 0, sizeof(r->velems[0]) * 3); 137 for (i = 0; i < 3; i++) { 138 r->velems[i].src_offset = i * 4 * sizeof(float); 139 r->velems[i].instance_divisor = 0; 140 r->velems[i].vertex_buffer_index = 0; 141 r->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 142 } 143} 144 145static INLINE void 146add_vertex_color(struct xa_context *r, float x, float y, float color[4]) 147{ 148 float *vertex = r->buffer + r->buffer_size; 149 150 vertex[0] = x; 151 vertex[1] = y; 152 vertex[2] = 0.f; /*z */ 153 vertex[3] = 1.f; /*w */ 154 155 vertex[4] = color[0]; /*r */ 156 vertex[5] = color[1]; /*g */ 157 vertex[6] = color[2]; /*b */ 158 vertex[7] = color[3]; /*a */ 159 160 r->buffer_size += 8; 161} 162 163static INLINE void 164add_vertex_1tex(struct xa_context *r, float x, float y, float s, float t) 165{ 166 float *vertex = r->buffer + r->buffer_size; 167 168 vertex[0] = x; 169 vertex[1] = y; 170 vertex[2] = 0.f; /*z */ 171 vertex[3] = 1.f; /*w */ 172 173 vertex[4] = s; /*s */ 174 vertex[5] = t; /*t */ 175 vertex[6] = 0.f; /*r */ 176 vertex[7] = 1.f; /*q */ 177 178 r->buffer_size += 8; 179} 180 181static INLINE void 182add_vertex_2tex(struct xa_context *r, 183 float x, float y, float s0, float t0, float s1, float t1) 184{ 185 float *vertex = r->buffer + r->buffer_size; 186 187 vertex[0] = x; 188 vertex[1] = y; 189 vertex[2] = 0.f; /*z */ 190 vertex[3] = 1.f; /*w */ 191 192 vertex[4] = s0; /*s */ 193 vertex[5] = t0; /*t */ 194 vertex[6] = 0.f; /*r */ 195 vertex[7] = 1.f; /*q */ 196 197 vertex[8] = s1; /*s */ 198 vertex[9] = t1; /*t */ 199 vertex[10] = 0.f; /*r */ 200 vertex[11] = 1.f; /*q */ 201 202 r->buffer_size += 12; 203} 204 205static void 206add_vertex_data1(struct xa_context *r, 207 float srcX, float srcY, float dstX, float dstY, 208 float width, float height, 209 struct pipe_resource *src, const float *src_matrix) 210{ 211 float s0, t0, s1, t1, s2, t2, s3, t3; 212 float pt0[2], pt1[2], pt2[2], pt3[2]; 213 214 pt0[0] = srcX; 215 pt0[1] = srcY; 216 pt1[0] = (srcX + width); 217 pt1[1] = srcY; 218 pt2[0] = (srcX + width); 219 pt2[1] = (srcY + height); 220 pt3[0] = srcX; 221 pt3[1] = (srcY + height); 222 223 if (src_matrix) { 224 map_point((float *)src_matrix, pt0[0], pt0[1], &pt0[0], &pt0[1]); 225 map_point((float *)src_matrix, pt1[0], pt1[1], &pt1[0], &pt1[1]); 226 map_point((float *)src_matrix, pt2[0], pt2[1], &pt2[0], &pt2[1]); 227 map_point((float *)src_matrix, pt3[0], pt3[1], &pt3[0], &pt3[1]); 228 } 229 230 s0 = pt0[0] / src->width0; 231 s1 = pt1[0] / src->width0; 232 s2 = pt2[0] / src->width0; 233 s3 = pt3[0] / src->width0; 234 t0 = pt0[1] / src->height0; 235 t1 = pt1[1] / src->height0; 236 t2 = pt2[1] / src->height0; 237 t3 = pt3[1] / src->height0; 238 239 /* 1st vertex */ 240 add_vertex_1tex(r, dstX, dstY, s0, t0); 241 /* 2nd vertex */ 242 add_vertex_1tex(r, dstX + width, dstY, s1, t1); 243 /* 3rd vertex */ 244 add_vertex_1tex(r, dstX + width, dstY + height, s2, t2); 245 /* 4th vertex */ 246 add_vertex_1tex(r, dstX, dstY + height, s3, t3); 247} 248 249static void 250add_vertex_data2(struct xa_context *r, 251 float srcX, float srcY, float maskX, float maskY, 252 float dstX, float dstY, float width, float height, 253 struct pipe_resource *src, 254 struct pipe_resource *mask, 255 const float *src_matrix, const float *mask_matrix) 256{ 257 float src_s0, src_t0, src_s1, src_t1; 258 float mask_s0, mask_t0, mask_s1, mask_t1; 259 float spt0[2], spt1[2]; 260 float mpt0[2], mpt1[2]; 261 262 spt0[0] = srcX; 263 spt0[1] = srcY; 264 spt1[0] = srcX + width; 265 spt1[1] = srcY + height; 266 267 mpt0[0] = maskX; 268 mpt0[1] = maskY; 269 mpt1[0] = maskX + width; 270 mpt1[1] = maskY + height; 271 272 if (src_matrix) { 273 map_point((float *)src_matrix, spt0[0], spt0[1], &spt0[0], &spt0[1]); 274 map_point((float *)src_matrix, spt1[0], spt1[1], &spt1[0], &spt1[1]); 275 } 276 277 if (mask_matrix) { 278 map_point((float *)mask_matrix, mpt0[0], mpt0[1], &mpt0[0], &mpt0[1]); 279 map_point((float *)mask_matrix, mpt1[0], mpt1[1], &mpt1[0], &mpt1[1]); 280 } 281 282 src_s0 = spt0[0] / src->width0; 283 src_t0 = spt0[1] / src->height0; 284 src_s1 = spt1[0] / src->width0; 285 src_t1 = spt1[1] / src->height0; 286 287 mask_s0 = mpt0[0] / mask->width0; 288 mask_t0 = mpt0[1] / mask->height0; 289 mask_s1 = mpt1[0] / mask->width0; 290 mask_t1 = mpt1[1] / mask->height0; 291 292 /* 1st vertex */ 293 add_vertex_2tex(r, dstX, dstY, 294 src_s0, src_t0, mask_s0, mask_t0); 295 /* 2nd vertex */ 296 add_vertex_2tex(r, dstX + width, dstY, 297 src_s1, src_t0, mask_s1, mask_t0); 298 /* 3rd vertex */ 299 add_vertex_2tex(r, dstX + width, dstY + height, 300 src_s1, src_t1, mask_s1, mask_t1); 301 /* 4th vertex */ 302 add_vertex_2tex(r, dstX, dstY + height, 303 src_s0, src_t1, mask_s0, mask_t1); 304} 305 306static struct pipe_resource * 307setup_vertex_data_yuv(struct xa_context *r, 308 float srcX, 309 float srcY, 310 float srcW, 311 float srcH, 312 float dstX, 313 float dstY, 314 float dstW, float dstH, struct xa_surface *srf[]) 315{ 316 float s0, t0, s1, t1; 317 float spt0[2], spt1[2]; 318 struct pipe_resource *tex; 319 320 spt0[0] = srcX; 321 spt0[1] = srcY; 322 spt1[0] = srcX + srcW; 323 spt1[1] = srcY + srcH; 324 325 tex = srf[0]->tex; 326 s0 = spt0[0] / tex->width0; 327 t0 = spt0[1] / tex->height0; 328 s1 = spt1[0] / tex->width0; 329 t1 = spt1[1] / tex->height0; 330 331 /* 1st vertex */ 332 add_vertex_1tex(r, dstX, dstY, s0, t0); 333 /* 2nd vertex */ 334 add_vertex_1tex(r, dstX + dstW, dstY, s1, t0); 335 /* 3rd vertex */ 336 add_vertex_1tex(r, dstX + dstW, dstY + dstH, s1, t1); 337 /* 4th vertex */ 338 add_vertex_1tex(r, dstX, dstY + dstH, s0, t1); 339 340 return renderer_buffer_create(r); 341} 342 343/* Set up framebuffer, viewport and vertex shader constant buffer 344 * state for a particular destinaton surface. In all our rendering, 345 * these concepts are linked. 346 */ 347void 348renderer_bind_destination(struct xa_context *r, 349 struct pipe_surface *surface, int width, int height) 350{ 351 352 struct pipe_framebuffer_state fb; 353 struct pipe_viewport_state viewport; 354 355 /* Framebuffer uses actual surface width/height 356 */ 357 memset(&fb, 0, sizeof fb); 358 fb.width = surface->width; 359 fb.height = surface->height; 360 fb.nr_cbufs = 1; 361 fb.cbufs[0] = surface; 362 fb.zsbuf = 0; 363 364 /* Viewport just touches the bit we're interested in: 365 */ 366 viewport.scale[0] = width / 2.f; 367 viewport.scale[1] = height / 2.f; 368 viewport.scale[2] = 1.0; 369 viewport.scale[3] = 1.0; 370 viewport.translate[0] = width / 2.f; 371 viewport.translate[1] = height / 2.f; 372 viewport.translate[2] = 0.0; 373 viewport.translate[3] = 0.0; 374 375 /* Constant buffer set up to match viewport dimensions: 376 */ 377 if (r->fb_width != width || r->fb_height != height) { 378 float vs_consts[8] = { 379 2.f / width, 2.f / height, 1, 1, 380 -1, -1, 0, 0 381 }; 382 383 r->fb_width = width; 384 r->fb_height = height; 385 386 renderer_set_constants(r, PIPE_SHADER_VERTEX, 387 vs_consts, sizeof vs_consts); 388 } 389 390 cso_set_framebuffer(r->cso, &fb); 391 cso_set_viewport(r->cso, &viewport); 392} 393 394void 395renderer_set_constants(struct xa_context *r, 396 int shader_type, const float *params, int param_bytes) 397{ 398 struct pipe_resource **cbuf = 399 (shader_type == PIPE_SHADER_VERTEX) ? &r->vs_const_buffer : 400 &r->fs_const_buffer; 401 402 pipe_resource_reference(cbuf, NULL); 403 *cbuf = pipe_buffer_create(r->pipe->screen, 404 PIPE_BIND_CONSTANT_BUFFER, PIPE_USAGE_STATIC, 405 param_bytes); 406 407 if (*cbuf) { 408 pipe_buffer_write(r->pipe, *cbuf, 0, param_bytes, params); 409 } 410 r->pipe->set_constant_buffer(r->pipe, shader_type, 0, *cbuf); 411} 412 413void 414renderer_copy_prepare(struct xa_context *r, 415 struct pipe_surface *dst_surface, 416 struct pipe_resource *src_texture, 417 const enum xa_formats src_xa_format, 418 const enum xa_formats dst_xa_format) 419{ 420 struct pipe_context *pipe = r->pipe; 421 struct pipe_screen *screen = pipe->screen; 422 struct xa_shader shader; 423 uint32_t fs_traits = FS_COMPOSITE; 424 425 assert(screen->is_format_supported(screen, dst_surface->format, 426 PIPE_TEXTURE_2D, 0, 427 PIPE_BIND_RENDER_TARGET)); 428 (void)screen; 429 430 /* set misc state we care about */ 431 { 432 struct pipe_blend_state blend; 433 434 memset(&blend, 0, sizeof(blend)); 435 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; 436 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; 437 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; 438 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; 439 blend.rt[0].colormask = PIPE_MASK_RGBA; 440 cso_set_blend(r->cso, &blend); 441 } 442 443 /* sampler */ 444 { 445 struct pipe_sampler_state sampler; 446 447 memset(&sampler, 0, sizeof(sampler)); 448 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 449 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 450 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 451 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 452 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; 453 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 454 sampler.normalized_coords = 1; 455 cso_single_sampler(r->cso, 0, &sampler); 456 cso_single_sampler_done(r->cso); 457 } 458 459 renderer_bind_destination(r, dst_surface, 460 dst_surface->width, dst_surface->height); 461 462 /* texture/sampler view */ 463 { 464 struct pipe_sampler_view templ; 465 struct pipe_sampler_view *src_view; 466 467 u_sampler_view_default_template(&templ, 468 src_texture, src_texture->format); 469 src_view = pipe->create_sampler_view(pipe, src_texture, &templ); 470 cso_set_fragment_sampler_views(r->cso, 1, &src_view); 471 pipe_sampler_view_reference(&src_view, NULL); 472 } 473 474 /* shaders */ 475 if (src_texture->format == PIPE_FORMAT_L8_UNORM) 476 fs_traits |= FS_SRC_LUMINANCE; 477 if (dst_surface->format == PIPE_FORMAT_L8_UNORM) 478 fs_traits |= FS_DST_LUMINANCE; 479 if (xa_format_a(dst_xa_format) != 0 && 480 xa_format_a(src_xa_format) == 0) 481 fs_traits |= FS_SRC_SET_ALPHA; 482 483 shader = xa_shaders_get(r->shaders, VS_COMPOSITE, fs_traits); 484 cso_set_vertex_shader_handle(r->cso, shader.vs); 485 cso_set_fragment_shader_handle(r->cso, shader.fs); 486 487 r->buffer_size = 0; 488 r->attrs_per_vertex = 2; 489} 490 491void 492renderer_copy(struct xa_context *r, 493 int dx, 494 int dy, 495 int sx, 496 int sy, 497 int width, int height, float src_width, float src_height) 498{ 499 float s0, t0, s1, t1; 500 float x0, y0, x1, y1; 501 502 /* XXX: could put the texcoord scaling calculation into the vertex 503 * shader. 504 */ 505 s0 = sx / src_width; 506 s1 = (sx + width) / src_width; 507 t0 = sy / src_height; 508 t1 = (sy + height) / src_height; 509 510 x0 = dx; 511 x1 = dx + width; 512 y0 = dy; 513 y1 = dy + height; 514 515 /* draw quad */ 516 renderer_draw_conditional(r, 4 * 8); 517 add_vertex_1tex(r, x0, y0, s0, t0); 518 add_vertex_1tex(r, x1, y0, s1, t0); 519 add_vertex_1tex(r, x1, y1, s1, t1); 520 add_vertex_1tex(r, x0, y1, s0, t1); 521} 522 523void 524renderer_draw_yuv(struct xa_context *r, 525 float src_x, 526 float src_y, 527 float src_w, 528 float src_h, 529 int dst_x, 530 int dst_y, int dst_w, int dst_h, struct xa_surface *srf[]) 531{ 532 struct pipe_context *pipe = r->pipe; 533 struct pipe_resource *buf = 0; 534 535 buf = setup_vertex_data_yuv(r, 536 src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, 537 dst_h, srf); 538 539 if (buf) { 540 const int num_attribs = 2; /*pos + tex coord */ 541 542 cso_set_vertex_elements(r->cso, num_attribs, r->velems); 543 544 util_draw_vertex_buffer(pipe, r->cso, buf, 0, PIPE_PRIM_QUADS, 4, /* verts */ 545 num_attribs); /* attribs/vert */ 546 547 pipe_resource_reference(&buf, NULL); 548 } 549} 550 551void 552renderer_begin_solid(struct xa_context *r) 553{ 554 r->buffer_size = 0; 555 r->attrs_per_vertex = 2; 556} 557 558void 559renderer_solid(struct xa_context *r, 560 int x0, int y0, int x1, int y1, float *color) 561{ 562 /* 563 * debug_printf("solid rect[(%d, %d), (%d, %d)], rgba[%f, %f, %f, %f]\n", 564 * x0, y0, x1, y1, color[0], color[1], color[2], color[3]); */ 565 566 renderer_draw_conditional(r, 4 * 8); 567 568 /* 1st vertex */ 569 add_vertex_color(r, x0, y0, color); 570 /* 2nd vertex */ 571 add_vertex_color(r, x1, y0, color); 572 /* 3rd vertex */ 573 add_vertex_color(r, x1, y1, color); 574 /* 4th vertex */ 575 add_vertex_color(r, x0, y1, color); 576} 577 578void 579renderer_draw_flush(struct xa_context *r) 580{ 581 renderer_draw_conditional(r, 0); 582} 583 584void 585renderer_begin_textures(struct xa_context *r) 586{ 587 r->attrs_per_vertex = 1 + r->num_bound_samplers; 588 r->buffer_size = 0; 589} 590 591void 592renderer_texture(struct xa_context *r, 593 int *pos, 594 int width, int height, 595 const float *src_matrix, 596 const float *mask_matrix) 597{ 598 struct pipe_sampler_view **sampler_view = r->bound_sampler_views; 599 600#if 0 601 if (src_matrix) { 602 debug_printf("src_matrix = \n"); 603 debug_printf("%f, %f, %f\n", src_matrix[0], src_matrix[1], src_matrix[2]); 604 debug_printf("%f, %f, %f\n", src_matrix[3], src_matrix[4], src_matrix[5]); 605 debug_printf("%f, %f, %f\n", src_matrix[6], src_matrix[7], src_matrix[8]); 606 } 607 if (mask_matrix) { 608 debug_printf("mask_matrix = \n"); 609 debug_printf("%f, %f, %f\n", mask_matrix[0], mask_matrix[1], mask_matrix[2]); 610 debug_printf("%f, %f, %f\n", mask_matrix[3], mask_matrix[4], mask_matrix[5]); 611 debug_printf("%f, %f, %f\n", mask_matrix[6], mask_matrix[7], mask_matrix[8]); 612 } 613#endif 614 615 switch(r->attrs_per_vertex) { 616 case 2: 617 renderer_draw_conditional(r, 4 * 8); 618 add_vertex_data1(r, 619 pos[0], pos[1], /* src */ 620 pos[4], pos[5], /* dst */ 621 width, height, 622 sampler_view[0]->texture, src_matrix); 623 break; 624 case 3: 625 renderer_draw_conditional(r, 4 * 12); 626 add_vertex_data2(r, 627 pos[0], pos[1], /* src */ 628 pos[2], pos[3], /* mask */ 629 pos[4], pos[5], /* dst */ 630 width, height, 631 sampler_view[0]->texture, sampler_view[1]->texture, 632 src_matrix, mask_matrix); 633 break; 634 default: 635 break; 636 } 637} 638