renderer.c revision e31a04ea3bc957b2a43b910b1f51807b12da18a6
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
32#include "pipe/p_context.h"
33#include "pipe/p_state.h"
34#include "util/u_inlines.h"
35#include "pipe/p_screen.h"
36#include "pipe/p_shader_tokens.h"
37
38#include "util/u_draw_quad.h"
39#include "util/u_simple_shaders.h"
40#include "util/u_memory.h"
41#include "util/u_sampler.h"
42
43#include "cso_cache/cso_context.h"
44#include "tgsi/tgsi_ureg.h"
45
46typedef enum {
47   RENDERER_STATE_INIT,
48   RENDERER_STATE_COPY,
49   RENDERER_STATE_DRAWTEX,
50   NUM_RENDERER_STATES
51} RendererState;
52
53typedef enum {
54   RENDERER_VS_PLAIN,
55   RENDERER_VS_COLOR,
56   RENDERER_VS_TEXTURE,
57   NUM_RENDERER_VS
58} RendererVs;
59
60typedef enum {
61   RENDERER_FS_COLOR,
62   RENDERER_FS_TEXTURE,
63   NUM_RENDERER_FS
64} RendererFs;
65
66struct renderer {
67   struct pipe_context *pipe;
68   struct vg_context *owner;
69
70   struct cso_context *cso;
71
72   void *fs;
73
74   VGfloat vertices[4][2][4];
75
76   void *cached_vs[NUM_RENDERER_VS];
77   void *cached_fs[NUM_RENDERER_FS];
78
79   RendererState state;
80
81   /* state data */
82   union {
83      struct {
84         VGint tex_width;
85         VGint tex_height;
86      } copy;
87
88      struct {
89         VGint tex_width;
90         VGint tex_height;
91      } drawtex;
92   } u;
93};
94
95/**
96 * Return VG_TRUE if the renderer can use the resource as the asked bindings.
97 */
98static VGboolean renderer_can_support(struct renderer *renderer,
99                                      struct pipe_resource *res,
100                                      unsigned bindings)
101{
102   struct pipe_screen *screen = renderer->pipe->screen;
103
104   return screen->is_format_supported(screen,
105         res->format, res->target, 0, bindings, 0);
106}
107
108/**
109 * Create a simple vertex shader that passes through position and the given
110 * attribute.
111 */
112static void *create_passthrough_vs(struct pipe_context *pipe, int semantic_name)
113{
114   struct ureg_program *ureg;
115   struct ureg_src src[2], constants[2];
116   struct ureg_dst dst[2], tmp;
117   int i;
118
119   ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
120   if (!ureg)
121      return NULL;
122
123   /* position in surface coordinates */
124   src[0] = ureg_DECL_vs_input(ureg, 0);
125   dst[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
126   tmp = ureg_DECL_temporary(ureg);
127   for (i = 0; i < 2; i++)
128      constants[i] = ureg_DECL_constant(ureg, i);
129
130   /* transform to clipped coordinates */
131   ureg_MUL(ureg, tmp, src[0], constants[0]);
132   ureg_ADD(ureg, tmp, ureg_src(tmp), constants[1]);
133   ureg_MOV(ureg, dst[0], ureg_src(tmp));
134
135   if (semantic_name >= 0) {
136      src[1] = ureg_DECL_vs_input(ureg, 1);
137      dst[1] = ureg_DECL_output(ureg, semantic_name, 0);
138      ureg_MOV(ureg, dst[1], src[1]);
139   }
140
141   ureg_END(ureg);
142
143   return ureg_create_shader_and_destroy(ureg, pipe);
144}
145
146/**
147 * Set renderer vertex shader.
148 *
149 * This function modifies vertex_shader state.
150 */
151static void renderer_set_vs(struct renderer *r, RendererVs id)
152{
153   /* create as needed */
154   if (!r->cached_vs[id]) {
155      int semantic_name = -1;
156
157      switch (id) {
158      case RENDERER_VS_PLAIN:
159         break;
160      case RENDERER_VS_COLOR:
161         semantic_name = TGSI_SEMANTIC_COLOR;
162         break;
163      case RENDERER_VS_TEXTURE:
164         semantic_name = TGSI_SEMANTIC_GENERIC;
165         break;
166      default:
167         assert(!"Unknown renderer vs id");
168         break;
169      }
170
171      r->cached_vs[id] = create_passthrough_vs(r->pipe, semantic_name);
172   }
173
174   cso_set_vertex_shader_handle(r->cso, r->cached_vs[id]);
175}
176
177/**
178 * Set renderer fragment shader.
179 *
180 * This function modifies fragment_shader state.
181 */
182static void renderer_set_fs(struct renderer *r, RendererFs id)
183{
184   /* create as needed */
185   if (!r->cached_fs[id]) {
186      void *fs = NULL;
187
188      switch (id) {
189      case RENDERER_FS_COLOR:
190         fs = util_make_fragment_passthrough_shader(r->pipe);
191         break;
192      case RENDERER_FS_TEXTURE:
193         fs = util_make_fragment_tex_shader(r->pipe,
194               TGSI_TEXTURE_2D, TGSI_INTERPOLATE_LINEAR);
195         break;
196      default:
197         assert(!"Unknown renderer fs id");
198         break;
199      }
200
201      r->cached_fs[id] = fs;
202   }
203
204   cso_set_fragment_shader_handle(r->cso, r->cached_fs[id]);
205}
206
207/**
208 * Set renderer target.
209 *
210 * This function modifies framebuffer and viewport states.
211 */
212static void renderer_set_target(struct renderer *r,
213                                struct pipe_surface *cbuf,
214                                struct pipe_surface *zsbuf,
215                                VGboolean y0_top)
216{
217   struct pipe_framebuffer_state fb;
218
219   memset(&fb, 0, sizeof(fb));
220   fb.width = cbuf->width;
221   fb.height = cbuf->height;
222   fb.cbufs[0] = cbuf;
223   fb.nr_cbufs = 1;
224   fb.zsbuf = zsbuf;
225   cso_set_framebuffer(r->cso, &fb);
226
227   vg_set_viewport(r->owner, (y0_top) ? VEGA_Y0_TOP : VEGA_Y0_BOTTOM);
228}
229
230/**
231 * Set renderer blend state.  Blending is disabled.
232 *
233 * This function modifies blend state.
234 */
235static void renderer_set_blend(struct renderer *r,
236                               VGbitfield channel_mask)
237{
238   struct pipe_blend_state blend;
239
240   memset(&blend, 0, sizeof(blend));
241
242   blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
243   blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
244   blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
245   blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
246
247   if (channel_mask & VG_RED)
248      blend.rt[0].colormask |= PIPE_MASK_R;
249   if (channel_mask & VG_GREEN)
250      blend.rt[0].colormask |= PIPE_MASK_G;
251   if (channel_mask & VG_BLUE)
252      blend.rt[0].colormask |= PIPE_MASK_B;
253   if (channel_mask & VG_ALPHA)
254      blend.rt[0].colormask |= PIPE_MASK_A;
255
256   cso_set_blend(r->cso, &blend);
257}
258
259/**
260 * Set renderer sampler and view states.
261 *
262 * This function modifies samplers and fragment_sampler_views states.
263 */
264static void renderer_set_samplers(struct renderer *r,
265                                  uint num_views,
266                                  struct pipe_sampler_view **views)
267{
268   struct pipe_sampler_state sampler;
269   unsigned tex_filter = PIPE_TEX_FILTER_NEAREST;
270   unsigned tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
271   uint i;
272
273   memset(&sampler, 0, sizeof(sampler));
274
275   sampler.min_img_filter = tex_filter;
276   sampler.mag_img_filter = tex_filter;
277   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
278
279   sampler.wrap_s = tex_wrap;
280   sampler.wrap_t = tex_wrap;
281   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
282
283   sampler.normalized_coords = 1;
284
285   /* set samplers */
286   for (i = 0; i < num_views; i++)
287      cso_single_sampler(r->cso, i, &sampler);
288   cso_single_sampler_done(r->cso);
289
290   /* set views */
291   cso_set_fragment_sampler_views(r->cso, num_views, views);
292}
293
294/**
295 * Setup renderer quad position.
296 */
297static void renderer_quad_pos(struct renderer *r,
298                              VGfloat x0, VGfloat y0,
299                              VGfloat x1, VGfloat y1,
300                              VGboolean scissor)
301{
302   VGfloat z;
303
304   /* the depth test is used for scissoring */
305   z = (scissor) ? 0.0f : 1.0f;
306
307   /* positions */
308   r->vertices[0][0][0] = x0;
309   r->vertices[0][0][1] = y0;
310   r->vertices[0][0][2] = z;
311
312   r->vertices[1][0][0] = x1;
313   r->vertices[1][0][1] = y0;
314   r->vertices[1][0][2] = z;
315
316   r->vertices[2][0][0] = x1;
317   r->vertices[2][0][1] = y1;
318   r->vertices[2][0][2] = z;
319
320   r->vertices[3][0][0] = x0;
321   r->vertices[3][0][1] = y1;
322   r->vertices[3][0][2] = z;
323}
324
325/**
326 * Setup renderer quad texture coordinates.
327 */
328static void renderer_quad_texcoord(struct renderer *r,
329                                   VGfloat x0, VGfloat y0,
330                                   VGfloat x1, VGfloat y1,
331                                   VGint tex_width, VGint tex_height)
332{
333   VGfloat s0, t0, s1, t1, r0, q0;
334   VGint i;
335
336   s0 = x0 / tex_width;
337   s1 = x1 / tex_width;
338   t0 = y0 / tex_height;
339   t1 = y1 / tex_height;
340   r0 = 0.0f;
341   q0 = 1.0f;
342
343   /* texcoords */
344   r->vertices[0][1][0] = s0;
345   r->vertices[0][1][1] = t0;
346
347   r->vertices[1][1][0] = s1;
348   r->vertices[1][1][1] = t0;
349
350   r->vertices[2][1][0] = s1;
351   r->vertices[2][1][1] = t1;
352
353   r->vertices[3][1][0] = s0;
354   r->vertices[3][1][1] = t1;
355
356   for (i = 0; i < 4; i++) {
357      r->vertices[i][1][2] = r0;
358      r->vertices[i][1][3] = q0;
359   }
360}
361
362/**
363 * Draw renderer quad.
364 */
365static void renderer_quad_draw(struct renderer *r)
366{
367   struct pipe_resource *buf;
368
369   buf = pipe_user_buffer_create(r->pipe->screen,
370                                 r->vertices,
371                                 sizeof(r->vertices),
372                                 PIPE_BIND_VERTEX_BUFFER);
373   if (buf) {
374      cso_set_vertex_elements(r->cso, 2, r->owner->velems);
375      util_draw_vertex_buffer(r->pipe, buf, 0,
376                              PIPE_PRIM_TRIANGLE_FAN,
377                              Elements(r->vertices),     /* verts */
378                              Elements(r->vertices[0])); /* attribs/vert */
379
380      pipe_resource_reference(&buf, NULL);
381   }
382}
383
384/**
385 * Prepare the renderer for copying.
386 */
387VGboolean renderer_copy_begin(struct renderer *renderer,
388                              struct pipe_surface *dst,
389                              VGboolean y0_top,
390                              struct pipe_sampler_view *src)
391{
392   assert(renderer->state == RENDERER_STATE_INIT);
393
394   /* sanity check */
395   if (!renderer_can_support(renderer,
396            dst->texture, PIPE_BIND_RENDER_TARGET) ||
397       !renderer_can_support(renderer,
398          src->texture, PIPE_BIND_SAMPLER_VIEW))
399      return VG_FALSE;
400
401   cso_save_framebuffer(renderer->cso);
402   cso_save_viewport(renderer->cso);
403   cso_save_blend(renderer->cso);
404   cso_save_samplers(renderer->cso);
405   cso_save_fragment_sampler_views(renderer->cso);
406   cso_save_fragment_shader(renderer->cso);
407   cso_save_vertex_shader(renderer->cso);
408
409   renderer_set_target(renderer, dst, NULL, y0_top);
410
411   renderer_set_blend(renderer, ~0);
412   renderer_set_samplers(renderer, 1, &src);
413
414   renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
415   renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
416
417   /* remember the texture size */
418   renderer->u.copy.tex_width = src->texture->width0;
419   renderer->u.copy.tex_height = src->texture->height0;
420   renderer->state = RENDERER_STATE_COPY;
421
422   return VG_TRUE;
423}
424
425/**
426 * Draw into the destination rectangle given by (x, y, w, h).  The texture is
427 * sampled from within the rectangle given by (sx, sy, sw, sh).
428 *
429 * The coordinates are in surface coordinates.
430 */
431void renderer_copy(struct renderer *renderer,
432                   VGint x, VGint y, VGint w, VGint h,
433                   VGint sx, VGint sy, VGint sw, VGint sh)
434{
435   assert(renderer->state == RENDERER_STATE_COPY);
436
437   /* there is no depth buffer for scissoring anyway */
438   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE);
439   renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
440         renderer->u.copy.tex_width,
441         renderer->u.copy.tex_height);
442
443   renderer_quad_draw(renderer);
444}
445
446/**
447 * End copying and restore the states.
448 */
449void renderer_copy_end(struct renderer *renderer)
450{
451   assert(renderer->state == RENDERER_STATE_COPY);
452
453   cso_restore_framebuffer(renderer->cso);
454   cso_restore_viewport(renderer->cso);
455   cso_restore_blend(renderer->cso);
456   cso_restore_samplers(renderer->cso);
457   cso_restore_fragment_sampler_views(renderer->cso);
458   cso_restore_fragment_shader(renderer->cso);
459   cso_restore_vertex_shader(renderer->cso);
460
461   renderer->state = RENDERER_STATE_INIT;
462}
463
464/**
465 * Prepare the renderer for textured drawing.
466 */
467VGboolean renderer_drawtex_begin(struct renderer *renderer,
468                                 struct pipe_sampler_view *src)
469{
470   assert(renderer->state == RENDERER_STATE_INIT);
471
472   if (!renderer_can_support(renderer, src->texture, PIPE_BIND_SAMPLER_VIEW))
473      return VG_FALSE;
474
475   cso_save_blend(renderer->cso);
476   cso_save_samplers(renderer->cso);
477   cso_save_fragment_sampler_views(renderer->cso);
478   cso_save_fragment_shader(renderer->cso);
479   cso_save_vertex_shader(renderer->cso);
480
481   renderer_set_blend(renderer, ~0);
482
483   renderer_set_samplers(renderer, 1, &src);
484
485   renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
486   renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
487
488   /* remember the texture size */
489   renderer->u.drawtex.tex_width = src->texture->width0;
490   renderer->u.drawtex.tex_height = src->texture->height0;
491   renderer->state = RENDERER_STATE_DRAWTEX;
492
493   return VG_TRUE;
494}
495
496/**
497 * Draw into the destination rectangle given by (x, y, w, h).  The texture is
498 * sampled from within the rectangle given by (sx, sy, sw, sh).
499 *
500 * The coordinates are in surface coordinates.
501 */
502void renderer_drawtex(struct renderer *renderer,
503                      VGint x, VGint y, VGint w, VGint h,
504                      VGint sx, VGint sy, VGint sw, VGint sh)
505{
506   assert(renderer->state == RENDERER_STATE_DRAWTEX);
507
508   /* with scissoring */
509   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_TRUE);
510   renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
511         renderer->u.drawtex.tex_width,
512         renderer->u.drawtex.tex_height);
513
514   renderer_quad_draw(renderer);
515}
516
517/**
518 * End textured drawing and restore the states.
519 */
520void renderer_drawtex_end(struct renderer *renderer)
521{
522   assert(renderer->state == RENDERER_STATE_DRAWTEX);
523
524   cso_restore_blend(renderer->cso);
525   cso_restore_samplers(renderer->cso);
526   cso_restore_fragment_sampler_views(renderer->cso);
527   cso_restore_fragment_shader(renderer->cso);
528   cso_restore_vertex_shader(renderer->cso);
529
530   renderer->state = RENDERER_STATE_INIT;
531}
532
533static void setup_shaders(struct renderer *ctx)
534{
535   struct pipe_context *pipe = ctx->pipe;
536   /* fragment shader */
537   ctx->fs = util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D,
538                                           TGSI_INTERPOLATE_LINEAR);
539}
540
541struct renderer * renderer_create(struct vg_context *owner)
542{
543   VGint i;
544   struct renderer *renderer = CALLOC_STRUCT(renderer);
545
546   if (!renderer)
547      return NULL;
548
549   renderer->owner = owner;
550   renderer->pipe = owner->pipe;
551   renderer->cso = owner->cso_context;
552
553   setup_shaders(renderer);
554
555   /* init vertex data that doesn't change */
556   for (i = 0; i < 4; i++)
557      renderer->vertices[i][0][3] = 1.0f; /* w */
558
559   renderer->state = RENDERER_STATE_INIT;
560
561   return renderer;
562}
563
564void renderer_destroy(struct renderer *ctx)
565{
566   int i;
567
568   for (i = 0; i < NUM_RENDERER_VS; i++) {
569      if (ctx->cached_vs[i])
570         cso_delete_vertex_shader(ctx->cso, ctx->cached_vs[i]);
571   }
572   for (i = 0; i < NUM_RENDERER_FS; i++) {
573      if (ctx->cached_fs[i])
574         cso_delete_fragment_shader(ctx->cso, ctx->cached_fs[i]);
575   }
576
577#if 0
578   if (ctx->fs) {
579      cso_delete_fragment_shader(ctx->cso, ctx->fs);
580      ctx->fs = NULL;
581   }
582#endif
583   FREE(ctx);
584}
585
586void renderer_draw_quad(struct renderer *r,
587                        VGfloat x1, VGfloat y1,
588                        VGfloat x2, VGfloat y2,
589                        VGfloat depth)
590{
591   assert(r->state == RENDERER_STATE_INIT);
592   assert(floatsEqual(depth, 0.0f));
593
594   renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
595   renderer_quad_draw(r);
596}
597
598void renderer_draw_texture(struct renderer *r,
599                           struct pipe_resource *tex,
600                           VGfloat x1offset, VGfloat y1offset,
601                           VGfloat x2offset, VGfloat y2offset,
602                           VGfloat x1, VGfloat y1,
603                           VGfloat x2, VGfloat y2)
604{
605   assert(r->state == RENDERER_STATE_INIT);
606   assert(tex->width0 != 0);
607   assert(tex->height0 != 0);
608
609   cso_save_vertex_shader(r->cso);
610
611   renderer_set_vs(r, RENDERER_VS_TEXTURE);
612
613   renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
614   renderer_quad_texcoord(r, x1offset, y1offset,
615         x2offset, y2offset, tex->width0, tex->height0);
616   renderer_quad_draw(r);
617
618   cso_restore_vertex_shader(r->cso);
619}
620
621void renderer_copy_texture(struct renderer *ctx,
622                           struct pipe_sampler_view *src,
623                           VGfloat sx1, VGfloat sy1,
624                           VGfloat sx2, VGfloat sy2,
625                           struct pipe_resource *dst,
626                           VGfloat dx1, VGfloat dy1,
627                           VGfloat dx2, VGfloat dy2)
628{
629   struct pipe_surface *surf;
630   VGint x, y, w, h, sx, sy, sw, sh;
631
632   /* get the destination surface */
633   surf = ctx->pipe->screen->get_tex_surface(ctx->pipe->screen,
634         dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
635   if (!surf)
636      return;
637
638   assert(ctx->state == RENDERER_STATE_INIT);
639   assert(src->texture->width0 != 0);
640   assert(src->texture->height0 != 0);
641   assert(dst->width0 != 0);
642   assert(dst->height0 != 0);
643
644   x = (VGint) dx1;
645   y = (VGint) dy1;
646   w = (VGint) (dx2 - dx1);
647   h = (VGint) (dy2 - dy1);
648   assert(floatsEqual(x, dx1) &&
649          floatsEqual(y, dy1) &&
650          floatsEqual(w, (dx2 - dx1)) &&
651          floatsEqual(h, (dy2 - dy1)));
652
653   sx = (VGint) sx1;
654   sy = (VGint) sy1;
655   sw = (VGint) (sx2 - sx1);
656   sh = (VGint) (sy2 - sy1);
657   assert(floatsEqual(sx, sx1) &&
658          floatsEqual(sy, sy1) &&
659          floatsEqual(sw, (sx2 - sx1)) &&
660          floatsEqual(sh, (sy2 - sy1)));
661
662   if (renderer_copy_begin(ctx, surf, VG_TRUE, src)) {
663      renderer_copy(ctx, x, y, w, h, sx, sy, sw, sh);
664      renderer_copy_end(ctx);
665   }
666
667   pipe_surface_reference(&surf, NULL);
668}
669
670void renderer_copy_surface(struct renderer *ctx,
671                           struct pipe_surface *src,
672                           int srcX0, int srcY0,
673                           int srcX1, int srcY1,
674                           struct pipe_surface *dst,
675                           int dstX0, int dstY0,
676                           int dstX1, int dstY1,
677                           float z, unsigned filter)
678{
679   struct pipe_context *pipe = ctx->pipe;
680   struct pipe_screen *screen = pipe->screen;
681   struct pipe_sampler_view view_templ;
682   struct pipe_sampler_view *view;
683   struct pipe_resource texTemp, *tex;
684   struct pipe_subresource subsrc, subdst;
685   struct st_framebuffer *stfb = ctx->owner->draw_buffer;
686   const int srcW = abs(srcX1 - srcX0);
687   const int srcH = abs(srcY1 - srcY0);
688   const int srcLeft = MIN2(srcX0, srcX1);
689   const int srcTop = MIN2(srcY0, srcY1);
690
691   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
692          filter == PIPE_TEX_MIPFILTER_LINEAR);
693
694   if (srcLeft != srcX0) {
695      /* left-right flip */
696      int tmp = dstX0;
697      dstX0 = dstX1;
698      dstX1 = tmp;
699   }
700
701   if (srcTop != srcY0) {
702      /* up-down flip */
703      int tmp = dstY0;
704      dstY0 = dstY1;
705      dstY1 = tmp;
706   }
707
708   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
709                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
710   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
711                                      0, PIPE_BIND_SAMPLER_VIEW, 0));
712   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
713                                      0, PIPE_BIND_RENDER_TARGET, 0));
714
715   /*
716    * XXX for now we're always creating a temporary texture.
717    * Strictly speaking that's not always needed.
718    */
719
720   /* create temp texture */
721   memset(&texTemp, 0, sizeof(texTemp));
722   texTemp.target = PIPE_TEXTURE_2D;
723   texTemp.format = src->format;
724   texTemp.last_level = 0;
725   texTemp.width0 = srcW;
726   texTemp.height0 = srcH;
727   texTemp.depth0 = 1;
728   texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
729
730   tex = screen->resource_create(screen, &texTemp);
731   if (!tex)
732      return;
733
734   u_sampler_view_default_template(&view_templ, tex, tex->format);
735   view = pipe->create_sampler_view(pipe, tex, &view_templ);
736
737   if (!view)
738      return;
739
740   subdst.face = 0;
741   subdst.level = 0;
742   subsrc.face = src->face;
743   subsrc.level = src->level;
744
745   pipe->resource_copy_region(pipe,
746                              tex, subdst, 0, 0, 0,  /* dest */
747                              src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */
748                              srcW, srcH);     /* size */
749
750   assert(floatsEqual(z, 0.0f));
751
752   /* draw */
753   if (stfb->strb->surface == dst) {
754      /* transform back to surface coordinates */
755      dstY0 = dst->height - dstY0;
756      dstY1 = dst->height - dstY1;
757
758      if (renderer_drawtex_begin(ctx, view)) {
759         renderer_drawtex(ctx,
760               dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0,
761               0, 0, view->texture->width0, view->texture->height0);
762         renderer_drawtex_end(ctx);
763      }
764   }
765   else {
766      if (renderer_copy_begin(ctx, dst, VG_TRUE, view)) {
767         renderer_copy(ctx,
768               dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0,
769               0, 0, view->texture->width0, view->texture->height0);
770         renderer_copy_end(ctx);
771      }
772   }
773}
774
775void renderer_texture_quad(struct renderer *r,
776                           struct pipe_resource *tex,
777                           VGfloat x1offset, VGfloat y1offset,
778                           VGfloat x2offset, VGfloat y2offset,
779                           VGfloat x1, VGfloat y1,
780                           VGfloat x2, VGfloat y2,
781                           VGfloat x3, VGfloat y3,
782                           VGfloat x4, VGfloat y4)
783{
784   const VGfloat z = 0.0f;
785
786   assert(r->state == RENDERER_STATE_INIT);
787   assert(tex->width0 != 0);
788   assert(tex->height0 != 0);
789
790   cso_save_vertex_shader(r->cso);
791
792   renderer_set_vs(r, RENDERER_VS_TEXTURE);
793
794   /* manually set up positions */
795   r->vertices[0][0][0] = x1;
796   r->vertices[0][0][1] = y1;
797   r->vertices[0][0][2] = z;
798
799   r->vertices[1][0][0] = x2;
800   r->vertices[1][0][1] = y2;
801   r->vertices[1][0][2] = z;
802
803   r->vertices[2][0][0] = x3;
804   r->vertices[2][0][1] = y3;
805   r->vertices[2][0][2] = z;
806
807   r->vertices[3][0][0] = x4;
808   r->vertices[3][0][1] = y4;
809   r->vertices[3][0][2] = z;
810
811   /* texcoords */
812   renderer_quad_texcoord(r, x1offset, y1offset,
813         x2offset, y2offset, tex->width0, tex->height0);
814
815   renderer_quad_draw(r);
816
817   cso_restore_vertex_shader(r->cso);
818}
819