renderer.c revision e5968a5355f0165aa7f3f8e71a27df884e5a3efb
1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. All Rights Reserved. 4 * Copyright 2010 LunarG, Inc. 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 VMWARE 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 "renderer.h" 29 30#include "vg_context.h" 31#include "image.h" 32 33#include "pipe/p_context.h" 34#include "pipe/p_state.h" 35#include "util/u_inlines.h" 36#include "pipe/p_screen.h" 37#include "pipe/p_shader_tokens.h" 38 39#include "util/u_draw_quad.h" 40#include "util/u_simple_shaders.h" 41#include "util/u_memory.h" 42#include "util/u_sampler.h" 43 44#include "cso_cache/cso_context.h" 45#include "tgsi/tgsi_ureg.h" 46 47typedef enum { 48 RENDERER_STATE_INIT, 49 RENDERER_STATE_COPY, 50 RENDERER_STATE_DRAWTEX, 51 RENDERER_STATE_SCISSOR, 52 RENDERER_STATE_CLEAR, 53 RENDERER_STATE_FILTER, 54 NUM_RENDERER_STATES 55} RendererState; 56 57typedef enum { 58 RENDERER_VS_PLAIN, 59 RENDERER_VS_COLOR, 60 RENDERER_VS_TEXTURE, 61 NUM_RENDERER_VS 62} RendererVs; 63 64typedef enum { 65 RENDERER_FS_COLOR, 66 RENDERER_FS_TEXTURE, 67 RENDERER_FS_SCISSOR, 68 NUM_RENDERER_FS 69} RendererFs; 70 71struct renderer { 72 struct pipe_context *pipe; 73 struct vg_context *owner; 74 75 struct cso_context *cso; 76 77 void *fs; 78 79 VGfloat vertices[4][2][4]; 80 81 void *cached_vs[NUM_RENDERER_VS]; 82 void *cached_fs[NUM_RENDERER_FS]; 83 84 RendererState state; 85 86 /* state data */ 87 union { 88 struct { 89 VGint tex_width; 90 VGint tex_height; 91 } copy; 92 93 struct { 94 VGint tex_width; 95 VGint tex_height; 96 } drawtex; 97 98 struct { 99 VGboolean restore_dsa; 100 } scissor; 101 102 struct { 103 VGboolean use_sampler; 104 VGint tex_width, tex_height; 105 } filter; 106 } u; 107}; 108 109/** 110 * Return VG_TRUE if the renderer can use the resource as the asked bindings. 111 */ 112static VGboolean renderer_can_support(struct renderer *renderer, 113 struct pipe_resource *res, 114 unsigned bindings) 115{ 116 struct pipe_screen *screen = renderer->pipe->screen; 117 118 return screen->is_format_supported(screen, 119 res->format, res->target, 0, bindings, 0); 120} 121 122/** 123 * Create a simple vertex shader that passes through position and the given 124 * attribute. 125 */ 126static void *create_passthrough_vs(struct pipe_context *pipe, int semantic_name) 127{ 128 struct ureg_program *ureg; 129 struct ureg_src src[2], constants[2]; 130 struct ureg_dst dst[2], tmp; 131 int i; 132 133 ureg = ureg_create(TGSI_PROCESSOR_VERTEX); 134 if (!ureg) 135 return NULL; 136 137 /* position in surface coordinates */ 138 src[0] = ureg_DECL_vs_input(ureg, 0); 139 dst[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); 140 tmp = ureg_DECL_temporary(ureg); 141 for (i = 0; i < 2; i++) 142 constants[i] = ureg_DECL_constant(ureg, i); 143 144 /* transform to clipped coordinates */ 145 ureg_MUL(ureg, tmp, src[0], constants[0]); 146 ureg_ADD(ureg, tmp, ureg_src(tmp), constants[1]); 147 ureg_MOV(ureg, dst[0], ureg_src(tmp)); 148 149 if (semantic_name >= 0) { 150 src[1] = ureg_DECL_vs_input(ureg, 1); 151 dst[1] = ureg_DECL_output(ureg, semantic_name, 0); 152 ureg_MOV(ureg, dst[1], src[1]); 153 } 154 155 ureg_END(ureg); 156 157 return ureg_create_shader_and_destroy(ureg, pipe); 158} 159 160/** 161 * Set renderer vertex shader. 162 * 163 * This function modifies vertex_shader state. 164 */ 165static void renderer_set_vs(struct renderer *r, RendererVs id) 166{ 167 /* create as needed */ 168 if (!r->cached_vs[id]) { 169 int semantic_name = -1; 170 171 switch (id) { 172 case RENDERER_VS_PLAIN: 173 break; 174 case RENDERER_VS_COLOR: 175 semantic_name = TGSI_SEMANTIC_COLOR; 176 break; 177 case RENDERER_VS_TEXTURE: 178 semantic_name = TGSI_SEMANTIC_GENERIC; 179 break; 180 default: 181 assert(!"Unknown renderer vs id"); 182 break; 183 } 184 185 r->cached_vs[id] = create_passthrough_vs(r->pipe, semantic_name); 186 } 187 188 cso_set_vertex_shader_handle(r->cso, r->cached_vs[id]); 189} 190 191/** 192 * Create a simple fragment shader that sets the depth to 0.0f. 193 */ 194static void *create_scissor_fs(struct pipe_context *pipe) 195{ 196 struct ureg_program *ureg; 197 struct ureg_dst out; 198 struct ureg_src imm; 199 200 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); 201 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); 202 imm = ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 0.0f); 203 204 ureg_MOV(ureg, ureg_writemask(out, TGSI_WRITEMASK_Z), imm); 205 ureg_END(ureg); 206 207 return ureg_create_shader_and_destroy(ureg, pipe); 208} 209 210/** 211 * Set renderer fragment shader. 212 * 213 * This function modifies fragment_shader state. 214 */ 215static void renderer_set_fs(struct renderer *r, RendererFs id) 216{ 217 /* create as needed */ 218 if (!r->cached_fs[id]) { 219 void *fs = NULL; 220 221 switch (id) { 222 case RENDERER_FS_COLOR: 223 fs = util_make_fragment_passthrough_shader(r->pipe); 224 break; 225 case RENDERER_FS_TEXTURE: 226 fs = util_make_fragment_tex_shader(r->pipe, 227 TGSI_TEXTURE_2D, TGSI_INTERPOLATE_LINEAR); 228 break; 229 case RENDERER_FS_SCISSOR: 230 fs = create_scissor_fs(r->pipe); 231 break; 232 default: 233 assert(!"Unknown renderer fs id"); 234 break; 235 } 236 237 r->cached_fs[id] = fs; 238 } 239 240 cso_set_fragment_shader_handle(r->cso, r->cached_fs[id]); 241} 242 243/** 244 * Set renderer target. 245 * 246 * This function modifies framebuffer and viewport states. 247 */ 248static void renderer_set_target(struct renderer *r, 249 struct pipe_surface *cbuf, 250 struct pipe_surface *zsbuf, 251 VGboolean y0_top) 252{ 253 struct pipe_framebuffer_state fb; 254 255 memset(&fb, 0, sizeof(fb)); 256 fb.width = cbuf->width; 257 fb.height = cbuf->height; 258 fb.cbufs[0] = cbuf; 259 fb.nr_cbufs = 1; 260 fb.zsbuf = zsbuf; 261 cso_set_framebuffer(r->cso, &fb); 262 263 vg_set_viewport(r->owner, (y0_top) ? VEGA_Y0_TOP : VEGA_Y0_BOTTOM); 264} 265 266/** 267 * Set renderer blend state. Blending is disabled. 268 * 269 * This function modifies blend state. 270 */ 271static void renderer_set_blend(struct renderer *r, 272 VGbitfield channel_mask) 273{ 274 struct pipe_blend_state blend; 275 276 memset(&blend, 0, sizeof(blend)); 277 278 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; 279 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; 280 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; 281 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; 282 283 if (channel_mask & VG_RED) 284 blend.rt[0].colormask |= PIPE_MASK_R; 285 if (channel_mask & VG_GREEN) 286 blend.rt[0].colormask |= PIPE_MASK_G; 287 if (channel_mask & VG_BLUE) 288 blend.rt[0].colormask |= PIPE_MASK_B; 289 if (channel_mask & VG_ALPHA) 290 blend.rt[0].colormask |= PIPE_MASK_A; 291 292 cso_set_blend(r->cso, &blend); 293} 294 295/** 296 * Set renderer sampler and view states. 297 * 298 * This function modifies samplers and fragment_sampler_views states. 299 */ 300static void renderer_set_samplers(struct renderer *r, 301 uint num_views, 302 struct pipe_sampler_view **views) 303{ 304 struct pipe_sampler_state sampler; 305 unsigned tex_filter = PIPE_TEX_FILTER_NEAREST; 306 unsigned tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 307 uint i; 308 309 memset(&sampler, 0, sizeof(sampler)); 310 311 sampler.min_img_filter = tex_filter; 312 sampler.mag_img_filter = tex_filter; 313 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 314 315 sampler.wrap_s = tex_wrap; 316 sampler.wrap_t = tex_wrap; 317 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 318 319 sampler.normalized_coords = 1; 320 321 /* set samplers */ 322 for (i = 0; i < num_views; i++) 323 cso_single_sampler(r->cso, i, &sampler); 324 cso_single_sampler_done(r->cso); 325 326 /* set views */ 327 cso_set_fragment_sampler_views(r->cso, num_views, views); 328} 329 330/** 331 * Set custom renderer fragment shader, and optionally set samplers and views 332 * and upload the fragment constant buffer. 333 * 334 * This function modifies fragment_shader, samplers and fragment_sampler_views 335 * states. 336 */ 337static void renderer_set_custom_fs(struct renderer *renderer, 338 void *fs, 339 const struct pipe_sampler_state **samplers, 340 struct pipe_sampler_view **views, 341 VGint num_samplers, 342 const void *const_buffer, 343 VGint const_buffer_len) 344{ 345 cso_set_fragment_shader_handle(renderer->cso, fs); 346 347 /* set samplers and views */ 348 if (num_samplers) { 349 cso_set_samplers(renderer->cso, num_samplers, samplers); 350 cso_set_fragment_sampler_views(renderer->cso, num_samplers, views); 351 } 352 353 /* upload fs constant buffer */ 354 if (const_buffer_len) { 355 struct pipe_resource *cbuf; 356 357 cbuf = pipe_buffer_create(renderer->pipe->screen, 358 PIPE_BIND_CONSTANT_BUFFER, const_buffer_len); 359 pipe_buffer_write(renderer->pipe, cbuf, 0, 360 const_buffer_len, const_buffer); 361 renderer->pipe->set_constant_buffer(renderer->pipe, 362 PIPE_SHADER_FRAGMENT, 0, cbuf); 363 364 /* destroy cbuf automatically */ 365 pipe_resource_reference(&cbuf, NULL); 366 } 367} 368 369/** 370 * Setup renderer quad position. 371 */ 372static void renderer_quad_pos(struct renderer *r, 373 VGfloat x0, VGfloat y0, 374 VGfloat x1, VGfloat y1, 375 VGboolean scissor) 376{ 377 VGfloat z; 378 379 /* the depth test is used for scissoring */ 380 z = (scissor) ? 0.0f : 1.0f; 381 382 /* positions */ 383 r->vertices[0][0][0] = x0; 384 r->vertices[0][0][1] = y0; 385 r->vertices[0][0][2] = z; 386 387 r->vertices[1][0][0] = x1; 388 r->vertices[1][0][1] = y0; 389 r->vertices[1][0][2] = z; 390 391 r->vertices[2][0][0] = x1; 392 r->vertices[2][0][1] = y1; 393 r->vertices[2][0][2] = z; 394 395 r->vertices[3][0][0] = x0; 396 r->vertices[3][0][1] = y1; 397 r->vertices[3][0][2] = z; 398} 399 400/** 401 * Setup renderer quad texture coordinates. 402 */ 403static void renderer_quad_texcoord(struct renderer *r, 404 VGfloat x0, VGfloat y0, 405 VGfloat x1, VGfloat y1, 406 VGint tex_width, VGint tex_height) 407{ 408 VGfloat s0, t0, s1, t1, r0, q0; 409 VGint i; 410 411 s0 = x0 / tex_width; 412 s1 = x1 / tex_width; 413 t0 = y0 / tex_height; 414 t1 = y1 / tex_height; 415 r0 = 0.0f; 416 q0 = 1.0f; 417 418 /* texcoords */ 419 r->vertices[0][1][0] = s0; 420 r->vertices[0][1][1] = t0; 421 422 r->vertices[1][1][0] = s1; 423 r->vertices[1][1][1] = t0; 424 425 r->vertices[2][1][0] = s1; 426 r->vertices[2][1][1] = t1; 427 428 r->vertices[3][1][0] = s0; 429 r->vertices[3][1][1] = t1; 430 431 for (i = 0; i < 4; i++) { 432 r->vertices[i][1][2] = r0; 433 r->vertices[i][1][3] = q0; 434 } 435} 436 437/** 438 * Draw renderer quad. 439 */ 440static void renderer_quad_draw(struct renderer *r) 441{ 442 struct pipe_resource *buf; 443 444 buf = pipe_user_buffer_create(r->pipe->screen, 445 r->vertices, 446 sizeof(r->vertices), 447 PIPE_BIND_VERTEX_BUFFER); 448 if (buf) { 449 cso_set_vertex_elements(r->cso, 2, r->owner->velems); 450 util_draw_vertex_buffer(r->pipe, buf, 0, 451 PIPE_PRIM_TRIANGLE_FAN, 452 Elements(r->vertices), /* verts */ 453 Elements(r->vertices[0])); /* attribs/vert */ 454 455 pipe_resource_reference(&buf, NULL); 456 } 457} 458 459/** 460 * Prepare the renderer for copying. 461 */ 462VGboolean renderer_copy_begin(struct renderer *renderer, 463 struct pipe_surface *dst, 464 VGboolean y0_top, 465 struct pipe_sampler_view *src) 466{ 467 assert(renderer->state == RENDERER_STATE_INIT); 468 469 /* sanity check */ 470 if (!renderer_can_support(renderer, 471 dst->texture, PIPE_BIND_RENDER_TARGET) || 472 !renderer_can_support(renderer, 473 src->texture, PIPE_BIND_SAMPLER_VIEW)) 474 return VG_FALSE; 475 476 cso_save_framebuffer(renderer->cso); 477 cso_save_viewport(renderer->cso); 478 cso_save_blend(renderer->cso); 479 cso_save_samplers(renderer->cso); 480 cso_save_fragment_sampler_views(renderer->cso); 481 cso_save_fragment_shader(renderer->cso); 482 cso_save_vertex_shader(renderer->cso); 483 484 renderer_set_target(renderer, dst, NULL, y0_top); 485 486 renderer_set_blend(renderer, ~0); 487 renderer_set_samplers(renderer, 1, &src); 488 489 renderer_set_fs(renderer, RENDERER_FS_TEXTURE); 490 renderer_set_vs(renderer, RENDERER_VS_TEXTURE); 491 492 /* remember the texture size */ 493 renderer->u.copy.tex_width = src->texture->width0; 494 renderer->u.copy.tex_height = src->texture->height0; 495 renderer->state = RENDERER_STATE_COPY; 496 497 return VG_TRUE; 498} 499 500/** 501 * Draw into the destination rectangle given by (x, y, w, h). The texture is 502 * sampled from within the rectangle given by (sx, sy, sw, sh). 503 * 504 * The coordinates are in surface coordinates. 505 */ 506void renderer_copy(struct renderer *renderer, 507 VGint x, VGint y, VGint w, VGint h, 508 VGint sx, VGint sy, VGint sw, VGint sh) 509{ 510 assert(renderer->state == RENDERER_STATE_COPY); 511 512 /* there is no depth buffer for scissoring anyway */ 513 renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE); 514 renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh, 515 renderer->u.copy.tex_width, 516 renderer->u.copy.tex_height); 517 518 renderer_quad_draw(renderer); 519} 520 521/** 522 * End copying and restore the states. 523 */ 524void renderer_copy_end(struct renderer *renderer) 525{ 526 assert(renderer->state == RENDERER_STATE_COPY); 527 528 cso_restore_framebuffer(renderer->cso); 529 cso_restore_viewport(renderer->cso); 530 cso_restore_blend(renderer->cso); 531 cso_restore_samplers(renderer->cso); 532 cso_restore_fragment_sampler_views(renderer->cso); 533 cso_restore_fragment_shader(renderer->cso); 534 cso_restore_vertex_shader(renderer->cso); 535 536 renderer->state = RENDERER_STATE_INIT; 537} 538 539/** 540 * Prepare the renderer for textured drawing. 541 */ 542VGboolean renderer_drawtex_begin(struct renderer *renderer, 543 struct pipe_sampler_view *src) 544{ 545 assert(renderer->state == RENDERER_STATE_INIT); 546 547 if (!renderer_can_support(renderer, src->texture, PIPE_BIND_SAMPLER_VIEW)) 548 return VG_FALSE; 549 550 cso_save_blend(renderer->cso); 551 cso_save_samplers(renderer->cso); 552 cso_save_fragment_sampler_views(renderer->cso); 553 cso_save_fragment_shader(renderer->cso); 554 cso_save_vertex_shader(renderer->cso); 555 556 renderer_set_blend(renderer, ~0); 557 558 renderer_set_samplers(renderer, 1, &src); 559 560 renderer_set_fs(renderer, RENDERER_FS_TEXTURE); 561 renderer_set_vs(renderer, RENDERER_VS_TEXTURE); 562 563 /* remember the texture size */ 564 renderer->u.drawtex.tex_width = src->texture->width0; 565 renderer->u.drawtex.tex_height = src->texture->height0; 566 renderer->state = RENDERER_STATE_DRAWTEX; 567 568 return VG_TRUE; 569} 570 571/** 572 * Draw into the destination rectangle given by (x, y, w, h). The texture is 573 * sampled from within the rectangle given by (sx, sy, sw, sh). 574 * 575 * The coordinates are in surface coordinates. 576 */ 577void renderer_drawtex(struct renderer *renderer, 578 VGint x, VGint y, VGint w, VGint h, 579 VGint sx, VGint sy, VGint sw, VGint sh) 580{ 581 assert(renderer->state == RENDERER_STATE_DRAWTEX); 582 583 /* with scissoring */ 584 renderer_quad_pos(renderer, x, y, x + w, y + h, VG_TRUE); 585 renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh, 586 renderer->u.drawtex.tex_width, 587 renderer->u.drawtex.tex_height); 588 589 renderer_quad_draw(renderer); 590} 591 592/** 593 * End textured drawing and restore the states. 594 */ 595void renderer_drawtex_end(struct renderer *renderer) 596{ 597 assert(renderer->state == RENDERER_STATE_DRAWTEX); 598 599 cso_restore_blend(renderer->cso); 600 cso_restore_samplers(renderer->cso); 601 cso_restore_fragment_sampler_views(renderer->cso); 602 cso_restore_fragment_shader(renderer->cso); 603 cso_restore_vertex_shader(renderer->cso); 604 605 renderer->state = RENDERER_STATE_INIT; 606} 607 608/** 609 * Prepare the renderer for scissor update. This will reset the depth buffer 610 * to 1.0f. 611 */ 612VGboolean renderer_scissor_begin(struct renderer *renderer, 613 VGboolean restore_dsa) 614{ 615 struct pipe_depth_stencil_alpha_state dsa; 616 617 assert(renderer->state == RENDERER_STATE_INIT); 618 619 if (restore_dsa) 620 cso_save_depth_stencil_alpha(renderer->cso); 621 cso_save_blend(renderer->cso); 622 cso_save_fragment_shader(renderer->cso); 623 624 /* enable depth writes */ 625 memset(&dsa, 0, sizeof(dsa)); 626 dsa.depth.enabled = 1; 627 dsa.depth.writemask = 1; 628 dsa.depth.func = PIPE_FUNC_ALWAYS; 629 cso_set_depth_stencil_alpha(renderer->cso, &dsa); 630 631 /* disable color writes */ 632 renderer_set_blend(renderer, 0); 633 renderer_set_fs(renderer, RENDERER_FS_SCISSOR); 634 635 renderer->u.scissor.restore_dsa = restore_dsa; 636 renderer->state = RENDERER_STATE_SCISSOR; 637 638 /* clear the depth buffer to 1.0f */ 639 renderer->pipe->clear(renderer->pipe, 640 PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0f, 0); 641 642 return VG_TRUE; 643} 644 645/** 646 * Add a scissor rectangle. Depth values inside the rectangle will be set to 647 * 0.0f. 648 */ 649void renderer_scissor(struct renderer *renderer, 650 VGint x, VGint y, VGint width, VGint height) 651{ 652 assert(renderer->state == RENDERER_STATE_SCISSOR); 653 654 renderer_quad_pos(renderer, x, y, x + width, y + height, VG_FALSE); 655 renderer_quad_draw(renderer); 656} 657 658/** 659 * End scissor update and restore the states. 660 */ 661void renderer_scissor_end(struct renderer *renderer) 662{ 663 assert(renderer->state == RENDERER_STATE_SCISSOR); 664 665 if (renderer->u.scissor.restore_dsa) 666 cso_restore_depth_stencil_alpha(renderer->cso); 667 cso_restore_blend(renderer->cso); 668 cso_restore_fragment_shader(renderer->cso); 669 670 renderer->state = RENDERER_STATE_INIT; 671} 672 673/** 674 * Prepare the renderer for clearing. 675 */ 676VGboolean renderer_clear_begin(struct renderer *renderer) 677{ 678 assert(renderer->state == RENDERER_STATE_INIT); 679 680 cso_save_blend(renderer->cso); 681 cso_save_fragment_shader(renderer->cso); 682 cso_save_vertex_shader(renderer->cso); 683 684 renderer_set_blend(renderer, ~0); 685 renderer_set_fs(renderer, RENDERER_FS_COLOR); 686 renderer_set_vs(renderer, RENDERER_VS_COLOR); 687 688 renderer->state = RENDERER_STATE_CLEAR; 689 690 return VG_TRUE; 691} 692 693/** 694 * Clear the framebuffer with the specified region and color. 695 * 696 * The coordinates are in surface coordinates. 697 */ 698void renderer_clear(struct renderer *renderer, 699 VGint x, VGint y, VGint width, VGint height, 700 const VGfloat color[4]) 701{ 702 VGuint i; 703 704 assert(renderer->state == RENDERER_STATE_CLEAR); 705 706 renderer_quad_pos(renderer, x, y, x + width, y + height, VG_TRUE); 707 for (i = 0; i < 4; i++) 708 memcpy(renderer->vertices[i][1], color, sizeof(VGfloat) * 4); 709 710 renderer_quad_draw(renderer); 711} 712 713/** 714 * End clearing and retore the states. 715 */ 716void renderer_clear_end(struct renderer *renderer) 717{ 718 assert(renderer->state == RENDERER_STATE_CLEAR); 719 720 cso_restore_blend(renderer->cso); 721 cso_restore_fragment_shader(renderer->cso); 722 cso_restore_vertex_shader(renderer->cso); 723 724 renderer->state = RENDERER_STATE_INIT; 725} 726 727/** 728 * Prepare the renderer for image filtering. 729 */ 730VGboolean renderer_filter_begin(struct renderer *renderer, 731 struct pipe_resource *dst, 732 VGboolean y0_top, 733 VGbitfield channel_mask, 734 const struct pipe_sampler_state **samplers, 735 struct pipe_sampler_view **views, 736 VGint num_samplers, 737 void *fs, 738 const void *const_buffer, 739 VGint const_buffer_len) 740{ 741 struct pipe_surface *surf; 742 743 assert(renderer->state == RENDERER_STATE_INIT); 744 745 if (!fs) 746 return VG_FALSE; 747 if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET)) 748 return VG_FALSE; 749 750 surf = renderer->pipe->screen->get_tex_surface(renderer->pipe->screen, 751 dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET); 752 if (!surf) 753 return VG_FALSE; 754 755 cso_save_framebuffer(renderer->cso); 756 cso_save_viewport(renderer->cso); 757 cso_save_blend(renderer->cso); 758 759 /* set the image as the target */ 760 renderer_set_target(renderer, surf, NULL, y0_top); 761 pipe_surface_reference(&surf, NULL); 762 763 renderer_set_blend(renderer, channel_mask); 764 765 if (num_samplers) { 766 struct pipe_resource *tex; 767 768 cso_save_samplers(renderer->cso); 769 cso_save_fragment_sampler_views(renderer->cso); 770 cso_save_fragment_shader(renderer->cso); 771 cso_save_vertex_shader(renderer->cso); 772 773 renderer_set_custom_fs(renderer, fs, 774 samplers, views, num_samplers, 775 const_buffer, const_buffer_len); 776 renderer_set_vs(renderer, RENDERER_VS_TEXTURE); 777 778 tex = views[0]->texture; 779 renderer->u.filter.tex_width = tex->width0; 780 renderer->u.filter.tex_height = tex->height0; 781 renderer->u.filter.use_sampler = VG_TRUE; 782 } 783 else { 784 cso_save_fragment_shader(renderer->cso); 785 786 renderer_set_custom_fs(renderer, fs, NULL, NULL, 0, 787 const_buffer, const_buffer_len); 788 789 renderer->u.filter.use_sampler = VG_FALSE; 790 } 791 792 renderer->state = RENDERER_STATE_FILTER; 793 794 return VG_TRUE; 795} 796 797/** 798 * Draw into a rectangle of the destination with the specified region of the 799 * texture(s). 800 * 801 * The coordinates are in surface coordinates. 802 */ 803void renderer_filter(struct renderer *renderer, 804 VGint x, VGint y, VGint w, VGint h, 805 VGint sx, VGint sy, VGint sw, VGint sh) 806{ 807 assert(renderer->state == RENDERER_STATE_FILTER); 808 809 renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE); 810 if (renderer->u.filter.use_sampler) { 811 renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh, 812 renderer->u.filter.tex_width, 813 renderer->u.filter.tex_height); 814 } 815 816 renderer_quad_draw(renderer); 817} 818 819/** 820 * End image filtering and restore the states. 821 */ 822void renderer_filter_end(struct renderer *renderer) 823{ 824 assert(renderer->state == RENDERER_STATE_FILTER); 825 826 if (renderer->u.filter.use_sampler) { 827 cso_restore_samplers(renderer->cso); 828 cso_restore_fragment_sampler_views(renderer->cso); 829 cso_restore_vertex_shader(renderer->cso); 830 } 831 832 cso_restore_framebuffer(renderer->cso); 833 cso_restore_viewport(renderer->cso); 834 cso_restore_blend(renderer->cso); 835 cso_restore_fragment_shader(renderer->cso); 836 837 renderer->state = RENDERER_STATE_INIT; 838} 839 840static void setup_shaders(struct renderer *ctx) 841{ 842 struct pipe_context *pipe = ctx->pipe; 843 /* fragment shader */ 844 ctx->fs = util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D, 845 TGSI_INTERPOLATE_LINEAR); 846} 847 848struct renderer * renderer_create(struct vg_context *owner) 849{ 850 VGint i; 851 struct renderer *renderer = CALLOC_STRUCT(renderer); 852 853 if (!renderer) 854 return NULL; 855 856 renderer->owner = owner; 857 renderer->pipe = owner->pipe; 858 renderer->cso = owner->cso_context; 859 860 setup_shaders(renderer); 861 862 /* init vertex data that doesn't change */ 863 for (i = 0; i < 4; i++) 864 renderer->vertices[i][0][3] = 1.0f; /* w */ 865 866 renderer->state = RENDERER_STATE_INIT; 867 868 return renderer; 869} 870 871void renderer_destroy(struct renderer *ctx) 872{ 873 int i; 874 875 for (i = 0; i < NUM_RENDERER_VS; i++) { 876 if (ctx->cached_vs[i]) 877 cso_delete_vertex_shader(ctx->cso, ctx->cached_vs[i]); 878 } 879 for (i = 0; i < NUM_RENDERER_FS; i++) { 880 if (ctx->cached_fs[i]) 881 cso_delete_fragment_shader(ctx->cso, ctx->cached_fs[i]); 882 } 883 884#if 0 885 if (ctx->fs) { 886 cso_delete_fragment_shader(ctx->cso, ctx->fs); 887 ctx->fs = NULL; 888 } 889#endif 890 FREE(ctx); 891} 892 893void renderer_draw_quad(struct renderer *r, 894 VGfloat x1, VGfloat y1, 895 VGfloat x2, VGfloat y2, 896 VGfloat depth) 897{ 898 assert(r->state == RENDERER_STATE_INIT); 899 assert(floatsEqual(depth, 0.0f)); 900 901 renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE); 902 renderer_quad_draw(r); 903} 904 905void renderer_draw_texture(struct renderer *r, 906 struct pipe_resource *tex, 907 VGfloat x1offset, VGfloat y1offset, 908 VGfloat x2offset, VGfloat y2offset, 909 VGfloat x1, VGfloat y1, 910 VGfloat x2, VGfloat y2) 911{ 912 assert(r->state == RENDERER_STATE_INIT); 913 assert(tex->width0 != 0); 914 assert(tex->height0 != 0); 915 916 cso_save_vertex_shader(r->cso); 917 918 renderer_set_vs(r, RENDERER_VS_TEXTURE); 919 920 renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE); 921 renderer_quad_texcoord(r, x1offset, y1offset, 922 x2offset, y2offset, tex->width0, tex->height0); 923 renderer_quad_draw(r); 924 925 cso_restore_vertex_shader(r->cso); 926} 927 928void renderer_copy_texture(struct renderer *ctx, 929 struct pipe_sampler_view *src, 930 VGfloat sx1, VGfloat sy1, 931 VGfloat sx2, VGfloat sy2, 932 struct pipe_resource *dst, 933 VGfloat dx1, VGfloat dy1, 934 VGfloat dx2, VGfloat dy2) 935{ 936 struct pipe_surface *surf; 937 VGint x, y, w, h, sx, sy, sw, sh; 938 939 /* get the destination surface */ 940 surf = ctx->pipe->screen->get_tex_surface(ctx->pipe->screen, 941 dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET); 942 if (!surf) 943 return; 944 945 assert(ctx->state == RENDERER_STATE_INIT); 946 assert(src->texture->width0 != 0); 947 assert(src->texture->height0 != 0); 948 assert(dst->width0 != 0); 949 assert(dst->height0 != 0); 950 951 x = (VGint) dx1; 952 y = (VGint) dy1; 953 w = (VGint) (dx2 - dx1); 954 h = (VGint) (dy2 - dy1); 955 assert(floatsEqual(x, dx1) && 956 floatsEqual(y, dy1) && 957 floatsEqual(w, (dx2 - dx1)) && 958 floatsEqual(h, (dy2 - dy1))); 959 960 sx = (VGint) sx1; 961 sy = (VGint) sy1; 962 sw = (VGint) (sx2 - sx1); 963 sh = (VGint) (sy2 - sy1); 964 assert(floatsEqual(sx, sx1) && 965 floatsEqual(sy, sy1) && 966 floatsEqual(sw, (sx2 - sx1)) && 967 floatsEqual(sh, (sy2 - sy1))); 968 969 if (renderer_copy_begin(ctx, surf, VG_TRUE, src)) { 970 renderer_copy(ctx, x, y, w, h, sx, sy, sw, sh); 971 renderer_copy_end(ctx); 972 } 973 974 pipe_surface_reference(&surf, NULL); 975} 976 977void renderer_copy_surface(struct renderer *ctx, 978 struct pipe_surface *src, 979 int srcX0, int srcY0, 980 int srcX1, int srcY1, 981 struct pipe_surface *dst, 982 int dstX0, int dstY0, 983 int dstX1, int dstY1, 984 float z, unsigned filter) 985{ 986 struct pipe_context *pipe = ctx->pipe; 987 struct pipe_screen *screen = pipe->screen; 988 struct pipe_sampler_view view_templ; 989 struct pipe_sampler_view *view; 990 struct pipe_resource texTemp, *tex; 991 struct pipe_subresource subsrc, subdst; 992 struct st_framebuffer *stfb = ctx->owner->draw_buffer; 993 const int srcW = abs(srcX1 - srcX0); 994 const int srcH = abs(srcY1 - srcY0); 995 const int srcLeft = MIN2(srcX0, srcX1); 996 const int srcTop = MIN2(srcY0, srcY1); 997 998 assert(filter == PIPE_TEX_MIPFILTER_NEAREST || 999 filter == PIPE_TEX_MIPFILTER_LINEAR); 1000 1001 if (srcLeft != srcX0) { 1002 /* left-right flip */ 1003 int tmp = dstX0; 1004 dstX0 = dstX1; 1005 dstX1 = tmp; 1006 } 1007 1008 if (srcTop != srcY0) { 1009 /* up-down flip */ 1010 int tmp = dstY0; 1011 dstY0 = dstY1; 1012 dstY1 = tmp; 1013 } 1014 1015 assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D, 1016 0, PIPE_BIND_SAMPLER_VIEW, 0)); 1017 assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D, 1018 0, PIPE_BIND_SAMPLER_VIEW, 0)); 1019 assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D, 1020 0, PIPE_BIND_RENDER_TARGET, 0)); 1021 1022 /* 1023 * XXX for now we're always creating a temporary texture. 1024 * Strictly speaking that's not always needed. 1025 */ 1026 1027 /* create temp texture */ 1028 memset(&texTemp, 0, sizeof(texTemp)); 1029 texTemp.target = PIPE_TEXTURE_2D; 1030 texTemp.format = src->format; 1031 texTemp.last_level = 0; 1032 texTemp.width0 = srcW; 1033 texTemp.height0 = srcH; 1034 texTemp.depth0 = 1; 1035 texTemp.bind = PIPE_BIND_SAMPLER_VIEW; 1036 1037 tex = screen->resource_create(screen, &texTemp); 1038 if (!tex) 1039 return; 1040 1041 u_sampler_view_default_template(&view_templ, tex, tex->format); 1042 view = pipe->create_sampler_view(pipe, tex, &view_templ); 1043 1044 if (!view) 1045 return; 1046 1047 subdst.face = 0; 1048 subdst.level = 0; 1049 subsrc.face = src->face; 1050 subsrc.level = src->level; 1051 1052 pipe->resource_copy_region(pipe, 1053 tex, subdst, 0, 0, 0, /* dest */ 1054 src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */ 1055 srcW, srcH); /* size */ 1056 1057 assert(floatsEqual(z, 0.0f)); 1058 1059 /* draw */ 1060 if (stfb->strb->surface == dst) { 1061 /* transform back to surface coordinates */ 1062 dstY0 = dst->height - dstY0; 1063 dstY1 = dst->height - dstY1; 1064 1065 if (renderer_drawtex_begin(ctx, view)) { 1066 renderer_drawtex(ctx, 1067 dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0, 1068 0, 0, view->texture->width0, view->texture->height0); 1069 renderer_drawtex_end(ctx); 1070 } 1071 } 1072 else { 1073 if (renderer_copy_begin(ctx, dst, VG_TRUE, view)) { 1074 renderer_copy(ctx, 1075 dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0, 1076 0, 0, view->texture->width0, view->texture->height0); 1077 renderer_copy_end(ctx); 1078 } 1079 } 1080} 1081 1082void renderer_texture_quad(struct renderer *r, 1083 struct pipe_resource *tex, 1084 VGfloat x1offset, VGfloat y1offset, 1085 VGfloat x2offset, VGfloat y2offset, 1086 VGfloat x1, VGfloat y1, 1087 VGfloat x2, VGfloat y2, 1088 VGfloat x3, VGfloat y3, 1089 VGfloat x4, VGfloat y4) 1090{ 1091 const VGfloat z = 0.0f; 1092 1093 assert(r->state == RENDERER_STATE_INIT); 1094 assert(tex->width0 != 0); 1095 assert(tex->height0 != 0); 1096 1097 cso_save_vertex_shader(r->cso); 1098 1099 renderer_set_vs(r, RENDERER_VS_TEXTURE); 1100 1101 /* manually set up positions */ 1102 r->vertices[0][0][0] = x1; 1103 r->vertices[0][0][1] = y1; 1104 r->vertices[0][0][2] = z; 1105 1106 r->vertices[1][0][0] = x2; 1107 r->vertices[1][0][1] = y2; 1108 r->vertices[1][0][2] = z; 1109 1110 r->vertices[2][0][0] = x3; 1111 r->vertices[2][0][1] = y3; 1112 r->vertices[2][0][2] = z; 1113 1114 r->vertices[3][0][0] = x4; 1115 r->vertices[3][0][1] = y4; 1116 r->vertices[3][0][2] = z; 1117 1118 /* texcoords */ 1119 renderer_quad_texcoord(r, x1offset, y1offset, 1120 x2offset, y2offset, tex->width0, tex->height0); 1121 1122 renderer_quad_draw(r); 1123 1124 cso_restore_vertex_shader(r->cso); 1125} 1126