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