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