• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2008 VMware, Inc.
4  * 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 /**
29  * @file
30  * Copy/blit pixel rect between surfaces
31  *
32  * @author Brian Paul
33  */
34 
35 
36 #include "pipe/p_context.h"
37 #include "util/u_debug.h"
38 #include "pipe/p_defines.h"
39 #include "util/u_inlines.h"
40 #include "pipe/p_shader_tokens.h"
41 #include "pipe/p_state.h"
42 
43 #include "util/u_blit.h"
44 #include "util/u_draw_quad.h"
45 #include "util/u_format.h"
46 #include "util/u_math.h"
47 #include "util/u_memory.h"
48 #include "util/u_sampler.h"
49 #include "util/u_texture.h"
50 #include "util/u_simple_shaders.h"
51 
52 #include "cso_cache/cso_context.h"
53 
54 
55 struct blit_state
56 {
57    struct pipe_context *pipe;
58    struct cso_context *cso;
59 
60    struct pipe_blend_state blend_write_color;
61    struct pipe_depth_stencil_alpha_state dsa_keep_depthstencil;
62    struct pipe_rasterizer_state rasterizer;
63    struct pipe_sampler_state sampler;
64    struct pipe_viewport_state viewport;
65    struct pipe_vertex_element velem[2];
66 
67    void *vs;
68    void *fs[PIPE_MAX_TEXTURE_TYPES][TGSI_WRITEMASK_XYZW + 1][3];
69 
70    struct pipe_resource *vbuf;  /**< quad vertices */
71    unsigned vbuf_slot;
72 
73    float vertices[4][2][4];   /**< vertex/texcoords for quad */
74 };
75 
76 
77 /**
78  * Create state object for blit.
79  * Intended to be created once and re-used for many blit() calls.
80  */
81 struct blit_state *
util_create_blit(struct pipe_context * pipe,struct cso_context * cso)82 util_create_blit(struct pipe_context *pipe, struct cso_context *cso)
83 {
84    struct blit_state *ctx;
85    uint i;
86 
87    ctx = CALLOC_STRUCT(blit_state);
88    if (!ctx)
89       return NULL;
90 
91    ctx->pipe = pipe;
92    ctx->cso = cso;
93 
94    /* disabled blending/masking */
95    ctx->blend_write_color.rt[0].colormask = PIPE_MASK_RGBA;
96 
97    /* rasterizer */
98    ctx->rasterizer.cull_face = PIPE_FACE_NONE;
99    ctx->rasterizer.half_pixel_center = 1;
100    ctx->rasterizer.bottom_edge_rule = 1;
101    ctx->rasterizer.depth_clip = 1;
102 
103    /* samplers */
104    ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
105    ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
106    ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
107    ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
108    ctx->sampler.min_img_filter = 0; /* set later */
109    ctx->sampler.mag_img_filter = 0; /* set later */
110 
111    /* vertex elements state */
112    for (i = 0; i < 2; i++) {
113       ctx->velem[i].src_offset = i * 4 * sizeof(float);
114       ctx->velem[i].instance_divisor = 0;
115       ctx->velem[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso);
116       ctx->velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
117    }
118 
119    ctx->vbuf = NULL;
120 
121    /* init vertex data that doesn't change */
122    for (i = 0; i < 4; i++) {
123       ctx->vertices[i][0][3] = 1.0f; /* w */
124       ctx->vertices[i][1][3] = 1.0f; /* q */
125    }
126 
127    return ctx;
128 }
129 
130 
131 /**
132  * Destroy a blit context
133  */
134 void
util_destroy_blit(struct blit_state * ctx)135 util_destroy_blit(struct blit_state *ctx)
136 {
137    struct pipe_context *pipe = ctx->pipe;
138    unsigned i, j, k;
139 
140    if (ctx->vs)
141       pipe->delete_vs_state(pipe, ctx->vs);
142 
143    for (i = 0; i < ARRAY_SIZE(ctx->fs); i++) {
144       for (j = 0; j < ARRAY_SIZE(ctx->fs[i]); j++) {
145          for (k = 0; k < ARRAY_SIZE(ctx->fs[i][j]); k++) {
146             if (ctx->fs[i][j][k])
147                pipe->delete_fs_state(pipe, ctx->fs[i][j][k]);
148          }
149       }
150    }
151 
152    pipe_resource_reference(&ctx->vbuf, NULL);
153 
154    FREE(ctx);
155 }
156 
157 
158 /**
159  * Helper function to set the fragment shaders.
160  */
161 static inline void
set_fragment_shader(struct blit_state * ctx,uint writemask,enum pipe_format format,enum pipe_texture_target pipe_tex)162 set_fragment_shader(struct blit_state *ctx, uint writemask,
163                     enum pipe_format format,
164                     enum pipe_texture_target pipe_tex)
165 {
166    enum tgsi_return_type stype;
167    unsigned idx;
168 
169    if (util_format_is_pure_uint(format)) {
170       stype = TGSI_RETURN_TYPE_UINT;
171       idx = 0;
172    } else if (util_format_is_pure_sint(format)) {
173       stype = TGSI_RETURN_TYPE_SINT;
174       idx = 1;
175    } else {
176       stype = TGSI_RETURN_TYPE_FLOAT;
177       idx = 2;
178    }
179 
180    if (!ctx->fs[pipe_tex][writemask][idx]) {
181       unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex, 0);
182 
183       /* OpenGL does not allow blits from signed to unsigned integer
184        * or vice versa. */
185       ctx->fs[pipe_tex][writemask][idx] =
186          util_make_fragment_tex_shader_writemask(ctx->pipe, tgsi_tex,
187                                                  TGSI_INTERPOLATE_LINEAR,
188                                                  writemask,
189                                                  stype, stype, false, false);
190    }
191 
192    cso_set_fragment_shader_handle(ctx->cso, ctx->fs[pipe_tex][writemask][idx]);
193 }
194 
195 
196 /**
197  * Helper function to set the vertex shader.
198  */
199 static inline void
set_vertex_shader(struct blit_state * ctx)200 set_vertex_shader(struct blit_state *ctx)
201 {
202    /* vertex shader - still required to provide the linkage between
203     * fragment shader input semantics and vertex_element/buffers.
204     */
205    if (!ctx->vs) {
206       const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
207                                       TGSI_SEMANTIC_GENERIC };
208       const uint semantic_indexes[] = { 0, 0 };
209       ctx->vs = util_make_vertex_passthrough_shader(ctx->pipe, 2,
210                                                     semantic_names,
211                                                     semantic_indexes, FALSE);
212    }
213 
214    cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
215 }
216 
217 
218 /**
219  * Get offset of next free slot in vertex buffer for quad vertices.
220  */
221 static unsigned
get_next_slot(struct blit_state * ctx)222 get_next_slot( struct blit_state *ctx )
223 {
224    const unsigned max_slots = 4096 / sizeof ctx->vertices;
225 
226    if (ctx->vbuf_slot >= max_slots) {
227       pipe_resource_reference(&ctx->vbuf, NULL);
228       ctx->vbuf_slot = 0;
229    }
230 
231    if (!ctx->vbuf) {
232       ctx->vbuf = pipe_buffer_create(ctx->pipe->screen,
233                                      PIPE_BIND_VERTEX_BUFFER,
234                                      PIPE_USAGE_STREAM,
235                                      max_slots * sizeof ctx->vertices);
236    }
237 
238    return ctx->vbuf_slot++ * sizeof ctx->vertices;
239 }
240 
241 
242 
243 
244 /**
245  * Setup vertex data for the textured quad we'll draw.
246  * Note: y=0=top
247  *
248  * FIXME: We should call util_map_texcoords2d_onto_cubemap
249  * for cubemaps.
250  */
251 static unsigned
setup_vertex_data_tex(struct blit_state * ctx,unsigned src_target,unsigned src_face,float x0,float y0,float x1,float y1,float s0,float t0,float s1,float t1,float z)252 setup_vertex_data_tex(struct blit_state *ctx,
253                       unsigned src_target,
254                       unsigned src_face,
255                       float x0, float y0, float x1, float y1,
256                       float s0, float t0, float s1, float t1,
257                       float z)
258 {
259    unsigned offset;
260 
261    ctx->vertices[0][0][0] = x0;
262    ctx->vertices[0][0][1] = y0;
263    ctx->vertices[0][0][2] = z;
264    ctx->vertices[0][1][0] = s0; /*s*/
265    ctx->vertices[0][1][1] = t0; /*t*/
266    ctx->vertices[0][1][2] = 0;  /*r*/
267 
268    ctx->vertices[1][0][0] = x1;
269    ctx->vertices[1][0][1] = y0;
270    ctx->vertices[1][0][2] = z;
271    ctx->vertices[1][1][0] = s1; /*s*/
272    ctx->vertices[1][1][1] = t0; /*t*/
273    ctx->vertices[1][1][2] = 0;  /*r*/
274 
275    ctx->vertices[2][0][0] = x1;
276    ctx->vertices[2][0][1] = y1;
277    ctx->vertices[2][0][2] = z;
278    ctx->vertices[2][1][0] = s1;
279    ctx->vertices[2][1][1] = t1;
280    ctx->vertices[3][1][2] = 0;
281 
282    ctx->vertices[3][0][0] = x0;
283    ctx->vertices[3][0][1] = y1;
284    ctx->vertices[3][0][2] = z;
285    ctx->vertices[3][1][0] = s0;
286    ctx->vertices[3][1][1] = t1;
287    ctx->vertices[3][1][2] = 0;
288 
289    if (src_target == PIPE_TEXTURE_CUBE ||
290        src_target == PIPE_TEXTURE_CUBE_ARRAY) {
291       /* Map cubemap texture coordinates inplace. */
292       const unsigned stride = sizeof ctx->vertices[0] / sizeof ctx->vertices[0][0][0];
293       util_map_texcoords2d_onto_cubemap(src_face,
294                                         &ctx->vertices[0][1][0], stride,
295                                         &ctx->vertices[0][1][0], stride,
296                                         TRUE);
297    }
298 
299    offset = get_next_slot( ctx );
300 
301    if (ctx->vbuf) {
302       pipe_buffer_write_nooverlap(ctx->pipe, ctx->vbuf,
303                                   offset, sizeof(ctx->vertices), ctx->vertices);
304    }
305 
306    return offset;
307 }
308 
309 
310 /**
311  * \return TRUE if two regions overlap, FALSE otherwise
312  */
313 static boolean
regions_overlap(int srcX0,int srcY0,int srcX1,int srcY1,int dstX0,int dstY0,int dstX1,int dstY1)314 regions_overlap(int srcX0, int srcY0,
315                 int srcX1, int srcY1,
316                 int dstX0, int dstY0,
317                 int dstX1, int dstY1)
318 {
319    if (MAX2(srcX0, srcX1) <= MIN2(dstX0, dstX1))
320       return FALSE; /* src completely left of dst */
321 
322    if (MAX2(dstX0, dstX1) <= MIN2(srcX0, srcX1))
323       return FALSE; /* dst completely left of src */
324 
325    if (MAX2(srcY0, srcY1) <= MIN2(dstY0, dstY1))
326       return FALSE; /* src completely above dst */
327 
328    if (MAX2(dstY0, dstY1) <= MIN2(srcY0, srcY1))
329       return FALSE; /* dst completely above src */
330 
331    return TRUE; /* some overlap */
332 }
333 
334 
335 /**
336  * Can we blit from src format to dest format with a simple copy?
337  */
338 static boolean
formats_compatible(enum pipe_format src_format,enum pipe_format dst_format)339 formats_compatible(enum pipe_format src_format,
340                    enum pipe_format dst_format)
341 {
342    if (src_format == dst_format) {
343       return TRUE;
344    }
345    else {
346       const struct util_format_description *src_desc =
347          util_format_description(src_format);
348       const struct util_format_description *dst_desc =
349          util_format_description(dst_format);
350       return util_is_format_compatible(src_desc, dst_desc);
351    }
352 }
353 
354 
355 /**
356  * Copy pixel block from src surface to dst surface.
357  * Overlapping regions are acceptable.
358  * Flipping and stretching are supported.
359  * \param filter  one of PIPE_TEX_FILTER_NEAREST/LINEAR
360  * \param writemask  bitmask of PIPE_MASK_[RGBAZS].  Controls which channels
361  *                   in the dest surface are sourced from the src surface.
362  *                   Disabled color channels are sourced from (0,0,0,1).
363  */
364 void
util_blit_pixels(struct blit_state * ctx,struct pipe_resource * src_tex,unsigned src_level,int srcX0,int srcY0,int srcX1,int srcY1,int srcZ0,struct pipe_surface * dst,int dstX0,int dstY0,int dstX1,int dstY1,MAYBE_UNUSED float z,uint filter,uint writemask)365 util_blit_pixels(struct blit_state *ctx,
366                  struct pipe_resource *src_tex,
367                  unsigned src_level,
368                  int srcX0, int srcY0,
369                  int srcX1, int srcY1,
370                  int srcZ0,
371                  struct pipe_surface *dst,
372                  int dstX0, int dstY0,
373                  int dstX1, int dstY1,
374                  MAYBE_UNUSED float z, uint filter,
375                  uint writemask)
376 {
377    struct pipe_context *pipe = ctx->pipe;
378    enum pipe_format src_format, dst_format;
379    const int srcW = abs(srcX1 - srcX0);
380    const int srcH = abs(srcY1 - srcY0);
381    boolean overlap;
382    boolean is_stencil, is_depth, blit_depth, blit_stencil;
383    const struct util_format_description *src_desc =
384          util_format_description(src_tex->format);
385    struct pipe_blit_info info;
386 
387    assert(filter == PIPE_TEX_FILTER_NEAREST ||
388           filter == PIPE_TEX_FILTER_LINEAR);
389 
390    assert(src_level <= src_tex->last_level);
391 
392    /* do the regions overlap? */
393    overlap = src_tex == dst->texture &&
394              dst->u.tex.level == src_level &&
395              dst->u.tex.first_layer == srcZ0 &&
396       regions_overlap(srcX0, srcY0, srcX1, srcY1,
397                       dstX0, dstY0, dstX1, dstY1);
398 
399    src_format = util_format_linear(src_tex->format);
400    dst_format = util_format_linear(dst->texture->format);
401 
402    /* See whether we will blit depth or stencil. */
403    is_depth = util_format_has_depth(src_desc);
404    is_stencil = util_format_has_stencil(src_desc);
405 
406    blit_depth = is_depth && (writemask & PIPE_MASK_Z);
407    blit_stencil = is_stencil && (writemask & PIPE_MASK_S);
408 
409    if (is_depth || is_stencil) {
410       assert((writemask & PIPE_MASK_RGBA) == 0);
411       assert(blit_depth || blit_stencil);
412    }
413    else {
414       assert((writemask & PIPE_MASK_ZS) == 0);
415       assert(!blit_depth);
416       assert(!blit_stencil);
417    }
418 
419    /*
420     * XXX: z parameter is deprecated. dst->u.tex.first_layer
421     * specificies the destination layer.
422     */
423    assert(z == 0.0f);
424 
425    /*
426     * Check for simple case:  no format conversion, no flipping, no stretching,
427     * no overlapping, same number of samples.
428     * Filter mode should not matter since there's no stretching.
429     */
430    if (formats_compatible(src_format, dst_format) &&
431        src_tex->nr_samples == dst->texture->nr_samples &&
432        is_stencil == blit_stencil &&
433        is_depth == blit_depth &&
434        srcX0 < srcX1 &&
435        dstX0 < dstX1 &&
436        srcY0 < srcY1 &&
437        dstY0 < dstY1 &&
438        (dstX1 - dstX0) == (srcX1 - srcX0) &&
439        (dstY1 - dstY0) == (srcY1 - srcY0) &&
440        !overlap) {
441       struct pipe_box src_box;
442       src_box.x = srcX0;
443       src_box.y = srcY0;
444       src_box.z = srcZ0;
445       src_box.width = srcW;
446       src_box.height = srcH;
447       src_box.depth = 1;
448       pipe->resource_copy_region(pipe,
449                                  dst->texture, dst->u.tex.level,
450                                  dstX0, dstY0, dst->u.tex.first_layer,/* dest */
451                                  src_tex, src_level,
452                                  &src_box);
453       return;
454    }
455 
456    memset(&info, 0, sizeof info);
457    info.dst.resource = dst->texture;
458    info.dst.level = dst->u.tex.level;
459    info.dst.box.x = dstX0;
460    info.dst.box.y = dstY0;
461    info.dst.box.z = dst->u.tex.first_layer;
462    info.dst.box.width = dstX1 - dstX0;
463    info.dst.box.height = dstY1 - dstY0;
464    assert(info.dst.box.width >= 0);
465    assert(info.dst.box.height >= 0);
466    info.dst.box.depth = 1;
467    info.dst.format = dst_format;
468    info.src.resource = src_tex;
469    info.src.level = src_level;
470    info.src.box.x = srcX0;
471    info.src.box.y = srcY0;
472    info.src.box.z = srcZ0;
473    info.src.box.width = srcX1 - srcX0;
474    info.src.box.height = srcY1 - srcY0;
475    info.src.box.depth = 1;
476    info.src.format = src_format;
477    info.mask = writemask;
478    info.filter = filter;
479    info.scissor_enable = 0;
480 
481    pipe->blit(pipe, &info);
482 }
483 
484 
485 /**
486  * Copy pixel block from src sampler view to dst surface.
487  *
488  * The sampler view's first_level field indicates the source
489  * mipmap level to use.
490  *
491  * The sampler view's first_layer indicate the layer to use, but for
492  * cube maps it must point to the first face.  Face is passed in src_face.
493  *
494  * The main advantage over util_blit_pixels is that it allows to specify swizzles in
495  * pipe_sampler_view::swizzle_?.
496  *
497  * But there is no control over blitting Z and/or stencil.
498  */
499 void
util_blit_pixels_tex(struct blit_state * ctx,struct pipe_sampler_view * src_sampler_view,int srcX0,int srcY0,int srcX1,int srcY1,unsigned src_face,struct pipe_surface * dst,int dstX0,int dstY0,int dstX1,int dstY1,float z,uint filter)500 util_blit_pixels_tex(struct blit_state *ctx,
501                      struct pipe_sampler_view *src_sampler_view,
502                      int srcX0, int srcY0,
503                      int srcX1, int srcY1,
504                      unsigned src_face,
505                      struct pipe_surface *dst,
506                      int dstX0, int dstY0,
507                      int dstX1, int dstY1,
508                      float z, uint filter)
509 {
510    boolean normalized = src_sampler_view->texture->target != PIPE_TEXTURE_RECT;
511    struct pipe_framebuffer_state fb;
512    float s0, t0, s1, t1;
513    unsigned offset;
514    struct pipe_resource *tex = src_sampler_view->texture;
515 
516    assert(filter == PIPE_TEX_FILTER_NEAREST ||
517           filter == PIPE_TEX_FILTER_LINEAR);
518 
519    assert(tex);
520    assert(tex->width0 != 0);
521    assert(tex->height0 != 0);
522 
523    s0 = (float) srcX0;
524    s1 = (float) srcX1;
525    t0 = (float) srcY0;
526    t1 = (float) srcY1;
527 
528    if(normalized)
529    {
530       /* normalize according to the mipmap level's size */
531       int level = src_sampler_view->u.tex.first_level;
532       float w = (float) u_minify(tex->width0, level);
533       float h = (float) u_minify(tex->height0, level);
534       s0 /= w;
535       s1 /= w;
536       t0 /= h;
537       t1 /= h;
538    }
539 
540    assert(ctx->pipe->screen->is_format_supported(ctx->pipe->screen, dst->format,
541                                                  PIPE_TEXTURE_2D,
542                                                  dst->texture->nr_samples,
543                                                  PIPE_BIND_RENDER_TARGET));
544 
545    /* save state (restored below) */
546    cso_save_state(ctx->cso, (CSO_BIT_BLEND |
547                              CSO_BIT_DEPTH_STENCIL_ALPHA |
548                              CSO_BIT_RASTERIZER |
549                              CSO_BIT_SAMPLE_MASK |
550                              CSO_BIT_MIN_SAMPLES |
551                              CSO_BIT_FRAGMENT_SAMPLERS |
552                              CSO_BIT_FRAGMENT_SAMPLER_VIEWS |
553                              CSO_BIT_STREAM_OUTPUTS |
554                              CSO_BIT_VIEWPORT |
555                              CSO_BIT_FRAMEBUFFER |
556                              CSO_BIT_PAUSE_QUERIES |
557                              CSO_BIT_FRAGMENT_SHADER |
558                              CSO_BIT_VERTEX_SHADER |
559                              CSO_BIT_TESSCTRL_SHADER |
560                              CSO_BIT_TESSEVAL_SHADER |
561                              CSO_BIT_GEOMETRY_SHADER |
562                              CSO_BIT_VERTEX_ELEMENTS |
563                              CSO_BIT_AUX_VERTEX_BUFFER_SLOT));
564 
565    /* set misc state we care about */
566    cso_set_blend(ctx->cso, &ctx->blend_write_color);
567    cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_keep_depthstencil);
568    cso_set_sample_mask(ctx->cso, ~0);
569    cso_set_min_samples(ctx->cso, 1);
570    cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
571    cso_set_vertex_elements(ctx->cso, 2, ctx->velem);
572    cso_set_stream_outputs(ctx->cso, 0, NULL, NULL);
573 
574    /* sampler */
575    ctx->sampler.normalized_coords = normalized;
576    ctx->sampler.min_img_filter = filter;
577    ctx->sampler.mag_img_filter = filter;
578    {
579       const struct pipe_sampler_state *samplers[] = {&ctx->sampler};
580       cso_set_samplers(ctx->cso, PIPE_SHADER_FRAGMENT, 1, samplers);
581    }
582 
583    /* viewport */
584    ctx->viewport.scale[0] = 0.5f * dst->width;
585    ctx->viewport.scale[1] = 0.5f * dst->height;
586    ctx->viewport.scale[2] = 0.5f;
587    ctx->viewport.translate[0] = 0.5f * dst->width;
588    ctx->viewport.translate[1] = 0.5f * dst->height;
589    ctx->viewport.translate[2] = 0.5f;
590    cso_set_viewport(ctx->cso, &ctx->viewport);
591 
592    /* texture */
593    cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &src_sampler_view);
594 
595    /* shaders */
596    set_fragment_shader(ctx, TGSI_WRITEMASK_XYZW,
597                        src_sampler_view->format,
598                        src_sampler_view->texture->target);
599    set_vertex_shader(ctx);
600    cso_set_tessctrl_shader_handle(ctx->cso, NULL);
601    cso_set_tesseval_shader_handle(ctx->cso, NULL);
602    cso_set_geometry_shader_handle(ctx->cso, NULL);
603 
604    /* drawing dest */
605    memset(&fb, 0, sizeof(fb));
606    fb.width = dst->width;
607    fb.height = dst->height;
608    fb.nr_cbufs = 1;
609    fb.cbufs[0] = dst;
610    cso_set_framebuffer(ctx->cso, &fb);
611 
612    /* draw quad */
613    offset = setup_vertex_data_tex(ctx,
614                                   src_sampler_view->texture->target,
615                                   src_face,
616                                   (float) dstX0 / dst->width * 2.0f - 1.0f,
617                                   (float) dstY0 / dst->height * 2.0f - 1.0f,
618                                   (float) dstX1 / dst->width * 2.0f - 1.0f,
619                                   (float) dstY1 / dst->height * 2.0f - 1.0f,
620                                   s0, t0, s1, t1,
621                                   z);
622 
623    util_draw_vertex_buffer(ctx->pipe, ctx->cso, ctx->vbuf,
624                            cso_get_aux_vertex_buffer_slot(ctx->cso),
625                            offset,
626                            PIPE_PRIM_TRIANGLE_FAN,
627                            4,  /* verts */
628                            2); /* attribs/vert */
629 
630    /* restore state we changed */
631    cso_restore_state(ctx->cso);
632 }
633