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