u_blit.c revision 683e7091a953204c9aee1410ac44be3b69bae9fc
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
49#include "cso_cache/cso_context.h"
50
51
52struct blit_state
53{
54   struct pipe_context *pipe;
55   struct cso_context *cso;
56
57   struct pipe_blend_state blend;
58   struct pipe_depth_stencil_alpha_state depthstencil;
59   struct pipe_rasterizer_state rasterizer;
60   struct pipe_sampler_state sampler;
61   struct pipe_viewport_state viewport;
62
63   void *vs;
64   void *fs;
65
66   struct pipe_buffer *vbuf;  /**< quad vertices */
67   unsigned vbuf_slot;
68
69   float vertices[4][2][4];   /**< vertex/texcoords for quad */
70};
71
72
73/**
74 * Create state object for blit.
75 * Intended to be created once and re-used for many blit() calls.
76 */
77struct blit_state *
78util_create_blit(struct pipe_context *pipe, struct cso_context *cso)
79{
80   struct blit_state *ctx;
81   uint i;
82
83   ctx = CALLOC_STRUCT(blit_state);
84   if (!ctx)
85      return NULL;
86
87   ctx->pipe = pipe;
88   ctx->cso = cso;
89
90   /* disabled blending/masking */
91   memset(&ctx->blend, 0, sizeof(ctx->blend));
92   ctx->blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
93   ctx->blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
94   ctx->blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
95   ctx->blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
96   ctx->blend.colormask = PIPE_MASK_RGBA;
97
98   /* no-op depth/stencil/alpha */
99   memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil));
100
101   /* rasterizer */
102   memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer));
103   ctx->rasterizer.front_winding = PIPE_WINDING_CW;
104   ctx->rasterizer.cull_mode = PIPE_WINDING_NONE;
105   ctx->rasterizer.bypass_vs_clip_and_viewport = 1;
106   ctx->rasterizer.gl_rasterization_rules = 1;
107
108   /* samplers */
109   memset(&ctx->sampler, 0, sizeof(ctx->sampler));
110   ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
111   ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
112   ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
113   ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
114   ctx->sampler.min_img_filter = 0; /* set later */
115   ctx->sampler.mag_img_filter = 0; /* set later */
116   ctx->sampler.normalized_coords = 1;
117
118
119   /* vertex shader - still required to provide the linkage between
120    * fragment shader input semantics and vertex_element/buffers.
121    */
122   {
123      const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
124                                      TGSI_SEMANTIC_GENERIC };
125      const uint semantic_indexes[] = { 0, 0 };
126      ctx->vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names,
127                                                    semantic_indexes);
128   }
129
130   /* fragment shader */
131   ctx->fs = util_make_fragment_tex_shader(pipe);
132   ctx->vbuf = NULL;
133
134   /* init vertex data that doesn't change */
135   for (i = 0; i < 4; i++) {
136      ctx->vertices[i][0][3] = 1.0f; /* w */
137      ctx->vertices[i][1][2] = 0.0f; /* r */
138      ctx->vertices[i][1][3] = 1.0f; /* q */
139   }
140
141   return ctx;
142}
143
144
145/**
146 * Destroy a blit context
147 */
148void
149util_destroy_blit(struct blit_state *ctx)
150{
151   struct pipe_context *pipe = ctx->pipe;
152
153   pipe->delete_vs_state(pipe, ctx->vs);
154   pipe->delete_fs_state(pipe, ctx->fs);
155
156   pipe_buffer_reference(&ctx->vbuf, NULL);
157
158   FREE(ctx);
159}
160
161
162static unsigned get_next_slot( struct blit_state *ctx )
163{
164   const unsigned max_slots = 4096 / sizeof ctx->vertices;
165
166   if (ctx->vbuf_slot >= max_slots)
167      util_blit_flush( ctx );
168
169   if (!ctx->vbuf) {
170      ctx->vbuf = pipe_buffer_create(ctx->pipe->screen,
171                                     32,
172                                     PIPE_BUFFER_USAGE_VERTEX,
173                                     max_slots * sizeof ctx->vertices);
174   }
175
176   return ctx->vbuf_slot++ * sizeof ctx->vertices;
177}
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 * Copy pixel block from src surface to dst surface.
269 * Overlapping regions are acceptable.
270 * XXX need some control over blitting Z and/or stencil.
271 */
272void
273util_blit_pixels(struct blit_state *ctx,
274                 struct pipe_surface *src,
275                 int srcX0, int srcY0,
276                 int srcX1, int srcY1,
277                 struct pipe_surface *dst,
278                 int dstX0, int dstY0,
279                 int dstX1, int dstY1,
280                 float z, uint filter)
281{
282   struct pipe_context *pipe = ctx->pipe;
283   struct pipe_screen *screen = pipe->screen;
284   struct pipe_texture texTemp, *tex;
285   struct pipe_surface *texSurf;
286   struct pipe_framebuffer_state fb;
287   const int srcW = abs(srcX1 - srcX0);
288   const int srcH = abs(srcY1 - srcY0);
289   const int srcLeft = MIN2(srcX0, srcX1);
290   const int srcTop = MIN2(srcY0, srcY1);
291   unsigned offset;
292
293   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
294          filter == PIPE_TEX_MIPFILTER_LINEAR);
295
296   if (srcLeft != srcX0) {
297      /* left-right flip */
298      int tmp = dstX0;
299      dstX0 = dstX1;
300      dstX1 = tmp;
301   }
302
303   if (srcTop != srcY0) {
304      /* up-down flip */
305      int tmp = dstY0;
306      dstY0 = dstY1;
307      dstY1 = tmp;
308   }
309
310   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
311                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
312   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
313                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
314
315   if(dst->format == src->format && (dstX1 - dstX0) == srcW && (dstY1 - dstY0) == srcH) {
316      /* FIXME: this will most surely fail for overlapping rectangles */
317      pipe->surface_copy(pipe,
318			 dst, dstX0, dstY0,   /* dest */
319			 src, srcX0, srcY0, /* src */
320			 srcW, srcH);     /* size */
321      return;
322   }
323
324   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
325                                      PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
326
327   /*
328    * XXX for now we're always creating a temporary texture.
329    * Strictly speaking that's not always needed.
330    */
331
332   /* create temp texture */
333   memset(&texTemp, 0, sizeof(texTemp));
334   texTemp.target = PIPE_TEXTURE_2D;
335   texTemp.format = src->format;
336   texTemp.last_level = 0;
337   texTemp.width[0] = srcW;
338   texTemp.height[0] = srcH;
339   texTemp.depth[0] = 1;
340   texTemp.compressed = 0;
341   pf_get_block(src->format, &texTemp.block);
342
343   tex = screen->texture_create(screen, &texTemp);
344   if (!tex)
345      return;
346
347   texSurf = screen->get_tex_surface(screen, tex, 0, 0, 0,
348                                     PIPE_BUFFER_USAGE_GPU_WRITE);
349
350   /* load temp texture */
351   pipe->surface_copy(pipe,
352                      texSurf, 0, 0,   /* dest */
353                      src, srcLeft, srcTop, /* src */
354                      srcW, srcH);     /* size */
355
356   /* free the surface, update the texture if necessary.
357    */
358   pipe_surface_reference(&texSurf, NULL);
359
360   /* save state (restored below) */
361   cso_save_blend(ctx->cso);
362   cso_save_depth_stencil_alpha(ctx->cso);
363   cso_save_rasterizer(ctx->cso);
364   cso_save_samplers(ctx->cso);
365   cso_save_sampler_textures(ctx->cso);
366   cso_save_framebuffer(ctx->cso);
367   cso_save_fragment_shader(ctx->cso);
368   cso_save_vertex_shader(ctx->cso);
369
370   /* set misc state we care about */
371   cso_set_blend(ctx->cso, &ctx->blend);
372   cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
373   cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
374
375   /* sampler */
376   ctx->sampler.min_img_filter = filter;
377   ctx->sampler.mag_img_filter = filter;
378   cso_single_sampler(ctx->cso, 0, &ctx->sampler);
379   cso_single_sampler_done(ctx->cso);
380
381   /* texture */
382   cso_set_sampler_textures(ctx->cso, 1, &tex);
383
384   /* shaders */
385   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
386   cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
387
388   /* drawing dest */
389   memset(&fb, 0, sizeof(fb));
390   fb.width = dst->width;
391   fb.height = dst->height;
392   fb.nr_cbufs = 1;
393   fb.cbufs[0] = dst;
394   cso_set_framebuffer(ctx->cso, &fb);
395
396   /* draw quad */
397   offset = setup_vertex_data(ctx,
398                              (float) dstX0, (float) dstY0,
399                              (float) dstX1, (float) dstY1, z);
400
401   util_draw_vertex_buffer(ctx->pipe, ctx->vbuf, offset,
402                           PIPE_PRIM_TRIANGLE_FAN,
403                           4,  /* verts */
404                           2); /* attribs/vert */
405
406   /* restore state we changed */
407   cso_restore_blend(ctx->cso);
408   cso_restore_depth_stencil_alpha(ctx->cso);
409   cso_restore_rasterizer(ctx->cso);
410   cso_restore_samplers(ctx->cso);
411   cso_restore_sampler_textures(ctx->cso);
412   cso_restore_framebuffer(ctx->cso);
413   cso_restore_fragment_shader(ctx->cso);
414   cso_restore_vertex_shader(ctx->cso);
415
416   pipe_texture_reference(&tex, NULL);
417}
418
419
420/* Release vertex buffer at end of frame to avoid synchronous
421 * rendering.
422 */
423void util_blit_flush( struct blit_state *ctx )
424{
425   pipe_buffer_reference(&ctx->vbuf, NULL);
426   ctx->vbuf_slot = 0;
427}
428
429
430
431/**
432 * Copy pixel block from src texture to dst surface.
433 * Overlapping regions are acceptable.
434 *
435 * XXX Should support selection of level.
436 * XXX need some control over blitting Z and/or stencil.
437 */
438void
439util_blit_pixels_tex(struct blit_state *ctx,
440                 struct pipe_texture *tex,
441                 int srcX0, int srcY0,
442                 int srcX1, int srcY1,
443                 struct pipe_surface *dst,
444                 int dstX0, int dstY0,
445                 int dstX1, int dstY1,
446                 float z, uint filter)
447{
448   struct pipe_framebuffer_state fb;
449   float s0, t0, s1, t1;
450   unsigned offset;
451
452   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
453          filter == PIPE_TEX_MIPFILTER_LINEAR);
454
455   assert(tex->width[0] != 0);
456   assert(tex->height[0] != 0);
457
458   s0 = srcX0 / (float)tex->width[0];
459   s1 = srcX1 / (float)tex->width[0];
460   t0 = srcY0 / (float)tex->height[0];
461   t1 = srcY1 / (float)tex->height[0];
462
463   assert(ctx->pipe->screen->is_format_supported(ctx->pipe->screen, dst->format,
464                                                 PIPE_TEXTURE_2D,
465                                                 PIPE_TEXTURE_USAGE_RENDER_TARGET,
466                                                 0));
467
468   /* save state (restored below) */
469   cso_save_blend(ctx->cso);
470   cso_save_depth_stencil_alpha(ctx->cso);
471   cso_save_rasterizer(ctx->cso);
472   cso_save_samplers(ctx->cso);
473   cso_save_sampler_textures(ctx->cso);
474   cso_save_framebuffer(ctx->cso);
475   cso_save_fragment_shader(ctx->cso);
476   cso_save_vertex_shader(ctx->cso);
477
478   /* set misc state we care about */
479   cso_set_blend(ctx->cso, &ctx->blend);
480   cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
481   cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
482
483   /* sampler */
484   ctx->sampler.min_img_filter = filter;
485   ctx->sampler.mag_img_filter = filter;
486   cso_single_sampler(ctx->cso, 0, &ctx->sampler);
487   cso_single_sampler_done(ctx->cso);
488
489   /* texture */
490   cso_set_sampler_textures(ctx->cso, 1, &tex);
491
492   /* shaders */
493   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
494   cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
495
496   /* drawing dest */
497   memset(&fb, 0, sizeof(fb));
498   fb.width = dst->width;
499   fb.height = dst->height;
500   fb.nr_cbufs = 1;
501   fb.cbufs[0] = dst;
502   cso_set_framebuffer(ctx->cso, &fb);
503
504   /* draw quad */
505   offset = setup_vertex_data_tex(ctx,
506                                  (float) dstX0, (float) dstY0,
507                                  (float) dstX1, (float) dstY1,
508                                  s0, t0, s1, t1,
509                                  z);
510
511   util_draw_vertex_buffer(ctx->pipe,
512                           ctx->vbuf, offset,
513                           PIPE_PRIM_TRIANGLE_FAN,
514                           4,  /* verts */
515                           2); /* attribs/vert */
516
517   /* restore state we changed */
518   cso_restore_blend(ctx->cso);
519   cso_restore_depth_stencil_alpha(ctx->cso);
520   cso_restore_rasterizer(ctx->cso);
521   cso_restore_samplers(ctx->cso);
522   cso_restore_sampler_textures(ctx->cso);
523   cso_restore_framebuffer(ctx->cso);
524   cso_restore_fragment_shader(ctx->cso);
525   cso_restore_vertex_shader(ctx->cso);
526}
527