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