Eliminate struct pipe_region.
[mesa.git] / src / mesa / state_tracker / st_cb_drawpixels.c
1 /**************************************************************************
2 *
3 * Copyright 2007 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 * Authors:
30 * Brian Paul
31 */
32
33 #include "main/imports.h"
34 #include "main/image.h"
35 #include "main/macros.h"
36 #include "main/texformat.h"
37 #include "shader/program.h"
38 #include "shader/prog_parameter.h"
39 #include "shader/prog_print.h"
40
41 #include "st_context.h"
42 #include "st_atom.h"
43 #include "st_atom_constbuf.h"
44 #include "st_cache.h"
45 #include "st_draw.h"
46 #include "st_program.h"
47 #include "st_cb_drawpixels.h"
48 #include "st_cb_readpixels.h"
49 #include "st_cb_fbo.h"
50 #include "st_cb_texture.h"
51 #include "st_draw.h"
52 #include "st_format.h"
53 #include "st_mesa_to_tgsi.h"
54 #include "st_texture.h"
55 #include "pipe/p_context.h"
56 #include "pipe/p_defines.h"
57 #include "pipe/p_inlines.h"
58 #include "pipe/p_winsys.h"
59 #include "shader/prog_instruction.h"
60
61
62 /**
63 * Check if the given program is:
64 * 0: MOVE result.color, fragment.color;
65 * 1: END;
66 */
67 static GLboolean
68 is_passthrough_program(const struct gl_fragment_program *prog)
69 {
70 if (prog->Base.NumInstructions == 2) {
71 const struct prog_instruction *inst = prog->Base.Instructions;
72 if (inst[0].Opcode == OPCODE_MOV &&
73 inst[1].Opcode == OPCODE_END &&
74 inst[0].DstReg.File == PROGRAM_OUTPUT &&
75 inst[0].DstReg.Index == FRAG_RESULT_COLR &&
76 inst[0].DstReg.WriteMask == WRITEMASK_XYZW &&
77 inst[0].SrcReg[0].File == PROGRAM_INPUT &&
78 inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 &&
79 inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) {
80 return GL_TRUE;
81 }
82 }
83 return GL_FALSE;
84 }
85
86
87 /**
88 * Make fragment program for glBitmap:
89 * Sample the texture and kill the fragment if the bit is 0.
90 * This program will be combined with the user's fragment program.
91 */
92 static struct st_fragment_program *
93 make_bitmap_fragment_program(GLcontext *ctx)
94 {
95 struct st_fragment_program *stfp;
96 struct gl_program *p;
97 GLuint ic = 0;
98
99 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
100 if (!p)
101 return NULL;
102
103 p->NumInstructions = 5;
104
105 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
106 if (!p->Instructions) {
107 ctx->Driver.DeleteProgram(ctx, p);
108 return NULL;
109 }
110 _mesa_init_instructions(p->Instructions, p->NumInstructions);
111
112 /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
113 p->Instructions[ic].Opcode = OPCODE_TEX;
114 p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
115 p->Instructions[ic].DstReg.Index = 0;
116 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
117 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
118 p->Instructions[ic].TexSrcUnit = 0;
119 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
120 ic++;
121
122 /* SWZ tmp0.x, tmp0.x, 1111; # tmp0.x = 1.0 */
123 p->Instructions[ic].Opcode = OPCODE_SWZ;
124 p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
125 p->Instructions[ic].DstReg.Index = 0;
126 p->Instructions[ic].DstReg.WriteMask = WRITEMASK_X;
127 p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
128 p->Instructions[ic].SrcReg[0].Index = 0;
129 p->Instructions[ic].SrcReg[0].Swizzle
130 = MAKE_SWIZZLE4(SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE );
131 ic++;
132
133 /* SUB tmp0, tmp0.wwww, tmp0.xxxx; # tmp0.w -= 1 */
134 p->Instructions[ic].Opcode = OPCODE_SUB;
135 p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
136 p->Instructions[ic].DstReg.Index = 0;
137 p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
138 p->Instructions[ic].SrcReg[0].Index = 0;
139 p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_WWWW;
140 p->Instructions[ic].SrcReg[1].File = PROGRAM_TEMPORARY;
141 p->Instructions[ic].SrcReg[1].Index = 0;
142 p->Instructions[ic].SrcReg[1].Swizzle = SWIZZLE_XXXX; /* 1.0 */
143 ic++;
144
145 /* KIL if tmp0 < 0 */
146 p->Instructions[ic].Opcode = OPCODE_KIL;
147 p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
148 p->Instructions[ic].SrcReg[0].Index = 0;
149 ic++;
150
151 /* END; */
152 p->Instructions[ic++].Opcode = OPCODE_END;
153
154 assert(ic == p->NumInstructions);
155
156 p->InputsRead = FRAG_BIT_TEX0;
157 p->OutputsWritten = 0x0;
158
159 stfp = (struct st_fragment_program *) p;
160 st_translate_fragment_program(ctx->st, stfp, NULL,
161 stfp->tokens, ST_MAX_SHADER_TOKENS);
162
163 return stfp;
164 }
165
166
167 /**
168 * Combine basic bitmap fragment program with the user-defined program.
169 */
170 static struct st_fragment_program *
171 combined_bitmap_fragment_program(GLcontext *ctx)
172 {
173 struct st_context *st = ctx->st;
174 struct st_fragment_program *stfp;
175
176 if (!st->bitmap.program) {
177 /* create the basic bitmap fragment program */
178 st->bitmap.program = make_bitmap_fragment_program(ctx);
179 }
180
181 if (st->bitmap.user_prog_sn == st->fp->serialNo) {
182 /* re-use */
183 stfp = st->bitmap.combined_prog;
184 }
185 else {
186 /* Concatenate the bitmap program with the current user-defined program.
187 */
188 stfp = (struct st_fragment_program *)
189 _mesa_combine_programs(ctx,
190 &st->bitmap.program->Base.Base,
191 &st->fp->Base.Base);
192
193 #if 0
194 {
195 struct gl_program *p = &stfp->Base.Base;
196 printf("Combined bitmap program:\n");
197 _mesa_print_program(p);
198 printf("InputsRead: 0x%x\n", p->InputsRead);
199 printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
200 _mesa_print_parameter_list(p->Parameters);
201 }
202 #endif
203
204 /* translate to TGSI tokens */
205 st_translate_fragment_program(st, stfp, NULL,
206 stfp->tokens, ST_MAX_SHADER_TOKENS);
207
208 /* save new program, update serial numbers */
209 st->bitmap.user_prog_sn = st->fp->serialNo;
210 st->bitmap.combined_prog = stfp;
211 }
212
213 /* Ideally we'd have updated the pipe constants during the normal
214 * st/atom mechanism. But we can't since this is specific to glBitmap.
215 */
216 st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
217
218 return stfp;
219 }
220
221
222
223 /**
224 * Make fragment shader for glDraw/CopyPixels. This shader is made
225 * by combining the pixel transfer shader with the user-defined shader.
226 */
227 static struct st_fragment_program *
228 combined_drawpix_fragment_program(GLcontext *ctx)
229 {
230 struct st_context *st = ctx->st;
231 struct st_fragment_program *stfp;
232
233 if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
234 && st->fp->serialNo == st->pixel_xfer.user_prog_sn) {
235 /* the pixel tranfer program has not changed and the user-defined
236 * program has not changed, so re-use the combined program.
237 */
238 stfp = st->pixel_xfer.combined_prog;
239 }
240 else {
241 /* Concatenate the pixel transfer program with the current user-
242 * defined program.
243 */
244 if (is_passthrough_program(&st->fp->Base)) {
245 stfp = (struct st_fragment_program *)
246 _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base);
247 }
248 else {
249 stfp = (struct st_fragment_program *)
250 _mesa_combine_programs(ctx,
251 &st->pixel_xfer.program->Base.Base,
252 &st->fp->Base.Base);
253 }
254
255 #if 0
256 {
257 struct gl_program *p = &stfp->Base.Base;
258 printf("Combined DrawPixels program:\n");
259 _mesa_print_program(p);
260 printf("InputsRead: 0x%x\n", p->InputsRead);
261 printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
262 _mesa_print_parameter_list(p->Parameters);
263 }
264 #endif
265
266 /* translate to TGSI tokens */
267 st_translate_fragment_program(st, stfp, NULL,
268 stfp->tokens, ST_MAX_SHADER_TOKENS);
269
270 /* save new program, update serial numbers */
271 st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
272 st->pixel_xfer.user_prog_sn = st->fp->serialNo;
273 st->pixel_xfer.combined_prog_sn = stfp->serialNo;
274 st->pixel_xfer.combined_prog = stfp;
275 }
276
277 /* Ideally we'd have updated the pipe constants during the normal
278 * st/atom mechanism. But we can't since this is specific to glDrawPixels.
279 */
280 st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
281
282 return stfp;
283 }
284
285
286 /**
287 * Create fragment shader that does a TEX() instruction to get a Z
288 * value, then writes to FRAG_RESULT_DEPR.
289 * Pass fragment color through as-is.
290 */
291 static struct st_fragment_program *
292 make_fragment_shader_z(struct st_context *st)
293 {
294 GLcontext *ctx = st->ctx;
295 /* only make programs once and re-use */
296 static struct st_fragment_program *stfp = NULL;
297 struct gl_program *p;
298 GLuint ic = 0;
299
300 if (stfp)
301 return stfp;
302
303 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
304 if (!p)
305 return NULL;
306
307 p->NumInstructions = 3;
308
309 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
310 if (!p->Instructions) {
311 ctx->Driver.DeleteProgram(ctx, p);
312 return NULL;
313 }
314 _mesa_init_instructions(p->Instructions, p->NumInstructions);
315
316 /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */
317 p->Instructions[ic].Opcode = OPCODE_TEX;
318 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
319 p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR;
320 p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
321 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
322 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
323 p->Instructions[ic].TexSrcUnit = 0;
324 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
325 ic++;
326
327 /* MOV result.color, fragment.color */
328 p->Instructions[ic].Opcode = OPCODE_MOV;
329 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
330 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
331 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
332 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
333 ic++;
334
335 /* END; */
336 p->Instructions[ic++].Opcode = OPCODE_END;
337
338 assert(ic == p->NumInstructions);
339
340 p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
341 p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR);
342
343 stfp = (struct st_fragment_program *) p;
344 st_translate_fragment_program(st, stfp, NULL,
345 stfp->tokens, ST_MAX_SHADER_TOKENS);
346
347 return stfp;
348 }
349
350
351
352 /**
353 * Create a simple vertex shader that just passes through the
354 * vertex position and texcoord (and optionally, color).
355 */
356 static struct st_vertex_program *
357 make_vertex_shader(struct st_context *st, GLboolean passColor)
358 {
359 /* only make programs once and re-use */
360 static struct st_vertex_program *progs[2] = { NULL, NULL };
361 GLcontext *ctx = st->ctx;
362 struct st_vertex_program *stvp;
363 struct gl_program *p;
364 GLuint ic = 0;
365
366 if (progs[passColor])
367 return progs[passColor];
368
369 p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
370 if (!p)
371 return NULL;
372
373 if (passColor)
374 p->NumInstructions = 4;
375 else
376 p->NumInstructions = 3;
377
378 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
379 if (!p->Instructions) {
380 ctx->Driver.DeleteProgram(ctx, p);
381 return NULL;
382 }
383 _mesa_init_instructions(p->Instructions, p->NumInstructions);
384 /* MOV result.pos, vertex.pos; */
385 p->Instructions[0].Opcode = OPCODE_MOV;
386 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
387 p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
388 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
389 p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
390 /* MOV result.texcoord0, vertex.texcoord0; */
391 p->Instructions[1].Opcode = OPCODE_MOV;
392 p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
393 p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
394 p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
395 p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
396 ic = 2;
397 if (passColor) {
398 /* MOV result.color0, vertex.color0; */
399 p->Instructions[ic].Opcode = OPCODE_MOV;
400 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
401 p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
402 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
403 p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
404 ic++;
405 }
406
407 /* END; */
408 p->Instructions[ic].Opcode = OPCODE_END;
409 ic++;
410
411 assert(ic == p->NumInstructions);
412
413 p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
414 p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
415 (1 << VERT_RESULT_HPOS));
416 if (passColor) {
417 p->InputsRead |= VERT_BIT_COLOR0;
418 p->OutputsWritten |= (1 << VERT_RESULT_COL0);
419 }
420
421 stvp = (struct st_vertex_program *) p;
422 st_translate_vertex_program(st, stvp, NULL,
423 stvp->tokens, ST_MAX_SHADER_TOKENS);
424
425 progs[passColor] = stvp;
426
427 return stvp;
428 }
429
430
431 static GLenum
432 _mesa_base_format(GLenum format)
433 {
434 switch (format) {
435 case GL_DEPTH_COMPONENT:
436 return GL_DEPTH_COMPONENT;
437 case GL_STENCIL_INDEX:
438 return GL_STENCIL_INDEX;
439 default:
440 return GL_RGBA;
441 }
442 }
443
444
445 /**
446 * Make texture containing an image for glDrawPixels image.
447 * If 'pixels' is NULL, leave the texture image data undefined.
448 */
449 static struct pipe_texture *
450 make_texture(struct st_context *st,
451 GLsizei width, GLsizei height, GLenum format, GLenum type,
452 const struct gl_pixelstore_attrib *unpack,
453 const GLvoid *pixels)
454 {
455 GLcontext *ctx = st->ctx;
456 struct pipe_context *pipe = st->pipe;
457 const struct gl_texture_format *mformat;
458 struct pipe_texture *pt;
459 GLuint pipeFormat, cpp;
460 GLenum baseFormat;
461
462 baseFormat = _mesa_base_format(format);
463
464 mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type);
465 assert(mformat);
466
467 pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
468 assert(pipeFormat);
469 cpp = st_sizeof_format(pipeFormat);
470
471 pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, baseFormat, 0, 0,
472 width, height, 1, 0);
473 if (!pt)
474 return NULL;
475
476 if (unpack->BufferObj && unpack->BufferObj->Name) {
477 /*
478 pt->region = buffer_object_region(unpack->BufferObj);
479 */
480 printf("st_DrawPixels (sourcing from PBO not implemented yet)\n");
481 }
482
483 {
484 struct pipe_surface *surface;
485 static const GLuint dstImageOffsets = 0;
486 GLboolean success;
487 GLubyte *dest;
488 const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
489
490 /* we'll do pixel transfer in a fragment shader */
491 ctx->_ImageTransferState = 0x0;
492
493 surface = pipe->get_tex_surface(pipe, pt, 0, 0, 0);
494
495 /* map texture surface */
496 dest = pipe_surface_map(surface);
497
498 /* Put image into texture surface.
499 * Note that the image is actually going to be upside down in
500 * the texture. We deal with that with texcoords.
501 */
502 success = mformat->StoreImage(ctx, 2, /* dims */
503 baseFormat, /* baseInternalFormat */
504 mformat, /* gl_texture_format */
505 dest, /* dest */
506 0, 0, 0, /* dstX/Y/Zoffset */
507 surface->pitch * cpp, /* dstRowStride, bytes */
508 &dstImageOffsets, /* dstImageOffsets */
509 width, height, 1, /* size */
510 format, type, /* src format/type */
511 pixels, /* data source */
512 unpack);
513
514 /* unmap */
515 pipe_surface_unmap(surface);
516 pipe_surface_reference(&surface, NULL);
517 assert(success);
518
519 /* restore */
520 ctx->_ImageTransferState = imageTransferStateSave;
521 }
522
523 return pt;
524 }
525
526
527 /**
528 * Draw textured quad.
529 * Coords are window coords with y=0=bottom.
530 */
531 static void
532 draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
533 GLfloat x1, GLfloat y1, GLboolean invertTex)
534 {
535 GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
536 GLuint i;
537 GLfloat tTop = invertTex, tBot = 1.0 - tTop;
538
539 /* upper-left */
540 verts[0][0][0] = x0; /* attr[0].x */
541 verts[0][0][1] = y0; /* attr[0].x */
542 verts[0][1][0] = 0.0; /* attr[1].s */
543 verts[0][1][1] = tTop; /* attr[1].t */
544
545 /* upper-right */
546 verts[1][0][0] = x1;
547 verts[1][0][1] = y0;
548 verts[1][1][0] = 1.0;
549 verts[1][1][1] = tTop;
550
551 /* lower-right */
552 verts[2][0][0] = x1;
553 verts[2][0][1] = y1;
554 verts[2][1][0] = 1.0;
555 verts[2][1][1] = tBot;
556
557 /* lower-left */
558 verts[3][0][0] = x0;
559 verts[3][0][1] = y1;
560 verts[3][1][0] = 0.0;
561 verts[3][1][1] = tBot;
562
563 /* same for all verts: */
564 for (i = 0; i < 4; i++) {
565 verts[i][0][2] = z; /*Z*/
566 verts[i][0][3] = 1.0; /*W*/
567 verts[i][1][2] = 0.0; /*R*/
568 verts[i][1][3] = 1.0; /*Q*/
569 }
570
571 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2);
572 }
573
574
575 static void
576 draw_quad_colored(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
577 GLfloat x1, GLfloat y1, const GLfloat *color,
578 GLboolean invertTex)
579 {
580 GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
581 GLuint i;
582 GLfloat tTop = invertTex, tBot = 1.0 - tTop;
583
584 /* upper-left */
585 verts[0][0][0] = x0; /* attr[0].x */
586 verts[0][0][1] = y0; /* attr[0].y */
587 verts[0][2][0] = 0.0; /* attr[2].s */
588 verts[0][2][1] = tTop; /* attr[2].t */
589
590 /* upper-right */
591 verts[1][0][0] = x1;
592 verts[1][0][1] = y0;
593 verts[1][2][0] = 1.0;
594 verts[1][2][1] = tTop;
595
596 /* lower-right */
597 verts[2][0][0] = x1;
598 verts[2][0][1] = y1;
599 verts[2][2][0] = 1.0;
600 verts[2][2][1] = tBot;
601
602 /* lower-left */
603 verts[3][0][0] = x0;
604 verts[3][0][1] = y1;
605 verts[3][2][0] = 0.0;
606 verts[3][2][1] = tBot;
607
608 /* same for all verts: */
609 for (i = 0; i < 4; i++) {
610 verts[i][0][2] = z; /*Z*/
611 verts[i][0][3] = 1.0; /*W*/
612 verts[i][1][0] = color[0];
613 verts[i][1][1] = color[1];
614 verts[i][1][2] = color[2];
615 verts[i][1][3] = color[3];
616 verts[i][2][2] = 0.0; /*R*/
617 verts[i][2][3] = 1.0; /*Q*/
618 }
619
620 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 3);
621 }
622
623
624
625 static void
626 draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
627 GLsizei width, GLsizei height,
628 GLfloat zoomX, GLfloat zoomY,
629 struct pipe_texture *pt,
630 struct st_vertex_program *stvp,
631 struct st_fragment_program *stfp,
632 const GLfloat *color,
633 GLboolean invertTex)
634 {
635 const GLuint unit = 0;
636 struct pipe_context *pipe = ctx->st->pipe;
637 GLfloat x0, y0, x1, y1;
638 GLuint maxSize;
639
640 /* limit checks */
641 /* XXX if DrawPixels image is larger than max texture size, break
642 * it up into chunks.
643 */
644 maxSize = 1 << (pipe->get_param(pipe, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
645 assert(width <= maxSize);
646 assert(height <= maxSize);
647
648 /* setup state: just scissor */
649 {
650 struct pipe_rasterizer_state setup;
651 const struct cso_rasterizer *cso;
652 memset(&setup, 0, sizeof(setup));
653 if (ctx->Scissor.Enabled)
654 setup.scissor = 1;
655 cso = st_cached_rasterizer_state(ctx->st, &setup);
656 pipe->bind_rasterizer_state(pipe, cso->data);
657 }
658
659 /* fragment shader state: TEX lookup program */
660 pipe->bind_fs_state(pipe, stfp->fs->data);
661
662 /* vertex shader state: position + texcoord pass-through */
663 pipe->bind_vs_state(pipe, stvp->vs->data);
664
665 /* texture sampling state: */
666 {
667 struct pipe_sampler_state sampler;
668 const struct cso_sampler *cso;
669 memset(&sampler, 0, sizeof(sampler));
670 sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
671 sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
672 sampler.wrap_r = PIPE_TEX_WRAP_REPEAT;
673 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
674 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
675 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
676 sampler.normalized_coords = 1;
677 cso = st_cached_sampler_state(ctx->st, &sampler);
678 pipe->bind_sampler_state(pipe, unit, cso->data);
679 }
680
681 /* viewport state: viewport matching window dims */
682 {
683 const float width = ctx->DrawBuffer->Width;
684 const float height = ctx->DrawBuffer->Height;
685 struct pipe_viewport_state vp;
686 vp.scale[0] = 0.5 * width;
687 vp.scale[1] = -0.5 * height;
688 vp.scale[2] = 1.0;
689 vp.scale[3] = 1.0;
690 vp.translate[0] = 0.5 * width;
691 vp.translate[1] = 0.5 * height;
692 vp.translate[2] = 0.0;
693 vp.translate[3] = 0.0;
694 pipe->set_viewport_state(pipe, &vp);
695 }
696
697 /* texture state: */
698 {
699 pipe->set_texture_state(pipe, unit, pt);
700 }
701
702 /* Compute window coords (y=0=bottom) with pixel zoom.
703 * Recall that these coords are transformed by the current
704 * vertex shader and viewport transformation.
705 */
706 x0 = x;
707 x1 = x + width * ctx->Pixel.ZoomX;
708 y0 = y;
709 y1 = y + height * ctx->Pixel.ZoomY;
710
711 /* draw textured quad */
712 if (color)
713 draw_quad_colored(ctx, x0, y0, z, x1, y1, color, invertTex);
714 else
715 draw_quad(ctx, x0, y0, z, x1, y1, invertTex);
716
717 /* restore GL state */
718 pipe->bind_rasterizer_state(pipe, ctx->st->state.rasterizer->data);
719 pipe->bind_fs_state(pipe, ctx->st->state.fs->data);
720 pipe->bind_vs_state(pipe, ctx->st->state.vs->data);
721 pipe->set_texture_state(pipe, unit, ctx->st->state.texture[unit]);
722 pipe->bind_sampler_state(pipe, unit, ctx->st->state.sampler[unit]->data);
723 pipe->set_viewport_state(pipe, &ctx->st->state.viewport);
724 }
725
726
727 /**
728 * Check if a GL format/type combination is a match to the given pipe format.
729 * XXX probably move this to a re-usable place.
730 */
731 static GLboolean
732 compatible_formats(GLenum format, GLenum type, GLuint pipeFormat)
733 {
734 static const GLuint one = 1;
735 GLubyte littleEndian = *((GLubyte *) &one);
736
737 if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
738 format == GL_RGBA &&
739 type == GL_UNSIGNED_BYTE &&
740 !littleEndian) {
741 return GL_TRUE;
742 }
743 else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
744 format == GL_ABGR_EXT &&
745 type == GL_UNSIGNED_BYTE &&
746 littleEndian) {
747 return GL_TRUE;
748 }
749 else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 &&
750 format == GL_BGRA &&
751 type == GL_UNSIGNED_BYTE &&
752 littleEndian) {
753 return GL_TRUE;
754 }
755 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
756 format == GL_RGB &&
757 type == GL_UNSIGNED_SHORT_5_6_5) {
758 /* endian don't care */
759 return GL_TRUE;
760 }
761 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
762 format == GL_BGR &&
763 type == GL_UNSIGNED_SHORT_5_6_5_REV) {
764 /* endian don't care */
765 return GL_TRUE;
766 }
767 else if (pipeFormat == PIPE_FORMAT_U_S8 &&
768 format == GL_STENCIL_INDEX &&
769 type == GL_UNSIGNED_BYTE) {
770 return GL_TRUE;
771 }
772 else if (pipeFormat == PIPE_FORMAT_U_Z32 &&
773 format == GL_DEPTH_COMPONENT &&
774 type == GL_UNSIGNED_INT) {
775 return GL_TRUE;
776 }
777 /* XXX add more cases */
778 else {
779 return GL_FALSE;
780 }
781 }
782
783
784 /**
785 * Check if any per-fragment ops are enabled.
786 * XXX probably move this to a re-usable place.
787 */
788 static GLboolean
789 any_fragment_ops(const struct st_context *st)
790 {
791 if (st->state.alpha_test->state.enabled ||
792 st->state.blend->state.blend_enable ||
793 st->state.blend->state.logicop_enable ||
794 st->state.depth_stencil->state.depth.enabled)
795 /* XXX more checks */
796 return GL_TRUE;
797 else
798 return GL_FALSE;
799 }
800
801
802 /**
803 * Check if any pixel transfer ops are enabled.
804 * XXX probably move this to a re-usable place.
805 */
806 static GLboolean
807 any_pixel_transfer_ops(const struct st_context *st)
808 {
809 if (st->ctx->Pixel.RedScale != 1.0 ||
810 st->ctx->Pixel.RedBias != 0.0 ||
811 st->ctx->Pixel.GreenScale != 1.0 ||
812 st->ctx->Pixel.GreenBias != 0.0 ||
813 st->ctx->Pixel.BlueScale != 1.0 ||
814 st->ctx->Pixel.BlueBias != 0.0 ||
815 st->ctx->Pixel.AlphaScale != 1.0 ||
816 st->ctx->Pixel.AlphaBias != 0.0 ||
817 st->ctx->Pixel.MapColorFlag)
818 /* XXX more checks */
819 return GL_TRUE;
820 else
821 return GL_FALSE;
822 }
823
824
825 /**
826 * Draw image with a blit, or other non-textured quad method.
827 */
828 static void
829 draw_blit(struct st_context *st,
830 GLsizei width, GLsizei height,
831 GLenum format, GLenum type, const GLvoid *pixels)
832 {
833
834
835 }
836
837
838 static void
839 draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
840 GLsizei width, GLsizei height, GLenum type,
841 const struct gl_pixelstore_attrib *unpack,
842 const GLvoid *pixels)
843 {
844 struct st_context *st = ctx->st;
845 struct pipe_context *pipe = st->pipe;
846 struct pipe_surface *ps = st->state.framebuffer.sbuf;
847 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
848 GLint skipPixels;
849 ubyte *stmap;
850
851 pipe->flush(pipe, 0);
852
853 /* map the stencil buffer */
854 stmap = pipe_surface_map(ps);
855
856 /* if width > MAX_WIDTH, have to process image in chunks */
857 skipPixels = 0;
858 while (skipPixels < width) {
859 const GLint spanX = x + skipPixels;
860 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
861 GLint row;
862 for (row = 0; row < height; row++) {
863 GLint spanY = y + row;
864 GLubyte values[MAX_WIDTH];
865 GLenum destType = GL_UNSIGNED_BYTE;
866 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
867 width, height,
868 GL_COLOR_INDEX, type,
869 row, skipPixels);
870 _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
871 type, source, unpack,
872 ctx->_ImageTransferState);
873 if (zoom) {
874 /*
875 _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
876 spanX, spanY, values);
877 */
878 }
879 else {
880 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
881 spanY = ctx->DrawBuffer->Height - spanY - 1;
882 }
883
884 switch (ps->format) {
885 case PIPE_FORMAT_U_S8:
886 {
887 ubyte *dest = stmap + spanY * ps->pitch + spanX;
888 memcpy(dest, values, spanWidth);
889 }
890 break;
891 case PIPE_FORMAT_S8_Z24:
892 {
893 uint *dest = (uint *) stmap + spanY * ps->pitch + spanX;
894 GLint k;
895 for (k = 0; k < spanWidth; k++) {
896 uint p = dest[k];
897 p = (p & 0xffffff) | (values[k] << 24);
898 dest[k] = p;
899 }
900 }
901 break;
902 default:
903 assert(0);
904 }
905 }
906 }
907 skipPixels += spanWidth;
908 }
909
910 /* unmap the stencil buffer */
911 pipe_surface_unmap(ps);
912 }
913
914
915 /**
916 * Called via ctx->Driver.DrawPixels()
917 */
918 static void
919 st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
920 GLenum format, GLenum type,
921 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
922 {
923 struct st_fragment_program *stfp;
924 struct st_vertex_program *stvp;
925 struct st_context *st = ctx->st;
926 struct pipe_surface *ps;
927 GLuint bufferFormat;
928 const GLfloat *color;
929
930 if (format == GL_STENCIL_INDEX) {
931 draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
932 return;
933 }
934
935 st_validate_state(st);
936
937 if (format == GL_DEPTH_COMPONENT) {
938 ps = st->state.framebuffer.zbuf;
939 stfp = make_fragment_shader_z(ctx->st);
940 stvp = make_vertex_shader(ctx->st, GL_TRUE);
941 color = ctx->Current.RasterColor;
942 }
943 else if (format == GL_STENCIL_INDEX) {
944 ps = st->state.framebuffer.sbuf;
945 /* XXX special case - can't use texture map */
946 color = NULL;
947 }
948 else {
949 ps = st->state.framebuffer.cbufs[0];
950 stfp = combined_drawpix_fragment_program(ctx);
951 stvp = make_vertex_shader(ctx->st, GL_FALSE);
952 color = NULL;
953 }
954
955 bufferFormat = ps->format;
956
957 if (any_fragment_ops(st) ||
958 any_pixel_transfer_ops(st) ||
959 !compatible_formats(format, type, ps->format)) {
960 /* textured quad */
961 struct pipe_texture *pt
962 = make_texture(ctx->st, width, height, format, type, unpack, pixels);
963 if (pt) {
964 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
965 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
966 pt, stvp, stfp, color, GL_FALSE);
967 st->pipe->texture_release(st->pipe, &pt);
968 }
969 }
970 else {
971 /* blit */
972 draw_blit(st, width, height, format, type, pixels);
973 }
974 }
975
976
977
978 /**
979 * Create a texture which represents a bitmap image.
980 */
981 static struct pipe_texture *
982 make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height,
983 const struct gl_pixelstore_attrib *unpack,
984 const GLubyte *bitmap)
985 {
986 struct pipe_context *pipe = ctx->st->pipe;
987 struct pipe_surface *surface;
988 uint format = 0, cpp, comp;
989 GLenum internal_format;
990 ubyte *dest;
991 struct pipe_texture *pt;
992 int row, col;
993
994 /* find a texture format we know */
995 if (pipe->is_format_supported( pipe, PIPE_FORMAT_U_I8 )) {
996 format = PIPE_FORMAT_U_I8;
997 internal_format = GL_INTENSITY8;
998 cpp = 1;
999 comp = 0;
1000 }
1001 else if (pipe->is_format_supported( pipe, PIPE_FORMAT_U_A8_R8_G8_B8 )) {
1002 format = PIPE_FORMAT_U_A8_R8_G8_B8;
1003 internal_format = GL_RGBA8;
1004 cpp = 4;
1005 comp = 3; /* alpha channel */ /*XXX little-endian dependency */
1006 }
1007 else {
1008 /* XXX support more formats */
1009 assert( 0 );
1010 }
1011
1012 /**
1013 * Create a texture.
1014 */
1015 pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, internal_format,
1016 0, 0, width, height, 1, 0);
1017 if (!pt)
1018 return NULL;
1019
1020 if (unpack->BufferObj && unpack->BufferObj->Name) {
1021 /*
1022 pt->region = buffer_object_region(unpack->BufferObj);
1023 */
1024 printf("st_Bitmap (sourcing from PBO not implemented yet)\n");
1025 }
1026
1027 surface = pipe->get_tex_surface(pipe, pt, 0, 0, 0);
1028
1029 /* map texture surface */
1030 dest = pipe_surface_map(surface);
1031
1032 /* Put image into texture surface.
1033 * Note that the image is actually going to be upside down in
1034 * the texture. We deal with that with texcoords.
1035 */
1036
1037 for (row = 0; row < height; row++) {
1038 const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack,
1039 bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0);
1040 ubyte *destRow = dest + row * surface->pitch * cpp;
1041
1042 if (unpack->LsbFirst) {
1043 /* Lsb first */
1044 GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
1045 for (col = 0; col < width; col++) {
1046
1047 /* set texel to 255 if bit is set */
1048 destRow[comp] = (*src & mask) ? 255 : 0;
1049 destRow += cpp;
1050
1051 if (mask == 128U) {
1052 src++;
1053 mask = 1U;
1054 }
1055 else {
1056 mask = mask << 1;
1057 }
1058 }
1059
1060 /* get ready for next row */
1061 if (mask != 1)
1062 src++;
1063 }
1064 else {
1065 /* Msb first */
1066 GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
1067 for (col = 0; col < width; col++) {
1068
1069 /* set texel to 255 if bit is set */
1070 destRow[comp] =(*src & mask) ? 255 : 0;
1071 destRow += cpp;
1072
1073 if (mask == 1U) {
1074 src++;
1075 mask = 128U;
1076 }
1077 else {
1078 mask = mask >> 1;
1079 }
1080 }
1081
1082 /* get ready for next row */
1083 if (mask != 128)
1084 src++;
1085 }
1086
1087 } /* row */
1088
1089 /* Release surface */
1090 pipe_surface_unmap(surface);
1091 pipe_surface_reference(&surface, NULL);
1092
1093 pt->format = format;
1094
1095 return pt;
1096 }
1097
1098
1099
1100 static void
1101 st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
1102 const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
1103 {
1104 struct st_fragment_program *stfp;
1105 struct st_vertex_program *stvp;
1106 struct st_context *st = ctx->st;
1107 struct pipe_texture *pt;
1108
1109 stvp = make_vertex_shader(ctx->st, GL_TRUE);
1110 stfp = combined_bitmap_fragment_program(ctx);
1111
1112 st_validate_state(st);
1113
1114 pt = make_bitmap_texture(ctx, width, height, unpack, bitmap);
1115 if (pt) {
1116 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
1117 width, height, 1.0, 1.0,
1118 pt, stvp, stfp,
1119 ctx->Current.RasterColor, GL_FALSE);
1120
1121 st->pipe->texture_release(st->pipe, &pt);
1122 }
1123 }
1124
1125
1126 static void
1127 copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
1128 GLsizei width, GLsizei height,
1129 GLint dstx, GLint dsty)
1130 {
1131 struct st_renderbuffer *rbRead = st_renderbuffer(ctx->ReadBuffer->_StencilBuffer);
1132 struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
1133 struct pipe_surface *psRead = rbRead->surface;
1134 struct pipe_surface *psDraw = rbDraw->surface;
1135 ubyte *readMap, *drawMap;
1136 ubyte *buffer;
1137 int i;
1138
1139 buffer = malloc(width * height * sizeof(ubyte));
1140 if (!buffer) {
1141 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
1142 return;
1143 }
1144
1145 /* map the stencil buffers */
1146 readMap = pipe_surface_map(psRead);
1147 drawMap = pipe_surface_map(psDraw);
1148
1149 /* this will do stencil pixel transfer ops */
1150 st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE,
1151 &ctx->DefaultPacking, buffer);
1152
1153 /* draw */
1154 /* XXX PixelZoom not handled yet */
1155 for (i = 0; i < height; i++) {
1156 ubyte *dst;
1157 const ubyte *src;
1158 int y;
1159
1160 y = dsty + i;
1161
1162 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1163 y = ctx->DrawBuffer->Height - y - 1;
1164 }
1165
1166 dst = drawMap + (y * psDraw->pitch + dstx) * psDraw->cpp;
1167 src = buffer + i * width;
1168
1169 switch (psDraw->format) {
1170 case PIPE_FORMAT_S8_Z24:
1171 {
1172 uint *dst4 = (uint *) dst;
1173 int j;
1174 for (j = 0; j < width; j++) {
1175 *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
1176 dst4++;
1177 }
1178 }
1179 break;
1180 case PIPE_FORMAT_U_S8:
1181 memcpy(dst, src, width);
1182 break;
1183 default:
1184 assert(0);
1185 }
1186 }
1187
1188 free(buffer);
1189
1190 /* unmap the stencil buffers */
1191 pipe_surface_unmap(psRead);
1192 pipe_surface_unmap(psDraw);
1193 }
1194
1195
1196 static void
1197 st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
1198 GLsizei width, GLsizei height,
1199 GLint dstx, GLint dsty, GLenum type)
1200 {
1201 struct st_context *st = ctx->st;
1202 struct pipe_context *pipe = st->pipe;
1203 struct st_renderbuffer *rbRead;
1204 struct st_vertex_program *stvp;
1205 struct st_fragment_program *stfp;
1206 struct pipe_surface *psRead;
1207 struct pipe_surface *psTex;
1208 struct pipe_texture *pt;
1209 GLfloat *color;
1210 uint format;
1211
1212 /* make sure rendering has completed */
1213 pipe->flush(pipe, 0x0);
1214
1215 st_validate_state(st);
1216
1217 if (type == GL_STENCIL) {
1218 /* can't use texturing to do stencil */
1219 copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
1220 return;
1221 }
1222
1223 if (type == GL_COLOR) {
1224 rbRead = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
1225 color = NULL;
1226 stfp = combined_drawpix_fragment_program(ctx);
1227 stvp = make_vertex_shader(ctx->st, GL_FALSE);
1228 }
1229 else {
1230 rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
1231 color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
1232 stfp = make_fragment_shader_z(ctx->st);
1233 stvp = make_vertex_shader(ctx->st, GL_TRUE);
1234 }
1235
1236 psRead = rbRead->surface;
1237 format = psRead->format;
1238
1239 pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format,
1240 rbRead->Base.InternalFormat, 0, 0, width, height, 1, 0);
1241 if (!pt)
1242 return;
1243
1244 psTex = pipe->get_tex_surface(pipe, pt, 0, 0, 0);
1245
1246 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
1247 srcy = ctx->DrawBuffer->Height - srcy - height;
1248 }
1249
1250 /* For some drivers (like Xlib) it's not possible to treat the
1251 * front/back color buffers as surfaces (they're XImages and Pixmaps).
1252 * So, this var tells us if we can use surface_copy here...
1253 */
1254 if (st->haveFramebufferSurfaces) {
1255 /* copy source framebuffer surface into mipmap/texture */
1256 pipe->surface_copy(pipe,
1257 psTex, /* dest */
1258 0, 0, /* destx/y */
1259 psRead,
1260 srcx, srcy, width, height);
1261 }
1262 else {
1263 /* alternate path using get/put_tile() */
1264 GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
1265
1266 (void) pipe_surface_map(psRead);
1267 (void) pipe_surface_map(psTex);
1268
1269 pipe->get_tile_rgba(pipe, psRead, srcx, srcy, width, height, buf);
1270 pipe->put_tile_rgba(pipe, psTex, 0, 0, width, height, buf);
1271
1272 pipe_surface_unmap(psRead);
1273 pipe_surface_unmap(psTex);
1274
1275 free(buf);
1276 }
1277
1278 /* draw textured quad */
1279 draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1280 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1281 pt, stvp, stfp, color, GL_TRUE);
1282
1283 pipe_surface_reference(&psTex, NULL);
1284 st->pipe->texture_release(st->pipe, &pt);
1285 }
1286
1287
1288
1289 void st_init_drawpixels_functions(struct dd_function_table *functions)
1290 {
1291 functions->DrawPixels = st_DrawPixels;
1292 functions->CopyPixels = st_CopyPixels;
1293 functions->Bitmap = st_Bitmap;
1294 }