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