u_blit.c revision dccbfd8bf0624250a435948029916073d3390191
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 "pipe/p_debug.h"
38#include "pipe/p_defines.h"
39#include "pipe/p_inlines.h"
40#include "pipe/p_util.h"
41#include "pipe/p_winsys.h"
42#include "pipe/p_shader_tokens.h"
43
44#include "util/u_draw_quad.h"
45#include "util/u_blit.h"
46#include "util/u_simple_shaders.h"
47
48#include "cso_cache/cso_context.h"
49
50
51struct blit_state
52{
53   struct pipe_context *pipe;
54   struct cso_context *cso;
55
56   struct pipe_blend_state blend;
57   struct pipe_depth_stencil_alpha_state depthstencil;
58   struct pipe_rasterizer_state rasterizer;
59   struct pipe_sampler_state sampler;
60
61   struct pipe_shader_state vert_shader;
62   struct pipe_shader_state frag_shader;
63   void *vs;
64   void *fs;
65
66   struct pipe_buffer *vbuf;  /**< quad vertices */
67   float vertices[4][2][4];   /**< vertex/texcoords for quad */
68};
69
70
71/**
72 * Create state object for blit.
73 * Intended to be created once and re-used for many blit() calls.
74 */
75struct blit_state *
76util_create_blit(struct pipe_context *pipe, struct cso_context *cso)
77{
78   struct blit_state *ctx;
79   uint i;
80
81   ctx = CALLOC_STRUCT(blit_state);
82   if (!ctx)
83      return NULL;
84
85   ctx->pipe = pipe;
86   ctx->cso = cso;
87
88   /* disabled blending/masking */
89   memset(&ctx->blend, 0, sizeof(ctx->blend));
90   ctx->blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
91   ctx->blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
92   ctx->blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
93   ctx->blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
94   ctx->blend.colormask = PIPE_MASK_RGBA;
95
96   /* no-op depth/stencil/alpha */
97   memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil));
98
99   /* rasterizer */
100   memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer));
101   ctx->rasterizer.front_winding = PIPE_WINDING_CW;
102   ctx->rasterizer.cull_mode = PIPE_WINDING_NONE;
103   ctx->rasterizer.bypass_clipping = 1;  /* bypasses viewport too */
104   /*ctx->rasterizer.bypass_vs = 1;*/
105
106   /* samplers */
107   memset(&ctx->sampler, 0, sizeof(ctx->sampler));
108   ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
109   ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
110   ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
111   ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
112   ctx->sampler.min_img_filter = 0; /* set later */
113   ctx->sampler.mag_img_filter = 0; /* set later */
114   ctx->sampler.normalized_coords = 1;
115
116#if 0
117   /* viewport */
118   ctx->viewport.scale[0] = 1.0;
119   ctx->viewport.scale[1] = 1.0;
120   ctx->viewport.scale[2] = 1.0;
121   ctx->viewport.scale[3] = 1.0;
122   ctx->viewport.translate[0] = 0.0;
123   ctx->viewport.translate[1] = 0.0;
124   ctx->viewport.translate[2] = 0.0;
125   ctx->viewport.translate[3] = 0.0;
126#endif
127
128   /* vertex shader */
129   {
130      const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
131                                      TGSI_SEMANTIC_GENERIC };
132      const uint semantic_indexes[] = { 0, 0 };
133      ctx->vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names,
134                                                    semantic_indexes,
135                                                    &ctx->vert_shader);
136   }
137
138   /* fragment shader */
139   ctx->fs = util_make_fragment_tex_shader(pipe, &ctx->frag_shader);
140
141   ctx->vbuf = pipe->winsys->buffer_create(pipe->winsys,
142                                           32,
143                                           PIPE_BUFFER_USAGE_VERTEX,
144                                           sizeof(ctx->vertices));
145   if (!ctx->vbuf) {
146      FREE(ctx);
147      ctx->pipe->delete_fs_state(ctx->pipe, ctx->fs);
148      ctx->pipe->delete_vs_state(ctx->pipe, ctx->vs);
149      return NULL;
150   }
151
152   /* init vertex data that doesn't change */
153   for (i = 0; i < 4; i++) {
154      ctx->vertices[i][0][3] = 1.0f; /* w */
155      ctx->vertices[i][1][2] = 0.0f; /* r */
156      ctx->vertices[i][1][3] = 1.0f; /* q */
157   }
158
159   return ctx;
160}
161
162
163/**
164 * Destroy a blit context
165 */
166void
167util_destroy_blit(struct blit_state *ctx)
168{
169   struct pipe_context *pipe = ctx->pipe;
170
171   pipe->delete_vs_state(pipe, ctx->vs);
172   pipe->delete_fs_state(pipe, ctx->fs);
173
174   FREE((void*) ctx->vert_shader.tokens);
175   FREE((void*) ctx->frag_shader.tokens);
176
177   pipe->winsys->buffer_destroy(pipe->winsys, ctx->vbuf);
178
179   FREE(ctx);
180}
181
182
183/**
184 * Setup vertex data for the textured quad we'll draw.
185 * Note: y=0=top
186 */
187static void
188setup_vertex_data(struct blit_state *ctx,
189                  float x0, float y0, float x1, float y1, float z)
190{
191   void *buf;
192
193   ctx->vertices[0][0][0] = x0;
194   ctx->vertices[0][0][1] = y0;
195   ctx->vertices[0][0][2] = z;
196   ctx->vertices[0][1][0] = 0.0f; /*s*/
197   ctx->vertices[0][1][1] = 0.0f; /*t*/
198
199   ctx->vertices[1][0][0] = x1;
200   ctx->vertices[1][0][1] = y0;
201   ctx->vertices[1][0][2] = z;
202   ctx->vertices[1][1][0] = 1.0f; /*s*/
203   ctx->vertices[1][1][1] = 0.0f; /*t*/
204
205   ctx->vertices[2][0][0] = x1;
206   ctx->vertices[2][0][1] = y1;
207   ctx->vertices[2][0][2] = z;
208   ctx->vertices[2][1][0] = 1.0f;
209   ctx->vertices[2][1][1] = 1.0f;
210
211   ctx->vertices[3][0][0] = x0;
212   ctx->vertices[3][0][1] = y1;
213   ctx->vertices[3][0][2] = z;
214   ctx->vertices[3][1][0] = 0.0f;
215   ctx->vertices[3][1][1] = 1.0f;
216
217   buf = ctx->pipe->winsys->buffer_map(ctx->pipe->winsys, ctx->vbuf,
218                                       PIPE_BUFFER_USAGE_CPU_WRITE);
219
220   memcpy(buf, ctx->vertices, sizeof(ctx->vertices));
221
222   ctx->pipe->winsys->buffer_unmap(ctx->pipe->winsys, ctx->vbuf);
223}
224
225
226/**
227 * Copy pixel block from src surface to dst surface.
228 * Overlapping regions are acceptable.
229 * XXX need some control over blitting Z and/or stencil.
230 */
231void
232util_blit_pixels(struct blit_state *ctx,
233                 struct pipe_surface *src,
234                 int srcX0, int srcY0,
235                 int srcX1, int srcY1,
236                 struct pipe_surface *dst,
237                 int dstX0, int dstY0,
238                 int dstX1, int dstY1,
239                 float z, uint filter)
240{
241   struct pipe_context *pipe = ctx->pipe;
242   struct pipe_screen *screen = pipe->screen;
243   struct pipe_texture texTemp, *tex;
244   struct pipe_surface *texSurf;
245   struct pipe_framebuffer_state fb;
246   const int srcW = abs(srcX1 - srcX0);
247   const int srcH = abs(srcY1 - srcY0);
248   const int srcLeft = MIN2(srcX0, srcX1);
249   const int srcTop = MIN2(srcY0, srcY1);
250
251   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
252          filter == PIPE_TEX_MIPFILTER_LINEAR);
253
254   if (srcLeft != srcX0) {
255      /* left-right flip */
256      int tmp = dstX0;
257      dstX0 = dstX1;
258      dstX1 = tmp;
259   }
260
261   if (srcTop != srcY0) {
262      /* up-down flip */
263      int tmp = dstY0;
264      dstY0 = dstY1;
265      dstY1 = tmp;
266   }
267
268   /*
269    * XXX for now we're always creating a temporary texture.
270    * Strictly speaking that's not always needed.
271    */
272
273   /* create temp texture */
274   memset(&texTemp, 0, sizeof(texTemp));
275   texTemp.target = PIPE_TEXTURE_2D;
276   texTemp.format = src->format;
277   texTemp.last_level = 0;
278   texTemp.width[0] = srcW;
279   texTemp.height[0] = srcH;
280   texTemp.depth[0] = 1;
281   texTemp.compressed = 0;
282   texTemp.cpp = pf_get_bits(src->format) / 8;
283
284   tex = screen->texture_create(screen, &texTemp);
285   if (!tex)
286      return;
287
288   texSurf = screen->get_tex_surface(screen, tex, 0, 0, 0);
289
290   /* load temp texture */
291   pipe->surface_copy(pipe, FALSE,
292                      texSurf, 0, 0,   /* dest */
293                      src, srcLeft, srcTop, /* src */
294                      srcW, srcH);     /* size */
295
296   /* save state (restored below) */
297   cso_save_blend(ctx->cso);
298   cso_save_depth_stencil_alpha(ctx->cso);
299   cso_save_rasterizer(ctx->cso);
300   cso_save_samplers(ctx->cso);
301   cso_save_sampler_textures(ctx->cso);
302   cso_save_framebuffer(ctx->cso);
303
304   /* set misc state we care about */
305   cso_set_blend(ctx->cso, &ctx->blend);
306   cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
307   cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
308
309   /* sampler */
310   ctx->sampler.min_img_filter = filter;
311   ctx->sampler.mag_img_filter = filter;
312   cso_single_sampler(ctx->cso, 0, &ctx->sampler);
313   cso_single_sampler_done(ctx->cso);
314
315   /* texture */
316   pipe->set_sampler_textures(pipe, 1, &tex);
317
318   /* shaders */
319   pipe->bind_fs_state(pipe, ctx->fs);
320   pipe->bind_vs_state(pipe, ctx->vs);
321
322   /* drawing dest */
323   memset(&fb, 0, sizeof(fb));
324   fb.width = dst->width;
325   fb.height = dst->height;
326   fb.num_cbufs = 1;
327   fb.cbufs[0] = dst;
328   cso_set_framebuffer(ctx->cso, &fb);
329
330   /* draw quad */
331   setup_vertex_data(ctx,
332                     (float) dstX0, (float) dstY0,
333                     (float) dstX1, (float) dstY1, z);
334
335   util_draw_vertex_buffer(ctx->pipe, ctx->vbuf,
336                           PIPE_PRIM_TRIANGLE_FAN,
337                           4,  /* verts */
338                           2); /* attribs/vert */
339
340   /* restore state we changed */
341   cso_restore_blend(ctx->cso);
342   cso_restore_depth_stencil_alpha(ctx->cso);
343   cso_restore_rasterizer(ctx->cso);
344   cso_restore_samplers(ctx->cso);
345   cso_restore_sampler_textures(ctx->cso);
346   cso_restore_framebuffer(ctx->cso);
347
348   /* free the texture */
349   pipe_surface_reference(&texSurf, NULL);
350   screen->texture_release(screen, &tex);
351}
352
353