u_blit.c revision 9de26ccbcc2123b658c1b01c079b010473bc6da6
1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 "pipe/p_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_math.h"
46#include "util/u_memory.h"
47#include "util/u_simple_shaders.h"
48#include "util/u_surface.h"
49
50#include "cso_cache/cso_context.h"
51
52
53struct blit_state
54{
55   struct pipe_context *pipe;
56   struct cso_context *cso;
57
58   struct pipe_blend_state blend;
59   struct pipe_depth_stencil_alpha_state depthstencil;
60   struct pipe_rasterizer_state rasterizer;
61   struct pipe_sampler_state sampler;
62   struct pipe_viewport_state viewport;
63
64   void *vs;
65   void *fs;
66
67   struct pipe_buffer *vbuf;  /**< quad vertices */
68   unsigned vbuf_slot;
69
70   float vertices[4][2][4];   /**< vertex/texcoords for quad */
71};
72
73
74/**
75 * Create state object for blit.
76 * Intended to be created once and re-used for many blit() calls.
77 */
78struct blit_state *
79util_create_blit(struct pipe_context *pipe, struct cso_context *cso)
80{
81   struct blit_state *ctx;
82   uint i;
83
84   ctx = CALLOC_STRUCT(blit_state);
85   if (!ctx)
86      return NULL;
87
88   ctx->pipe = pipe;
89   ctx->cso = cso;
90
91   /* disabled blending/masking */
92   memset(&ctx->blend, 0, sizeof(ctx->blend));
93   ctx->blend.colormask = PIPE_MASK_RGBA;
94
95   /* no-op depth/stencil/alpha */
96   memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil));
97
98   /* rasterizer */
99   memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer));
100   ctx->rasterizer.front_winding = PIPE_WINDING_CW;
101   ctx->rasterizer.cull_mode = PIPE_WINDING_NONE;
102   ctx->rasterizer.bypass_vs_clip_and_viewport = 1;
103   ctx->rasterizer.gl_rasterization_rules = 1;
104
105   /* samplers */
106   memset(&ctx->sampler, 0, sizeof(ctx->sampler));
107   ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
108   ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
109   ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
110   ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
111   ctx->sampler.min_img_filter = 0; /* set later */
112   ctx->sampler.mag_img_filter = 0; /* set later */
113   ctx->sampler.normalized_coords = 1;
114
115
116   /* vertex shader - still required to provide the linkage between
117    * fragment shader input semantics and vertex_element/buffers.
118    */
119   {
120      const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
121                                      TGSI_SEMANTIC_GENERIC };
122      const uint semantic_indexes[] = { 0, 0 };
123      ctx->vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names,
124                                                    semantic_indexes);
125   }
126
127   /* fragment shader */
128   ctx->fs = util_make_fragment_tex_shader(pipe);
129   ctx->vbuf = NULL;
130
131   /* init vertex data that doesn't change */
132   for (i = 0; i < 4; i++) {
133      ctx->vertices[i][0][3] = 1.0f; /* w */
134      ctx->vertices[i][1][2] = 0.0f; /* r */
135      ctx->vertices[i][1][3] = 1.0f; /* q */
136   }
137
138   return ctx;
139}
140
141
142/**
143 * Destroy a blit context
144 */
145void
146util_destroy_blit(struct blit_state *ctx)
147{
148   struct pipe_context *pipe = ctx->pipe;
149
150   pipe->delete_vs_state(pipe, ctx->vs);
151   pipe->delete_fs_state(pipe, ctx->fs);
152
153   pipe_buffer_reference(&ctx->vbuf, NULL);
154
155   FREE(ctx);
156}
157
158
159/**
160 * Get offset of next free slot in vertex buffer for quad vertices.
161 */
162static unsigned
163get_next_slot( struct blit_state *ctx )
164{
165   const unsigned max_slots = 4096 / sizeof ctx->vertices;
166
167   if (ctx->vbuf_slot >= max_slots)
168      util_blit_flush( ctx );
169
170   if (!ctx->vbuf) {
171      ctx->vbuf = pipe_buffer_create(ctx->pipe->screen,
172                                     32,
173                                     PIPE_BUFFER_USAGE_VERTEX,
174                                     max_slots * sizeof ctx->vertices);
175   }
176
177   return ctx->vbuf_slot++ * sizeof ctx->vertices;
178}
179
180
181/**
182 * Setup vertex data for the textured quad we'll draw.
183 * Note: y=0=top
184 */
185static unsigned
186setup_vertex_data(struct blit_state *ctx,
187                  float x0, float y0, float x1, float y1, float z)
188{
189   unsigned offset;
190
191   ctx->vertices[0][0][0] = x0;
192   ctx->vertices[0][0][1] = y0;
193   ctx->vertices[0][0][2] = z;
194   ctx->vertices[0][1][0] = 0.0f; /*s*/
195   ctx->vertices[0][1][1] = 0.0f; /*t*/
196
197   ctx->vertices[1][0][0] = x1;
198   ctx->vertices[1][0][1] = y0;
199   ctx->vertices[1][0][2] = z;
200   ctx->vertices[1][1][0] = 1.0f; /*s*/
201   ctx->vertices[1][1][1] = 0.0f; /*t*/
202
203   ctx->vertices[2][0][0] = x1;
204   ctx->vertices[2][0][1] = y1;
205   ctx->vertices[2][0][2] = z;
206   ctx->vertices[2][1][0] = 1.0f;
207   ctx->vertices[2][1][1] = 1.0f;
208
209   ctx->vertices[3][0][0] = x0;
210   ctx->vertices[3][0][1] = y1;
211   ctx->vertices[3][0][2] = z;
212   ctx->vertices[3][1][0] = 0.0f;
213   ctx->vertices[3][1][1] = 1.0f;
214
215   offset = get_next_slot( ctx );
216
217   pipe_buffer_write(ctx->pipe->screen, ctx->vbuf,
218                     offset, sizeof(ctx->vertices), ctx->vertices);
219
220   return offset;
221}
222
223
224/**
225 * Setup vertex data for the textured quad we'll draw.
226 * Note: y=0=top
227 */
228static unsigned
229setup_vertex_data_tex(struct blit_state *ctx,
230                      float x0, float y0, float x1, float y1,
231                      float s0, float t0, float s1, float t1,
232                      float z)
233{
234   unsigned offset;
235
236   ctx->vertices[0][0][0] = x0;
237   ctx->vertices[0][0][1] = y0;
238   ctx->vertices[0][0][2] = z;
239   ctx->vertices[0][1][0] = s0; /*s*/
240   ctx->vertices[0][1][1] = t0; /*t*/
241
242   ctx->vertices[1][0][0] = x1;
243   ctx->vertices[1][0][1] = y0;
244   ctx->vertices[1][0][2] = z;
245   ctx->vertices[1][1][0] = s1; /*s*/
246   ctx->vertices[1][1][1] = t0; /*t*/
247
248   ctx->vertices[2][0][0] = x1;
249   ctx->vertices[2][0][1] = y1;
250   ctx->vertices[2][0][2] = z;
251   ctx->vertices[2][1][0] = s1;
252   ctx->vertices[2][1][1] = t1;
253
254   ctx->vertices[3][0][0] = x0;
255   ctx->vertices[3][0][1] = y1;
256   ctx->vertices[3][0][2] = z;
257   ctx->vertices[3][1][0] = s0;
258   ctx->vertices[3][1][1] = t1;
259
260   offset = get_next_slot( ctx );
261
262   pipe_buffer_write(ctx->pipe->screen, ctx->vbuf,
263                     offset, sizeof(ctx->vertices), ctx->vertices);
264
265   return offset;
266}
267
268
269/**
270 * \return TRUE if two regions overlap, FALSE otherwise
271 */
272static boolean
273regions_overlap(int srcX0, int srcY0,
274                int srcX1, int srcY1,
275                int dstX0, int dstY0,
276                int dstX1, int dstY1)
277{
278   if (MAX2(srcX0, srcX1) < MIN2(dstX0, dstX1))
279      return FALSE; /* src completely left of dst */
280
281   if (MAX2(dstX0, dstX1) < MIN2(srcX0, srcX1))
282      return FALSE; /* dst completely left of src */
283
284   if (MAX2(srcY0, srcY1) < MIN2(dstY0, dstY1))
285      return FALSE; /* src completely above dst */
286
287   if (MAX2(dstY0, dstY1) < MIN2(srcY0, srcY1))
288      return FALSE; /* dst completely above src */
289
290   return TRUE; /* some overlap */
291}
292
293
294/**
295 * Copy pixel block from src surface to dst surface.
296 * Overlapping regions are acceptable.
297 * Flipping and stretching are supported.
298 * XXX what about clipping???
299 * XXX need some control over blitting Z and/or stencil.
300 */
301void
302util_blit_pixels(struct blit_state *ctx,
303                 struct pipe_surface *src,
304                 int srcX0, int srcY0,
305                 int srcX1, int srcY1,
306                 struct pipe_surface *dst,
307                 int dstX0, int dstY0,
308                 int dstX1, int dstY1,
309                 float z, uint filter)
310{
311   struct pipe_context *pipe = ctx->pipe;
312   struct pipe_screen *screen = pipe->screen;
313   struct pipe_texture texTemp, *tex;
314   struct pipe_surface *texSurf;
315   struct pipe_framebuffer_state fb;
316   const int srcW = abs(srcX1 - srcX0);
317   const int srcH = abs(srcY1 - srcY0);
318   const int srcLeft = MIN2(srcX0, srcX1);
319   const int srcTop = MIN2(srcY0, srcY1);
320   unsigned offset;
321   boolean overlap;
322
323   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
324          filter == PIPE_TEX_MIPFILTER_LINEAR);
325
326   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
327                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
328   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
329                                      PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
330
331   /* do the regions overlap? */
332   overlap = util_same_surface(src, dst) &&
333      regions_overlap(srcX0, srcY0, srcX1, srcY1,
334                      dstX0, dstY0, dstX1, dstY1);
335
336   /*
337    * Check for simple case:  no format conversion, no flipping, no stretching,
338    * no overlapping.
339    * Filter mode should not matter since there's no stretching.
340    */
341   if (dst->format == src->format &&
342       srcX0 < srcX1 &&
343       dstX0 < dstX1 &&
344       srcY0 < srcY1 &&
345       dstY0 < dstY1 &&
346       (dstX1 - dstX0) == (srcX1 - srcX0) &&
347       (dstY1 - dstY0) == (srcY1 - srcY0) &&
348       !overlap) {
349      pipe->surface_copy(pipe,
350			 dst, dstX0, dstY0, /* dest */
351			 src, srcX0, srcY0, /* src */
352			 srcW, srcH);       /* size */
353      return;
354   }
355
356   if (srcLeft != srcX0) {
357      /* left-right flip */
358      int tmp = dstX0;
359      dstX0 = dstX1;
360      dstX1 = tmp;
361   }
362
363   if (srcTop != srcY0) {
364      /* up-down flip */
365      int tmp = dstY0;
366      dstY0 = dstY1;
367      dstY1 = tmp;
368   }
369
370   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
371                                      PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
372
373   /*
374    * XXX for now we're always creating a temporary texture.
375    * Strictly speaking that's not always needed.
376    */
377
378   /* create temp texture */
379   memset(&texTemp, 0, sizeof(texTemp));
380   texTemp.target = PIPE_TEXTURE_2D;
381   texTemp.format = src->format;
382   texTemp.last_level = 0;
383   texTemp.width[0] = srcW;
384   texTemp.height[0] = srcH;
385   texTemp.depth[0] = 1;
386   pf_get_block(src->format, &texTemp.block);
387
388   tex = screen->texture_create(screen, &texTemp);
389   if (!tex)
390      return;
391
392   texSurf = screen->get_tex_surface(screen, tex, 0, 0, 0,
393                                     PIPE_BUFFER_USAGE_GPU_WRITE);
394
395   /* load temp texture */
396   pipe->surface_copy(pipe,
397                      texSurf, 0, 0,   /* dest */
398                      src, srcLeft, srcTop, /* src */
399                      srcW, srcH);     /* size */
400
401   /* free the surface, update the texture if necessary.
402    */
403   pipe_surface_reference(&texSurf, NULL);
404
405   /* save state (restored below) */
406   cso_save_blend(ctx->cso);
407   cso_save_depth_stencil_alpha(ctx->cso);
408   cso_save_rasterizer(ctx->cso);
409   cso_save_samplers(ctx->cso);
410   cso_save_sampler_textures(ctx->cso);
411   cso_save_framebuffer(ctx->cso);
412   cso_save_fragment_shader(ctx->cso);
413   cso_save_vertex_shader(ctx->cso);
414
415   /* set misc state we care about */
416   cso_set_blend(ctx->cso, &ctx->blend);
417   cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
418   cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
419
420   /* sampler */
421   ctx->sampler.min_img_filter = filter;
422   ctx->sampler.mag_img_filter = filter;
423   cso_single_sampler(ctx->cso, 0, &ctx->sampler);
424   cso_single_sampler_done(ctx->cso);
425
426   /* texture */
427   cso_set_sampler_textures(ctx->cso, 1, &tex);
428
429   /* shaders */
430   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
431   cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
432
433   /* drawing dest */
434   memset(&fb, 0, sizeof(fb));
435   fb.width = dst->width;
436   fb.height = dst->height;
437   fb.nr_cbufs = 1;
438   fb.cbufs[0] = dst;
439   cso_set_framebuffer(ctx->cso, &fb);
440
441   /* draw quad */
442   offset = setup_vertex_data(ctx,
443                              (float) dstX0, (float) dstY0,
444                              (float) dstX1, (float) dstY1, z);
445
446   util_draw_vertex_buffer(ctx->pipe, ctx->vbuf, offset,
447                           PIPE_PRIM_TRIANGLE_FAN,
448                           4,  /* verts */
449                           2); /* attribs/vert */
450
451   /* restore state we changed */
452   cso_restore_blend(ctx->cso);
453   cso_restore_depth_stencil_alpha(ctx->cso);
454   cso_restore_rasterizer(ctx->cso);
455   cso_restore_samplers(ctx->cso);
456   cso_restore_sampler_textures(ctx->cso);
457   cso_restore_framebuffer(ctx->cso);
458   cso_restore_fragment_shader(ctx->cso);
459   cso_restore_vertex_shader(ctx->cso);
460
461   pipe_texture_reference(&tex, NULL);
462}
463
464
465/* Release vertex buffer at end of frame to avoid synchronous
466 * rendering.
467 */
468void util_blit_flush( struct blit_state *ctx )
469{
470   pipe_buffer_reference(&ctx->vbuf, NULL);
471   ctx->vbuf_slot = 0;
472}
473
474
475
476/**
477 * Copy pixel block from src texture to dst surface.
478 * Overlapping regions are acceptable.
479 *
480 * XXX Should support selection of level.
481 * XXX need some control over blitting Z and/or stencil.
482 */
483void
484util_blit_pixels_tex(struct blit_state *ctx,
485                 struct pipe_texture *tex,
486                 int srcX0, int srcY0,
487                 int srcX1, int srcY1,
488                 struct pipe_surface *dst,
489                 int dstX0, int dstY0,
490                 int dstX1, int dstY1,
491                 float z, uint filter)
492{
493   struct pipe_framebuffer_state fb;
494   float s0, t0, s1, t1;
495   unsigned offset;
496
497   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
498          filter == PIPE_TEX_MIPFILTER_LINEAR);
499
500   assert(tex->width[0] != 0);
501   assert(tex->height[0] != 0);
502
503   s0 = srcX0 / (float)tex->width[0];
504   s1 = srcX1 / (float)tex->width[0];
505   t0 = srcY0 / (float)tex->height[0];
506   t1 = srcY1 / (float)tex->height[0];
507
508   assert(ctx->pipe->screen->is_format_supported(ctx->pipe->screen, dst->format,
509                                                 PIPE_TEXTURE_2D,
510                                                 PIPE_TEXTURE_USAGE_RENDER_TARGET,
511                                                 0));
512
513   /* save state (restored below) */
514   cso_save_blend(ctx->cso);
515   cso_save_depth_stencil_alpha(ctx->cso);
516   cso_save_rasterizer(ctx->cso);
517   cso_save_samplers(ctx->cso);
518   cso_save_sampler_textures(ctx->cso);
519   cso_save_framebuffer(ctx->cso);
520   cso_save_fragment_shader(ctx->cso);
521   cso_save_vertex_shader(ctx->cso);
522
523   /* set misc state we care about */
524   cso_set_blend(ctx->cso, &ctx->blend);
525   cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
526   cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
527
528   /* sampler */
529   ctx->sampler.min_img_filter = filter;
530   ctx->sampler.mag_img_filter = filter;
531   cso_single_sampler(ctx->cso, 0, &ctx->sampler);
532   cso_single_sampler_done(ctx->cso);
533
534   /* texture */
535   cso_set_sampler_textures(ctx->cso, 1, &tex);
536
537   /* shaders */
538   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
539   cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
540
541   /* drawing dest */
542   memset(&fb, 0, sizeof(fb));
543   fb.width = dst->width;
544   fb.height = dst->height;
545   fb.nr_cbufs = 1;
546   fb.cbufs[0] = dst;
547   cso_set_framebuffer(ctx->cso, &fb);
548
549   /* draw quad */
550   offset = setup_vertex_data_tex(ctx,
551                                  (float) dstX0, (float) dstY0,
552                                  (float) dstX1, (float) dstY1,
553                                  s0, t0, s1, t1,
554                                  z);
555
556   util_draw_vertex_buffer(ctx->pipe,
557                           ctx->vbuf, offset,
558                           PIPE_PRIM_TRIANGLE_FAN,
559                           4,  /* verts */
560                           2); /* attribs/vert */
561
562   /* restore state we changed */
563   cso_restore_blend(ctx->cso);
564   cso_restore_depth_stencil_alpha(ctx->cso);
565   cso_restore_rasterizer(ctx->cso);
566   cso_restore_samplers(ctx->cso);
567   cso_restore_sampler_textures(ctx->cso);
568   cso_restore_framebuffer(ctx->cso);
569   cso_restore_fragment_shader(ctx->cso);
570   cso_restore_vertex_shader(ctx->cso);
571}
572