72a2ddb379ba37ba85f37c7b0647caf78aaaaf4a
[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/bufferobj.h"
36 #include "main/macros.h"
37 #include "main/texformat.h"
38 #include "main/texstore.h"
39 #include "shader/program.h"
40 #include "shader/prog_print.h"
41
42 #include "st_debug.h"
43 #include "st_context.h"
44 #include "st_atom.h"
45 #include "st_atom_constbuf.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_format.h"
51 #include "st_texture.h"
52 #include "st_inlines.h"
53
54 #include "pipe/p_context.h"
55 #include "pipe/p_defines.h"
56 #include "util/u_inlines.h"
57 #include "tgsi/tgsi_ureg.h"
58 #include "util/u_tile.h"
59 #include "util/u_draw_quad.h"
60 #include "util/u_format.h"
61 #include "util/u_math.h"
62 #include "util/u_rect.h"
63 #include "shader/prog_instruction.h"
64 #include "cso_cache/cso_context.h"
65
66
67 /**
68 * Check if the given program is:
69 * 0: MOVE result.color, fragment.color;
70 * 1: END;
71 */
72 static GLboolean
73 is_passthrough_program(const struct gl_fragment_program *prog)
74 {
75 if (prog->Base.NumInstructions == 2) {
76 const struct prog_instruction *inst = prog->Base.Instructions;
77 if (inst[0].Opcode == OPCODE_MOV &&
78 inst[1].Opcode == OPCODE_END &&
79 inst[0].DstReg.File == PROGRAM_OUTPUT &&
80 inst[0].DstReg.Index == FRAG_RESULT_COLOR &&
81 inst[0].DstReg.WriteMask == WRITEMASK_XYZW &&
82 inst[0].SrcReg[0].File == PROGRAM_INPUT &&
83 inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 &&
84 inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) {
85 return GL_TRUE;
86 }
87 }
88 return GL_FALSE;
89 }
90
91
92
93 /**
94 * Make fragment shader for glDraw/CopyPixels. This shader is made
95 * by combining the pixel transfer shader with the user-defined shader.
96 * \return pointer to Gallium driver fragment shader
97 */
98 static void *
99 combined_drawpix_fragment_program(GLcontext *ctx)
100 {
101 struct st_context *st = st_context(ctx);
102 struct st_fragment_program *stfp;
103
104 if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
105 && st->fp->serialNo == st->pixel_xfer.user_prog_sn) {
106 /* the pixel tranfer program has not changed and the user-defined
107 * program has not changed, so re-use the combined program.
108 */
109 stfp = st->pixel_xfer.combined_prog;
110 }
111 else {
112 /* Concatenate the pixel transfer program with the current user-
113 * defined program.
114 */
115 if (is_passthrough_program(&st->fp->Base)) {
116 stfp = (struct st_fragment_program *)
117 _mesa_clone_fragment_program(ctx, &st->pixel_xfer.program->Base);
118 }
119 else {
120 #if 0
121 printf("Base program:\n");
122 _mesa_print_program(&st->fp->Base.Base);
123 printf("DrawPix program:\n");
124 _mesa_print_program(&st->pixel_xfer.program->Base.Base);
125 #endif
126 stfp = (struct st_fragment_program *)
127 _mesa_combine_programs(ctx,
128 &st->pixel_xfer.program->Base.Base,
129 &st->fp->Base.Base);
130 }
131
132 #if 0
133 {
134 struct gl_program *p = &stfp->Base.Base;
135 printf("Combined DrawPixels program:\n");
136 _mesa_print_program(p);
137 printf("InputsRead: 0x%x\n", p->InputsRead);
138 printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
139 _mesa_print_parameter_list(p->Parameters);
140 }
141 #endif
142
143 /* translate to TGSI tokens */
144 st_translate_fragment_program(st, stfp);
145
146 /* save new program, update serial numbers */
147 st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
148 st->pixel_xfer.user_prog_sn = st->fp->serialNo;
149 st->pixel_xfer.combined_prog_sn = stfp->serialNo;
150 /* can't reference new program directly, already have a reference on it */
151 st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
152 st->pixel_xfer.combined_prog = stfp;
153 }
154
155 /* Ideally we'd have updated the pipe constants during the normal
156 * st/atom mechanism. But we can't since this is specific to glDrawPixels.
157 */
158 st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
159
160 return stfp->driver_shader;
161 }
162
163
164 /**
165 * Create fragment shader that does a TEX() instruction to get a Z
166 * value, then writes to FRAG_RESULT_DEPTH.
167 * Pass fragment color through as-is.
168 * \return pointer to the Gallium driver fragment shader
169 */
170 static void *
171 make_fragment_shader_z(struct st_context *st)
172 {
173 GLcontext *ctx = st->ctx;
174 struct gl_program *p;
175 GLuint ic = 0;
176
177 if (st->drawpix.z_shader) {
178 return st->drawpix.z_shader->driver_shader;
179 }
180
181 /*
182 * Create shader now
183 */
184 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
185 if (!p)
186 return NULL;
187
188 p->NumInstructions = 3;
189
190 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
191 if (!p->Instructions) {
192 ctx->Driver.DeleteProgram(ctx, p);
193 return NULL;
194 }
195 _mesa_init_instructions(p->Instructions, p->NumInstructions);
196
197 /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */
198 p->Instructions[ic].Opcode = OPCODE_TEX;
199 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
200 p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH;
201 p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
202 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
203 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
204 p->Instructions[ic].TexSrcUnit = 0;
205 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
206 ic++;
207
208 /* MOV result.color, fragment.color */
209 p->Instructions[ic].Opcode = OPCODE_MOV;
210 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
211 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLOR;
212 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
213 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0;
214 ic++;
215
216 /* END; */
217 p->Instructions[ic++].Opcode = OPCODE_END;
218
219 assert(ic == p->NumInstructions);
220
221 p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
222 p->OutputsWritten = (1 << FRAG_RESULT_COLOR) | (1 << FRAG_RESULT_DEPTH);
223 p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */
224
225 st->drawpix.z_shader = (struct st_fragment_program *) p;
226 st_translate_fragment_program(st, st->drawpix.z_shader);
227
228 return st->drawpix.z_shader->driver_shader;
229 }
230
231
232
233 /**
234 * Create a simple vertex shader that just passes through the
235 * vertex position and texcoord (and optionally, color).
236 */
237 static void *
238 make_passthrough_vertex_shader(struct st_context *st,
239 GLboolean passColor)
240 {
241 if (!st->drawpix.vert_shaders[passColor]) {
242 struct ureg_program *ureg =
243 ureg_create( TGSI_PROCESSOR_VERTEX );
244
245 if (ureg == NULL)
246 return NULL;
247
248 /* MOV result.pos, vertex.pos; */
249 ureg_MOV(ureg,
250 ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ),
251 ureg_DECL_vs_input( ureg, 0 ));
252
253 /* MOV result.texcoord0, vertex.texcoord0; */
254 ureg_MOV(ureg,
255 ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ),
256 ureg_DECL_vs_input( ureg, 1 ));
257
258 if (passColor) {
259 /* MOV result.color0, vertex.color0; */
260 ureg_MOV(ureg,
261 ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ),
262 ureg_DECL_vs_input( ureg, 2 ));
263 }
264
265 ureg_END( ureg );
266
267 st->drawpix.vert_shaders[passColor] =
268 ureg_create_shader_and_destroy( ureg, st->pipe );
269 }
270
271 return st->drawpix.vert_shaders[passColor];
272 }
273
274
275 /**
276 * Return a texture internalFormat for drawing/copying an image
277 * of the given type.
278 */
279 static GLenum
280 base_format(GLenum format)
281 {
282 switch (format) {
283 case GL_DEPTH_COMPONENT:
284 return GL_DEPTH_COMPONENT;
285 case GL_DEPTH_STENCIL:
286 return GL_DEPTH_STENCIL;
287 case GL_STENCIL_INDEX:
288 return GL_STENCIL_INDEX;
289 default:
290 return GL_RGBA;
291 }
292 }
293
294
295 /**
296 * Create a temporary texture to hold an image of the given size.
297 * If width, height are not POT and the driver only handles POT textures,
298 * allocate the next larger size of texture that is POT.
299 */
300 static struct pipe_texture *
301 alloc_texture(struct st_context *st, GLsizei width, GLsizei height,
302 enum pipe_format texFormat)
303 {
304 struct pipe_context *pipe = st->pipe;
305 struct pipe_screen *screen = pipe->screen;
306 struct pipe_texture *pt;
307 int ptw, pth;
308
309 ptw = width;
310 pth = height;
311
312 /* Need to use POT texture? */
313 if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) {
314 int l2pt, maxSize;
315
316 l2pt = util_logbase2(width);
317 if (1 << l2pt != width) {
318 ptw = 1 << (l2pt + 1);
319 }
320
321 l2pt = util_logbase2(height);
322 if (1 << l2pt != height) {
323 pth = 1 << (l2pt + 1);
324 }
325
326 /* Check against maximum texture size */
327 maxSize = 1 << (pipe->screen->get_param(pipe->screen,
328 PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
329 assert(ptw <= maxSize);
330 assert(pth <= maxSize);
331 }
332
333 pt = st_texture_create(st, PIPE_TEXTURE_2D, texFormat, 0,
334 ptw, pth, 1, PIPE_TEXTURE_USAGE_SAMPLER);
335
336 return pt;
337 }
338
339
340 /**
341 * Make texture containing an image for glDrawPixels image.
342 * If 'pixels' is NULL, leave the texture image data undefined.
343 */
344 static struct pipe_texture *
345 make_texture(struct st_context *st,
346 GLsizei width, GLsizei height, GLenum format, GLenum type,
347 const struct gl_pixelstore_attrib *unpack,
348 const GLvoid *pixels)
349 {
350 GLcontext *ctx = st->ctx;
351 struct pipe_context *pipe = st->pipe;
352 gl_format mformat;
353 struct pipe_texture *pt;
354 enum pipe_format pipeFormat;
355 GLuint cpp;
356 GLenum baseFormat;
357
358 baseFormat = base_format(format);
359
360 mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type);
361 assert(mformat);
362
363 pipeFormat = st_mesa_format_to_pipe_format(mformat);
364 assert(pipeFormat);
365 cpp = util_format_get_blocksize(pipeFormat);
366
367 pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
368 if (!pixels)
369 return NULL;
370
371 /* alloc temporary texture */
372 pt = alloc_texture(st, width, height, pipeFormat);
373 if (!pt) {
374 _mesa_unmap_pbo_source(ctx, unpack);
375 return NULL;
376 }
377
378 {
379 struct pipe_transfer *transfer;
380 static const GLuint dstImageOffsets = 0;
381 GLboolean success;
382 GLubyte *dest;
383 const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
384
385 /* we'll do pixel transfer in a fragment shader */
386 ctx->_ImageTransferState = 0x0;
387
388 transfer = st_no_flush_get_tex_transfer(st, pt, 0, 0, 0,
389 PIPE_TRANSFER_WRITE, 0, 0,
390 width, height);
391
392 /* map texture transfer */
393 dest = pipe->transfer_map(pipe, transfer);
394
395
396 /* Put image into texture transfer.
397 * Note that the image is actually going to be upside down in
398 * the texture. We deal with that with texcoords.
399 */
400 success = _mesa_texstore(ctx, 2, /* dims */
401 baseFormat, /* baseInternalFormat */
402 mformat, /* gl_format */
403 dest, /* dest */
404 0, 0, 0, /* dstX/Y/Zoffset */
405 transfer->stride, /* dstRowStride, bytes */
406 &dstImageOffsets, /* dstImageOffsets */
407 width, height, 1, /* size */
408 format, type, /* src format/type */
409 pixels, /* data source */
410 unpack);
411
412 /* unmap */
413 pipe->transfer_unmap(pipe, transfer);
414 pipe->tex_transfer_destroy(pipe, transfer);
415
416 assert(success);
417
418 /* restore */
419 ctx->_ImageTransferState = imageTransferStateSave;
420 }
421
422 _mesa_unmap_pbo_source(ctx, unpack);
423
424 return pt;
425 }
426
427
428 /**
429 * Draw quad with texcoords and optional color.
430 * Coords are gallium window coords with y=0=top.
431 * \param color may be null
432 * \param invertTex if true, flip texcoords vertically
433 */
434 static void
435 draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
436 GLfloat x1, GLfloat y1, const GLfloat *color,
437 GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord)
438 {
439 struct st_context *st = st_context(ctx);
440 struct pipe_context *pipe = st->pipe;
441 GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
442
443 /* setup vertex data */
444 {
445 const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
446 const GLfloat fb_width = (GLfloat) fb->Width;
447 const GLfloat fb_height = (GLfloat) fb->Height;
448 const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f;
449 const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f;
450 const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f;
451 const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f;
452 const GLfloat sLeft = 0.0f, sRight = maxXcoord;
453 const GLfloat tTop = invertTex ? maxYcoord : 0.0f;
454 const GLfloat tBot = invertTex ? 0.0f : maxYcoord;
455 GLuint tex, i;
456
457 /* upper-left */
458 verts[0][0][0] = clip_x0; /* v[0].attr[0].x */
459 verts[0][0][1] = clip_y0; /* v[0].attr[0].y */
460
461 /* upper-right */
462 verts[1][0][0] = clip_x1;
463 verts[1][0][1] = clip_y0;
464
465 /* lower-right */
466 verts[2][0][0] = clip_x1;
467 verts[2][0][1] = clip_y1;
468
469 /* lower-left */
470 verts[3][0][0] = clip_x0;
471 verts[3][0][1] = clip_y1;
472
473 tex = color ? 2 : 1;
474 verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */
475 verts[0][tex][1] = tTop; /* v[0].attr[tex].t */
476 verts[1][tex][0] = sRight;
477 verts[1][tex][1] = tTop;
478 verts[2][tex][0] = sRight;
479 verts[2][tex][1] = tBot;
480 verts[3][tex][0] = sLeft;
481 verts[3][tex][1] = tBot;
482
483 /* same for all verts: */
484 if (color) {
485 for (i = 0; i < 4; i++) {
486 verts[i][0][2] = z; /*Z*/
487 verts[i][0][3] = 1.0f; /*W*/
488 verts[i][1][0] = color[0];
489 verts[i][1][1] = color[1];
490 verts[i][1][2] = color[2];
491 verts[i][1][3] = color[3];
492 verts[i][2][2] = 0.0f; /*R*/
493 verts[i][2][3] = 1.0f; /*Q*/
494 }
495 }
496 else {
497 for (i = 0; i < 4; i++) {
498 verts[i][0][2] = z; /*Z*/
499 verts[i][0][3] = 1.0f; /*W*/
500 verts[i][1][2] = 0.0f; /*R*/
501 verts[i][1][3] = 1.0f; /*Q*/
502 }
503 }
504 }
505
506 {
507 struct pipe_buffer *buf;
508
509 /* allocate/load buffer object with vertex data */
510 buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX,
511 sizeof(verts));
512 st_no_flush_pipe_buffer_write(st, buf, 0, sizeof(verts), verts);
513
514 util_draw_vertex_buffer(pipe, buf, 0,
515 PIPE_PRIM_QUADS,
516 4, /* verts */
517 3); /* attribs/vert */
518 pipe_buffer_reference(&buf, NULL);
519 }
520 }
521
522
523
524 static void
525 draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
526 GLsizei width, GLsizei height,
527 GLfloat zoomX, GLfloat zoomY,
528 struct pipe_sampler_view *sv,
529 void *driver_vp,
530 void *driver_fp,
531 const GLfloat *color,
532 GLboolean invertTex)
533 {
534 struct st_context *st = st_context(ctx);
535 struct pipe_context *pipe = st->pipe;
536 struct cso_context *cso = st->cso_context;
537 GLfloat x0, y0, x1, y1;
538 GLsizei maxSize;
539
540 /* limit checks */
541 /* XXX if DrawPixels image is larger than max texture size, break
542 * it up into chunks.
543 */
544 maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
545 assert(width <= maxSize);
546 assert(height <= maxSize);
547
548 cso_save_rasterizer(cso);
549 cso_save_viewport(cso);
550 cso_save_samplers(cso);
551 cso_save_fragment_sampler_views(cso);
552 cso_save_fragment_shader(cso);
553 cso_save_vertex_shader(cso);
554 cso_save_vertex_elements(cso);
555
556 /* rasterizer state: just scissor */
557 {
558 struct pipe_rasterizer_state rasterizer;
559 memset(&rasterizer, 0, sizeof(rasterizer));
560 rasterizer.gl_rasterization_rules = 1;
561 rasterizer.scissor = ctx->Scissor.Enabled;
562 cso_set_rasterizer(cso, &rasterizer);
563 }
564
565 /* fragment shader state: TEX lookup program */
566 cso_set_fragment_shader_handle(cso, driver_fp);
567
568 /* vertex shader state: position + texcoord pass-through */
569 cso_set_vertex_shader_handle(cso, driver_vp);
570
571
572 /* texture sampling state: */
573 {
574 struct pipe_sampler_state sampler;
575 memset(&sampler, 0, sizeof(sampler));
576 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
577 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
578 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP;
579 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
580 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
581 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
582 sampler.normalized_coords = 1;
583
584 cso_single_sampler(cso, 0, &sampler);
585 if (st->pixel_xfer.pixelmap_enabled) {
586 cso_single_sampler(cso, 1, &sampler);
587 }
588 cso_single_sampler_done(cso);
589 }
590
591 /* viewport state: viewport matching window dims */
592 {
593 const float w = (float) ctx->DrawBuffer->Width;
594 const float h = (float) ctx->DrawBuffer->Height;
595 struct pipe_viewport_state vp;
596 vp.scale[0] = 0.5f * w;
597 vp.scale[1] = -0.5f * h;
598 vp.scale[2] = 0.5f;
599 vp.scale[3] = 1.0f;
600 vp.translate[0] = 0.5f * w;
601 vp.translate[1] = 0.5f * h;
602 vp.translate[2] = 0.5f;
603 vp.translate[3] = 0.0f;
604 cso_set_viewport(cso, &vp);
605 }
606
607 cso_set_vertex_elements(cso, 3, st->velems_util_draw);
608
609 /* texture state: */
610 if (st->pixel_xfer.pixelmap_enabled) {
611 struct pipe_sampler_view *sampler_views[2];
612 sampler_views[0] = sv;
613 sampler_views[1] = st->pixel_xfer.pixelmap_sampler_view;
614 cso_set_fragment_sampler_views(cso, 2, sampler_views);
615 }
616 else {
617 cso_set_fragment_sampler_views(cso, 1, &sv);
618 }
619
620 /* Compute Gallium window coords (y=0=top) with pixel zoom.
621 * Recall that these coords are transformed by the current
622 * vertex shader and viewport transformation.
623 */
624 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) {
625 y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY);
626 invertTex = !invertTex;
627 }
628
629 x0 = (GLfloat) x;
630 x1 = x + width * ctx->Pixel.ZoomX;
631 y0 = (GLfloat) y;
632 y1 = y + height * ctx->Pixel.ZoomY;
633
634 /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */
635 z = z * 2.0 - 1.0;
636
637 draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex,
638 (GLfloat) width / sv->texture->width0,
639 (GLfloat) height / sv->texture->height0);
640
641 /* restore state */
642 cso_restore_rasterizer(cso);
643 cso_restore_viewport(cso);
644 cso_restore_samplers(cso);
645 cso_restore_fragment_sampler_views(cso);
646 cso_restore_fragment_shader(cso);
647 cso_restore_vertex_shader(cso);
648 cso_restore_vertex_elements(cso);
649 }
650
651
652 static void
653 draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
654 GLsizei width, GLsizei height, GLenum format, GLenum type,
655 const struct gl_pixelstore_attrib *unpack,
656 const GLvoid *pixels)
657 {
658 struct st_context *st = st_context(ctx);
659 struct pipe_context *pipe = st->pipe;
660 struct st_renderbuffer *strb;
661 enum pipe_transfer_usage usage;
662 struct pipe_transfer *pt;
663 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
664 GLint skipPixels;
665 ubyte *stmap;
666 struct gl_pixelstore_attrib clippedUnpack = *unpack;
667
668 if (!zoom) {
669 if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height,
670 &clippedUnpack)) {
671 /* totally clipped */
672 return;
673 }
674 }
675
676 strb = st_renderbuffer(ctx->DrawBuffer->
677 Attachment[BUFFER_STENCIL].Renderbuffer);
678
679 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
680 y = ctx->DrawBuffer->Height - y - height;
681 }
682
683 if(format != GL_DEPTH_STENCIL &&
684 util_format_get_component_bits(strb->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0)
685 usage = PIPE_TRANSFER_READ_WRITE;
686 else
687 usage = PIPE_TRANSFER_WRITE;
688
689 pt = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture, 0, 0, 0,
690 usage, x, y,
691 width, height);
692
693 stmap = pipe->transfer_map(pipe, pt);
694
695 pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels);
696 assert(pixels);
697
698 /* if width > MAX_WIDTH, have to process image in chunks */
699 skipPixels = 0;
700 while (skipPixels < width) {
701 const GLint spanX = skipPixels;
702 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
703 GLint row;
704 for (row = 0; row < height; row++) {
705 GLubyte sValues[MAX_WIDTH];
706 GLuint zValues[MAX_WIDTH];
707 GLenum destType = GL_UNSIGNED_BYTE;
708 const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels,
709 width, height,
710 format, type,
711 row, skipPixels);
712 _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues,
713 type, source, &clippedUnpack,
714 ctx->_ImageTransferState);
715
716 if (format == GL_DEPTH_STENCIL) {
717 _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues,
718 (1 << 24) - 1, type, source,
719 &clippedUnpack);
720 }
721
722 if (zoom) {
723 _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with "
724 "zoom not complete");
725 }
726
727 {
728 GLint spanY;
729
730 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
731 spanY = height - row - 1;
732 }
733 else {
734 spanY = row;
735 }
736
737 /* now pack the stencil (and Z) values in the dest format */
738 switch (pt->texture->format) {
739 case PIPE_FORMAT_S8_UNORM:
740 {
741 ubyte *dest = stmap + spanY * pt->stride + spanX;
742 assert(usage == PIPE_TRANSFER_WRITE);
743 memcpy(dest, sValues, spanWidth);
744 }
745 break;
746 case PIPE_FORMAT_Z24S8_UNORM:
747 if (format == GL_DEPTH_STENCIL) {
748 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
749 GLint k;
750 assert(usage == PIPE_TRANSFER_WRITE);
751 for (k = 0; k < spanWidth; k++) {
752 dest[k] = zValues[k] | (sValues[k] << 24);
753 }
754 }
755 else {
756 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
757 GLint k;
758 assert(usage == PIPE_TRANSFER_READ_WRITE);
759 for (k = 0; k < spanWidth; k++) {
760 dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24);
761 }
762 }
763 break;
764 case PIPE_FORMAT_S8Z24_UNORM:
765 if (format == GL_DEPTH_STENCIL) {
766 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
767 GLint k;
768 assert(usage == PIPE_TRANSFER_WRITE);
769 for (k = 0; k < spanWidth; k++) {
770 dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff);
771 }
772 }
773 else {
774 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
775 GLint k;
776 assert(usage == PIPE_TRANSFER_READ_WRITE);
777 for (k = 0; k < spanWidth; k++) {
778 dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff);
779 }
780 }
781 break;
782 default:
783 assert(0);
784 }
785 }
786 }
787 skipPixels += spanWidth;
788 }
789
790 _mesa_unmap_pbo_source(ctx, &clippedUnpack);
791
792 /* unmap the stencil buffer */
793 pipe->transfer_unmap(pipe, pt);
794 pipe->tex_transfer_destroy(pipe, pt);
795 }
796
797
798 /**
799 * Called via ctx->Driver.DrawPixels()
800 */
801 static void
802 st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
803 GLenum format, GLenum type,
804 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
805 {
806 void *driver_vp, *driver_fp;
807 struct st_context *st = st_context(ctx);
808 const GLfloat *color;
809
810 if (format == GL_STENCIL_INDEX ||
811 format == GL_DEPTH_STENCIL) {
812 draw_stencil_pixels(ctx, x, y, width, height, format, type,
813 unpack, pixels);
814 return;
815 }
816
817 /* Mesa state should be up to date by now */
818 assert(ctx->NewState == 0x0);
819
820 st_validate_state(st);
821
822 if (format == GL_DEPTH_COMPONENT) {
823 driver_fp = make_fragment_shader_z(st);
824 driver_vp = make_passthrough_vertex_shader(st, GL_TRUE);
825 color = ctx->Current.RasterColor;
826 }
827 else {
828 driver_fp = combined_drawpix_fragment_program(ctx);
829 driver_vp = make_passthrough_vertex_shader(st, GL_FALSE);
830 color = NULL;
831 }
832
833 /* draw with textured quad */
834 {
835 struct pipe_texture *pt
836 = make_texture(st, width, height, format, type, unpack, pixels);
837 if (pt) {
838 struct pipe_sampler_view *sv = st_sampler_view_from_texture(st->pipe, pt);
839
840 if (sv) {
841 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
842 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
843 sv,
844 driver_vp,
845 driver_fp,
846 color, GL_FALSE);
847 pipe_sampler_view_reference(&sv, NULL);
848 }
849 pipe_texture_reference(&pt, NULL);
850 }
851 }
852 }
853
854
855
856 static void
857 copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
858 GLsizei width, GLsizei height,
859 GLint dstx, GLint dsty)
860 {
861 struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
862 struct pipe_context *pipe = ctx->st->pipe;
863 enum pipe_transfer_usage usage;
864 struct pipe_transfer *ptDraw;
865 ubyte *drawMap;
866 ubyte *buffer;
867 int i;
868
869 buffer = malloc(width * height * sizeof(ubyte));
870 if (!buffer) {
871 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
872 return;
873 }
874
875 /* this will do stencil pixel transfer ops */
876 st_read_stencil_pixels(ctx, srcx, srcy, width, height,
877 GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
878 &ctx->DefaultPacking, buffer);
879
880 if(util_format_get_component_bits(rbDraw->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0)
881 usage = PIPE_TRANSFER_READ_WRITE;
882 else
883 usage = PIPE_TRANSFER_WRITE;
884
885 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
886 dsty = rbDraw->Base.Height - dsty - height;
887 }
888
889 ptDraw = st_cond_flush_get_tex_transfer(st_context(ctx),
890 rbDraw->texture, 0, 0, 0,
891 usage, dstx, dsty,
892 width, height);
893
894 assert(util_format_get_blockwidth(ptDraw->texture->format) == 1);
895 assert(util_format_get_blockheight(ptDraw->texture->format) == 1);
896
897 /* map the stencil buffer */
898 drawMap = pipe->transfer_map(pipe, ptDraw);
899
900 /* draw */
901 /* XXX PixelZoom not handled yet */
902 for (i = 0; i < height; i++) {
903 ubyte *dst;
904 const ubyte *src;
905 int y;
906
907 y = i;
908
909 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
910 y = height - y - 1;
911 }
912
913 dst = drawMap + y * ptDraw->stride;
914 src = buffer + i * width;
915
916 switch (ptDraw->texture->format) {
917 case PIPE_FORMAT_Z24S8_UNORM:
918 {
919 uint *dst4 = (uint *) dst;
920 int j;
921 assert(usage == PIPE_TRANSFER_READ_WRITE);
922 for (j = 0; j < width; j++) {
923 *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
924 dst4++;
925 }
926 }
927 break;
928 case PIPE_FORMAT_S8Z24_UNORM:
929 {
930 uint *dst4 = (uint *) dst;
931 int j;
932 assert(usage == PIPE_TRANSFER_READ_WRITE);
933 for (j = 0; j < width; j++) {
934 *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff);
935 dst4++;
936 }
937 }
938 break;
939 case PIPE_FORMAT_S8_UNORM:
940 assert(usage == PIPE_TRANSFER_WRITE);
941 memcpy(dst, src, width);
942 break;
943 default:
944 assert(0);
945 }
946 }
947
948 free(buffer);
949
950 /* unmap the stencil buffer */
951 pipe->transfer_unmap(pipe, ptDraw);
952 pipe->tex_transfer_destroy(pipe, ptDraw);
953 }
954
955
956 static void
957 st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
958 GLsizei width, GLsizei height,
959 GLint dstx, GLint dsty, GLenum type)
960 {
961 struct st_context *st = st_context(ctx);
962 struct pipe_context *pipe = st->pipe;
963 struct pipe_screen *screen = pipe->screen;
964 struct st_renderbuffer *rbRead;
965 void *driver_vp, *driver_fp;
966 struct pipe_texture *pt;
967 struct pipe_sampler_view *sv;
968 GLfloat *color;
969 enum pipe_format srcFormat, texFormat;
970 GLboolean invertTex = GL_FALSE;
971 GLint readX, readY, readW, readH;
972 struct gl_pixelstore_attrib unpack = ctx->DefaultPacking;
973
974 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
975
976 st_validate_state(st);
977
978 if (type == GL_STENCIL) {
979 /* can't use texturing to do stencil */
980 copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
981 return;
982 }
983
984 if (type == GL_COLOR) {
985 rbRead = st_get_color_read_renderbuffer(ctx);
986 color = NULL;
987 driver_fp = combined_drawpix_fragment_program(ctx);
988 driver_vp = make_passthrough_vertex_shader(st, GL_FALSE);
989 }
990 else {
991 assert(type == GL_DEPTH);
992 rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
993 color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
994 driver_fp = make_fragment_shader_z(st);
995 driver_vp = make_passthrough_vertex_shader(st, GL_TRUE);
996 }
997
998 srcFormat = rbRead->texture->format;
999
1000 if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D,
1001 PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
1002 texFormat = srcFormat;
1003 }
1004 else {
1005 /* srcFormat can't be used as a texture format */
1006 if (type == GL_DEPTH) {
1007 texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT,
1008 PIPE_TEXTURE_2D,
1009 PIPE_TEXTURE_USAGE_DEPTH_STENCIL);
1010 assert(texFormat != PIPE_FORMAT_NONE);
1011 }
1012 else {
1013 /* default color format */
1014 texFormat = st_choose_format(screen, GL_RGBA, PIPE_TEXTURE_2D,
1015 PIPE_TEXTURE_USAGE_SAMPLER);
1016 assert(texFormat != PIPE_FORMAT_NONE);
1017 }
1018 }
1019
1020 /* Invert src region if needed */
1021 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
1022 srcy = ctx->ReadBuffer->Height - srcy - height;
1023 invertTex = !invertTex;
1024 }
1025
1026 /* Clip the read region against the src buffer bounds.
1027 * We'll still allocate a temporary buffer/texture for the original
1028 * src region size but we'll only read the region which is on-screen.
1029 * This may mean that we draw garbage pixels into the dest region, but
1030 * that's expected.
1031 */
1032 readX = srcx;
1033 readY = srcy;
1034 readW = width;
1035 readH = height;
1036 _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &unpack);
1037 readW = MAX2(0, readW);
1038 readH = MAX2(0, readH);
1039
1040 /* alloc temporary texture */
1041 pt = alloc_texture(st, width, height, texFormat);
1042 if (!pt)
1043 return;
1044
1045 sv = st_sampler_view_from_texture(st->pipe, pt);
1046 if (!sv) {
1047 pipe_texture_reference(&pt, NULL);
1048 return;
1049 }
1050
1051 /* Make temporary texture which is a copy of the src region.
1052 */
1053 if (srcFormat == texFormat) {
1054 /* copy source framebuffer surface into mipmap/texture */
1055 struct pipe_surface *psRead = screen->get_tex_surface(screen,
1056 rbRead->texture, 0, 0, 0,
1057 PIPE_BUFFER_USAGE_GPU_READ);
1058 struct pipe_surface *psTex = screen->get_tex_surface(screen, pt, 0, 0, 0,
1059 PIPE_BUFFER_USAGE_GPU_WRITE );
1060 if (pipe->surface_copy) {
1061 pipe->surface_copy(pipe,
1062 psTex, /* dest surf */
1063 unpack.SkipPixels, unpack.SkipRows, /* dest pos */
1064 psRead, /* src surf */
1065 readX, readY, readW, readH); /* src region */
1066 } else {
1067 util_surface_copy(pipe, FALSE,
1068 psTex,
1069 unpack.SkipPixels, unpack.SkipRows,
1070 psRead,
1071 readX, readY, readW, readH);
1072 }
1073
1074 if (0) {
1075 /* debug */
1076 debug_dump_surface(pipe, "copypixsrcsurf", psRead);
1077 debug_dump_surface(pipe, "copypixtemptex", psTex);
1078 }
1079
1080 pipe_surface_reference(&psRead, NULL);
1081 pipe_surface_reference(&psTex, NULL);
1082 }
1083 else {
1084 /* CPU-based fallback/conversion */
1085 struct pipe_transfer *ptRead =
1086 st_cond_flush_get_tex_transfer(st, rbRead->texture, 0, 0, 0,
1087 PIPE_TRANSFER_READ,
1088 readX, readY, readW, readH);
1089 struct pipe_transfer *ptTex;
1090 enum pipe_transfer_usage transfer_usage;
1091
1092 if (ST_DEBUG & DEBUG_FALLBACK)
1093 debug_printf("%s: fallback processing\n", __FUNCTION__);
1094
1095 if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format))
1096 transfer_usage = PIPE_TRANSFER_READ_WRITE;
1097 else
1098 transfer_usage = PIPE_TRANSFER_WRITE;
1099
1100 ptTex = st_cond_flush_get_tex_transfer(st, pt, 0, 0, 0, transfer_usage,
1101 0, 0, width, height);
1102
1103 /* copy image from ptRead surface to ptTex surface */
1104 if (type == GL_COLOR) {
1105 /* alternate path using get/put_tile() */
1106 GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
1107 pipe_get_tile_rgba(pipe, ptRead, readX, readY, readW, readH, buf);
1108 pipe_put_tile_rgba(pipe, ptTex, unpack.SkipPixels, unpack.SkipRows,
1109 readW, readH, buf);
1110 free(buf);
1111 }
1112 else {
1113 /* GL_DEPTH */
1114 GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint));
1115 pipe_get_tile_z(pipe, ptRead, readX, readY, readW, readH, buf);
1116 pipe_put_tile_z(pipe, ptTex, unpack.SkipPixels, unpack.SkipRows,
1117 readW, readH, buf);
1118 free(buf);
1119 }
1120
1121 pipe->tex_transfer_destroy(pipe, ptRead);
1122 pipe->tex_transfer_destroy(pipe, ptTex);
1123 }
1124
1125 /* OK, the texture 'pt' contains the src image/pixels. Now draw a
1126 * textured quad with that texture.
1127 */
1128 draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
1129 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
1130 sv,
1131 driver_vp,
1132 driver_fp,
1133 color, invertTex);
1134
1135 pipe_texture_reference(&pt, NULL);
1136 pipe_sampler_view_reference(&sv, NULL);
1137 }
1138
1139
1140
1141 void st_init_drawpixels_functions(struct dd_function_table *functions)
1142 {
1143 functions->DrawPixels = st_DrawPixels;
1144 functions->CopyPixels = st_CopyPixels;
1145 }
1146
1147
1148 void
1149 st_destroy_drawpix(struct st_context *st)
1150 {
1151 st_reference_fragprog(st, &st->drawpix.z_shader, NULL);
1152 st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
1153 if (st->drawpix.vert_shaders[0])
1154 free(st->drawpix.vert_shaders[0]);
1155 if (st->drawpix.vert_shaders[1])
1156 free(st->drawpix.vert_shaders[1]);
1157 }