util: Reset clip state when doing blitting.
[mesa.git] / src / gallium / auxiliary / util / u_blit.c
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 "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_simple_shaders.h"
49 #include "util/u_surface.h"
50 #include "util/u_rect.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;
61 struct pipe_depth_stencil_alpha_state depthstencil;
62 struct pipe_rasterizer_state rasterizer;
63 struct pipe_sampler_state sampler;
64 struct pipe_viewport_state viewport;
65 struct pipe_clip_state clip;
66
67 void *vs;
68 void *fs[TGSI_WRITEMASK_XYZW + 1];
69
70 struct pipe_buffer *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 *
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 memset(&ctx->blend, 0, sizeof(ctx->blend));
96 ctx->blend.rt[0].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.gl_rasterization_rules = 1;
106
107 /* samplers */
108 memset(&ctx->sampler, 0, sizeof(ctx->sampler));
109 ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
110 ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
111 ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
112 ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
113 ctx->sampler.min_img_filter = 0; /* set later */
114 ctx->sampler.mag_img_filter = 0; /* set later */
115 ctx->sampler.normalized_coords = 1;
116
117 /* vertex shader - still required to provide the linkage between
118 * fragment shader input semantics and vertex_element/buffers.
119 */
120 {
121 const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
122 TGSI_SEMANTIC_GENERIC };
123 const uint semantic_indexes[] = { 0, 0 };
124 ctx->vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names,
125 semantic_indexes);
126 }
127
128 /* fragment shader */
129 ctx->fs[TGSI_WRITEMASK_XYZW] =
130 util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D);
131 ctx->vbuf = NULL;
132
133 /* init vertex data that doesn't change */
134 for (i = 0; i < 4; i++) {
135 ctx->vertices[i][0][3] = 1.0f; /* w */
136 ctx->vertices[i][1][2] = 0.0f; /* r */
137 ctx->vertices[i][1][3] = 1.0f; /* q */
138 }
139
140 return ctx;
141 }
142
143
144 /**
145 * Destroy a blit context
146 */
147 void
148 util_destroy_blit(struct blit_state *ctx)
149 {
150 struct pipe_context *pipe = ctx->pipe;
151 unsigned i;
152
153 pipe->delete_vs_state(pipe, ctx->vs);
154
155 for (i = 0; i < Elements(ctx->fs); i++)
156 if (ctx->fs[i])
157 pipe->delete_fs_state(pipe, ctx->fs[i]);
158
159 pipe_buffer_reference(&ctx->vbuf, NULL);
160
161 FREE(ctx);
162 }
163
164
165 /**
166 * Get offset of next free slot in vertex buffer for quad vertices.
167 */
168 static unsigned
169 get_next_slot( struct blit_state *ctx )
170 {
171 const unsigned max_slots = 4096 / sizeof ctx->vertices;
172
173 if (ctx->vbuf_slot >= max_slots)
174 util_blit_flush( ctx );
175
176 if (!ctx->vbuf) {
177 ctx->vbuf = pipe_buffer_create(ctx->pipe->screen,
178 32,
179 PIPE_BUFFER_USAGE_VERTEX,
180 max_slots * sizeof ctx->vertices);
181 }
182
183 return ctx->vbuf_slot++ * sizeof ctx->vertices;
184 }
185
186
187
188
189
190 /**
191 * Setup vertex data for the textured quad we'll draw.
192 * Note: y=0=top
193 */
194 static unsigned
195 setup_vertex_data_tex(struct blit_state *ctx,
196 float x0, float y0, float x1, float y1,
197 float s0, float t0, float s1, float t1,
198 float z)
199 {
200 unsigned offset;
201
202 ctx->vertices[0][0][0] = x0;
203 ctx->vertices[0][0][1] = y0;
204 ctx->vertices[0][0][2] = z;
205 ctx->vertices[0][1][0] = s0; /*s*/
206 ctx->vertices[0][1][1] = t0; /*t*/
207
208 ctx->vertices[1][0][0] = x1;
209 ctx->vertices[1][0][1] = y0;
210 ctx->vertices[1][0][2] = z;
211 ctx->vertices[1][1][0] = s1; /*s*/
212 ctx->vertices[1][1][1] = t0; /*t*/
213
214 ctx->vertices[2][0][0] = x1;
215 ctx->vertices[2][0][1] = y1;
216 ctx->vertices[2][0][2] = z;
217 ctx->vertices[2][1][0] = s1;
218 ctx->vertices[2][1][1] = t1;
219
220 ctx->vertices[3][0][0] = x0;
221 ctx->vertices[3][0][1] = y1;
222 ctx->vertices[3][0][2] = z;
223 ctx->vertices[3][1][0] = s0;
224 ctx->vertices[3][1][1] = t1;
225
226 offset = get_next_slot( ctx );
227
228 pipe_buffer_write_nooverlap(ctx->pipe->screen, ctx->vbuf,
229 offset, sizeof(ctx->vertices), ctx->vertices);
230
231 return offset;
232 }
233
234
235 /**
236 * \return TRUE if two regions overlap, FALSE otherwise
237 */
238 static boolean
239 regions_overlap(int srcX0, int srcY0,
240 int srcX1, int srcY1,
241 int dstX0, int dstY0,
242 int dstX1, int dstY1)
243 {
244 if (MAX2(srcX0, srcX1) < MIN2(dstX0, dstX1))
245 return FALSE; /* src completely left of dst */
246
247 if (MAX2(dstX0, dstX1) < MIN2(srcX0, srcX1))
248 return FALSE; /* dst completely left of src */
249
250 if (MAX2(srcY0, srcY1) < MIN2(dstY0, dstY1))
251 return FALSE; /* src completely above dst */
252
253 if (MAX2(dstY0, dstY1) < MIN2(srcY0, srcY1))
254 return FALSE; /* dst completely above src */
255
256 return TRUE; /* some overlap */
257 }
258
259
260 /**
261 * Copy pixel block from src surface to dst surface.
262 * Overlapping regions are acceptable.
263 * Flipping and stretching are supported.
264 * \param filter one of PIPE_TEX_MIPFILTER_NEAREST/LINEAR
265 * \param writemask controls which channels in the dest surface are sourced
266 * from the src surface. Disabled channels are sourced
267 * from (0,0,0,1).
268 * XXX need some control over blitting Z and/or stencil.
269 */
270 void
271 util_blit_pixels_writemask(struct blit_state *ctx,
272 struct pipe_surface *src,
273 int srcX0, int srcY0,
274 int srcX1, int srcY1,
275 struct pipe_surface *dst,
276 int dstX0, int dstY0,
277 int dstX1, int dstY1,
278 float z, uint filter,
279 uint writemask)
280 {
281 struct pipe_context *pipe = ctx->pipe;
282 struct pipe_screen *screen = pipe->screen;
283 struct pipe_texture *tex = NULL;
284 struct pipe_framebuffer_state fb;
285 const int srcW = abs(srcX1 - srcX0);
286 const int srcH = abs(srcY1 - srcY0);
287 unsigned offset;
288 boolean overlap;
289 float s0, t0, s1, t1;
290
291 assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
292 filter == PIPE_TEX_MIPFILTER_LINEAR);
293
294 assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
295 PIPE_TEXTURE_USAGE_SAMPLER, 0));
296 assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
297 PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
298
299 /* do the regions overlap? */
300 overlap = util_same_surface(src, dst) &&
301 regions_overlap(srcX0, srcY0, srcX1, srcY1,
302 dstX0, dstY0, dstX1, dstY1);
303
304 /*
305 * Check for simple case: no format conversion, no flipping, no stretching,
306 * no overlapping.
307 * Filter mode should not matter since there's no stretching.
308 */
309 if (pipe->surface_copy &&
310 dst->format == src->format &&
311 srcX0 < srcX1 &&
312 dstX0 < dstX1 &&
313 srcY0 < srcY1 &&
314 dstY0 < dstY1 &&
315 (dstX1 - dstX0) == (srcX1 - srcX0) &&
316 (dstY1 - dstY0) == (srcY1 - srcY0) &&
317 !overlap) {
318 pipe->surface_copy(pipe,
319 dst, dstX0, dstY0, /* dest */
320 src, srcX0, srcY0, /* src */
321 srcW, srcH); /* size */
322 return;
323 }
324
325 assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
326 PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
327
328 /* Create a temporary texture when src and dest alias or when src
329 * is anything other than a single-level 2d texture.
330 *
331 * This can still be improved upon.
332 */
333 if (util_same_surface(src, dst) ||
334 src->texture->target != PIPE_TEXTURE_2D ||
335 src->texture->last_level != 0)
336 {
337 struct pipe_texture texTemp;
338 struct pipe_surface *texSurf;
339 const int srcLeft = MIN2(srcX0, srcX1);
340 const int srcTop = MIN2(srcY0, srcY1);
341
342 if (srcLeft != srcX0) {
343 /* left-right flip */
344 int tmp = dstX0;
345 dstX0 = dstX1;
346 dstX1 = tmp;
347 }
348
349 if (srcTop != srcY0) {
350 /* up-down flip */
351 int tmp = dstY0;
352 dstY0 = dstY1;
353 dstY1 = tmp;
354 }
355
356 /* create temp texture */
357 memset(&texTemp, 0, sizeof(texTemp));
358 texTemp.target = PIPE_TEXTURE_2D;
359 texTemp.format = src->format;
360 texTemp.last_level = 0;
361 texTemp.width0 = srcW;
362 texTemp.height0 = srcH;
363 texTemp.depth0 = 1;
364
365 tex = screen->texture_create(screen, &texTemp);
366 if (!tex)
367 return;
368
369 texSurf = screen->get_tex_surface(screen, tex, 0, 0, 0,
370 PIPE_BUFFER_USAGE_GPU_WRITE);
371
372 /* load temp texture */
373 if (pipe->surface_copy) {
374 pipe->surface_copy(pipe,
375 texSurf, 0, 0, /* dest */
376 src, srcLeft, srcTop, /* src */
377 srcW, srcH); /* size */
378 } else {
379 util_surface_copy(pipe, FALSE,
380 texSurf, 0, 0, /* dest */
381 src, srcLeft, srcTop, /* src */
382 srcW, srcH); /* size */
383 }
384
385 /* free the surface, update the texture if necessary.
386 */
387 pipe_surface_reference(&texSurf, NULL);
388 s0 = 0.0f;
389 s1 = 1.0f;
390 t0 = 0.0f;
391 t1 = 1.0f;
392 }
393 else {
394 pipe_texture_reference(&tex, src->texture);
395 s0 = srcX0 / (float)tex->width0;
396 s1 = srcX1 / (float)tex->width0;
397 t0 = srcY0 / (float)tex->height0;
398 t1 = srcY1 / (float)tex->height0;
399 }
400
401
402 /* save state (restored below) */
403 cso_save_blend(ctx->cso);
404 cso_save_depth_stencil_alpha(ctx->cso);
405 cso_save_rasterizer(ctx->cso);
406 cso_save_samplers(ctx->cso);
407 cso_save_sampler_textures(ctx->cso);
408 cso_save_viewport(ctx->cso);
409 cso_save_framebuffer(ctx->cso);
410 cso_save_fragment_shader(ctx->cso);
411 cso_save_vertex_shader(ctx->cso);
412 cso_save_clip(ctx->cso);
413
414 /* set misc state we care about */
415 cso_set_blend(ctx->cso, &ctx->blend);
416 cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
417 cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
418 cso_set_clip(ctx->cso, &ctx->clip);
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 /* viewport */
427 ctx->viewport.scale[0] = 0.5f * dst->width;
428 ctx->viewport.scale[1] = 0.5f * dst->height;
429 ctx->viewport.scale[2] = 1.0f;
430 ctx->viewport.scale[3] = 1.0f;
431 ctx->viewport.translate[0] = 0.5f * dst->width;
432 ctx->viewport.translate[1] = 0.5f * dst->height;
433 ctx->viewport.translate[2] = 0.0f;
434 ctx->viewport.translate[3] = 0.0f;
435 cso_set_viewport(ctx->cso, &ctx->viewport);
436
437 /* texture */
438 cso_set_sampler_textures(ctx->cso, 1, &tex);
439
440 if (ctx->fs[writemask] == NULL)
441 ctx->fs[writemask] =
442 util_make_fragment_tex_shader_writemask(pipe, TGSI_TEXTURE_2D,
443 writemask);
444
445 /* shaders */
446 cso_set_fragment_shader_handle(ctx->cso, ctx->fs[writemask]);
447 cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
448
449 /* drawing dest */
450 memset(&fb, 0, sizeof(fb));
451 fb.width = dst->width;
452 fb.height = dst->height;
453 fb.nr_cbufs = 1;
454 fb.cbufs[0] = dst;
455 cso_set_framebuffer(ctx->cso, &fb);
456
457 /* draw quad */
458 offset = setup_vertex_data_tex(ctx,
459 (float) dstX0, (float) dstY0,
460 (float) dstX1, (float) dstY1,
461 s0, t0,
462 s1, t1,
463 z);
464
465 util_draw_vertex_buffer(ctx->pipe, ctx->vbuf, offset,
466 PIPE_PRIM_TRIANGLE_FAN,
467 4, /* verts */
468 2); /* attribs/vert */
469
470 /* restore state we changed */
471 cso_restore_blend(ctx->cso);
472 cso_restore_depth_stencil_alpha(ctx->cso);
473 cso_restore_rasterizer(ctx->cso);
474 cso_restore_samplers(ctx->cso);
475 cso_restore_sampler_textures(ctx->cso);
476 cso_restore_viewport(ctx->cso);
477 cso_restore_framebuffer(ctx->cso);
478 cso_restore_fragment_shader(ctx->cso);
479 cso_restore_vertex_shader(ctx->cso);
480 cso_restore_clip(ctx->cso);
481
482 pipe_texture_reference(&tex, NULL);
483 }
484
485
486 void
487 util_blit_pixels(struct blit_state *ctx,
488 struct pipe_surface *src,
489 int srcX0, int srcY0,
490 int srcX1, int srcY1,
491 struct pipe_surface *dst,
492 int dstX0, int dstY0,
493 int dstX1, int dstY1,
494 float z, uint filter )
495 {
496 util_blit_pixels_writemask( ctx, src,
497 srcX0, srcY0,
498 srcX1, srcY1,
499 dst,
500 dstX0, dstY0,
501 dstX1, dstY1,
502 z, filter,
503 TGSI_WRITEMASK_XYZW );
504 }
505
506
507 /* Release vertex buffer at end of frame to avoid synchronous
508 * rendering.
509 */
510 void util_blit_flush( struct blit_state *ctx )
511 {
512 pipe_buffer_reference(&ctx->vbuf, NULL);
513 ctx->vbuf_slot = 0;
514 }
515
516
517
518 /**
519 * Copy pixel block from src texture to dst surface.
520 * Overlapping regions are acceptable.
521 *
522 * XXX Should support selection of level.
523 * XXX need some control over blitting Z and/or stencil.
524 */
525 void
526 util_blit_pixels_tex(struct blit_state *ctx,
527 struct pipe_texture *tex,
528 int srcX0, int srcY0,
529 int srcX1, int srcY1,
530 struct pipe_surface *dst,
531 int dstX0, int dstY0,
532 int dstX1, int dstY1,
533 float z, uint filter)
534 {
535 struct pipe_framebuffer_state fb;
536 float s0, t0, s1, t1;
537 unsigned offset;
538
539 assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
540 filter == PIPE_TEX_MIPFILTER_LINEAR);
541
542 assert(tex->width0 != 0);
543 assert(tex->height0 != 0);
544
545 s0 = srcX0 / (float)tex->width0;
546 s1 = srcX1 / (float)tex->width0;
547 t0 = srcY0 / (float)tex->height0;
548 t1 = srcY1 / (float)tex->height0;
549
550 assert(ctx->pipe->screen->is_format_supported(ctx->pipe->screen, dst->format,
551 PIPE_TEXTURE_2D,
552 PIPE_TEXTURE_USAGE_RENDER_TARGET,
553 0));
554
555 /* save state (restored below) */
556 cso_save_blend(ctx->cso);
557 cso_save_depth_stencil_alpha(ctx->cso);
558 cso_save_rasterizer(ctx->cso);
559 cso_save_samplers(ctx->cso);
560 cso_save_sampler_textures(ctx->cso);
561 cso_save_framebuffer(ctx->cso);
562 cso_save_fragment_shader(ctx->cso);
563 cso_save_vertex_shader(ctx->cso);
564 cso_save_clip(ctx->cso);
565
566 /* set misc state we care about */
567 cso_set_blend(ctx->cso, &ctx->blend);
568 cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
569 cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
570 cso_set_clip(ctx->cso, &ctx->clip);
571
572 /* sampler */
573 ctx->sampler.min_img_filter = filter;
574 ctx->sampler.mag_img_filter = filter;
575 cso_single_sampler(ctx->cso, 0, &ctx->sampler);
576 cso_single_sampler_done(ctx->cso);
577
578 /* texture */
579 cso_set_sampler_textures(ctx->cso, 1, &tex);
580
581 /* shaders */
582 cso_set_fragment_shader_handle(ctx->cso, ctx->fs[TGSI_WRITEMASK_XYZW]);
583 cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
584
585 /* drawing dest */
586 memset(&fb, 0, sizeof(fb));
587 fb.width = dst->width;
588 fb.height = dst->height;
589 fb.nr_cbufs = 1;
590 fb.cbufs[0] = dst;
591 cso_set_framebuffer(ctx->cso, &fb);
592
593 /* draw quad */
594 offset = setup_vertex_data_tex(ctx,
595 (float) dstX0, (float) dstY0,
596 (float) dstX1, (float) dstY1,
597 s0, t0, s1, t1,
598 z);
599
600 util_draw_vertex_buffer(ctx->pipe,
601 ctx->vbuf, offset,
602 PIPE_PRIM_TRIANGLE_FAN,
603 4, /* verts */
604 2); /* attribs/vert */
605
606 /* restore state we changed */
607 cso_restore_blend(ctx->cso);
608 cso_restore_depth_stencil_alpha(ctx->cso);
609 cso_restore_rasterizer(ctx->cso);
610 cso_restore_samplers(ctx->cso);
611 cso_restore_sampler_textures(ctx->cso);
612 cso_restore_framebuffer(ctx->cso);
613 cso_restore_fragment_shader(ctx->cso);
614 cso_restore_vertex_shader(ctx->cso);
615 cso_restore_clip(ctx->cso);
616 }