st_cb_drawpixels.c revision f5c810c42f9dfcb660303ea898975b64f060b238
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 "program/program.h" 40#include "program/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 "program/prog_instruction.h" 62#include "cso_cache/cso_context.h" 63 64 65#if FEATURE_drawpix 66 67/** 68 * Check if the given program is: 69 * 0: MOVE result.color, fragment.color; 70 * 1: END; 71 */ 72static GLboolean 73is_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 */ 98static void * 99combined_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 */ 170static void * 171make_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 */ 237static void * 238make_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.attr[1]; */ 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.attr[2]; */ 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 */ 279static GLenum 280base_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 */ 300static struct pipe_resource * 301alloc_texture(struct st_context *st, GLsizei width, GLsizei height, 302 enum pipe_format texFormat) 303{ 304 struct pipe_resource *pt; 305 306 pt = st_texture_create(st, st->internal_target, texFormat, 0, 307 width, height, 1, PIPE_BIND_SAMPLER_VIEW); 308 309 return pt; 310} 311 312 313/** 314 * Make texture containing an image for glDrawPixels image. 315 * If 'pixels' is NULL, leave the texture image data undefined. 316 */ 317static struct pipe_resource * 318make_texture(struct st_context *st, 319 GLsizei width, GLsizei height, GLenum format, GLenum type, 320 const struct gl_pixelstore_attrib *unpack, 321 const GLvoid *pixels) 322{ 323 GLcontext *ctx = st->ctx; 324 struct pipe_context *pipe = st->pipe; 325 gl_format mformat; 326 struct pipe_resource *pt; 327 enum pipe_format pipeFormat; 328 GLuint cpp; 329 GLenum baseFormat; 330 331 baseFormat = base_format(format); 332 333 mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type); 334 assert(mformat); 335 336 pipeFormat = st_mesa_format_to_pipe_format(mformat); 337 assert(pipeFormat); 338 cpp = util_format_get_blocksize(pipeFormat); 339 340 pixels = _mesa_map_pbo_source(ctx, unpack, pixels); 341 if (!pixels) 342 return NULL; 343 344 /* alloc temporary texture */ 345 pt = alloc_texture(st, width, height, pipeFormat); 346 if (!pt) { 347 _mesa_unmap_pbo_source(ctx, unpack); 348 return NULL; 349 } 350 351 { 352 struct pipe_transfer *transfer; 353 static const GLuint dstImageOffsets = 0; 354 GLboolean success; 355 GLubyte *dest; 356 const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; 357 358 /* we'll do pixel transfer in a fragment shader */ 359 ctx->_ImageTransferState = 0x0; 360 361 transfer = pipe_get_transfer(st->pipe, pt, 0, 0, 0, 362 PIPE_TRANSFER_WRITE, 0, 0, 363 width, height); 364 365 /* map texture transfer */ 366 dest = pipe_transfer_map(pipe, transfer); 367 368 369 /* Put image into texture transfer. 370 * Note that the image is actually going to be upside down in 371 * the texture. We deal with that with texcoords. 372 */ 373 success = _mesa_texstore(ctx, 2, /* dims */ 374 baseFormat, /* baseInternalFormat */ 375 mformat, /* gl_format */ 376 dest, /* dest */ 377 0, 0, 0, /* dstX/Y/Zoffset */ 378 transfer->stride, /* dstRowStride, bytes */ 379 &dstImageOffsets, /* dstImageOffsets */ 380 width, height, 1, /* size */ 381 format, type, /* src format/type */ 382 pixels, /* data source */ 383 unpack); 384 385 /* unmap */ 386 pipe_transfer_unmap(pipe, transfer); 387 pipe->transfer_destroy(pipe, transfer); 388 389 assert(success); 390 391 /* restore */ 392 ctx->_ImageTransferState = imageTransferStateSave; 393 } 394 395 _mesa_unmap_pbo_source(ctx, unpack); 396 397 return pt; 398} 399 400 401/** 402 * Draw quad with texcoords and optional color. 403 * Coords are gallium window coords with y=0=top. 404 * \param color may be null 405 * \param invertTex if true, flip texcoords vertically 406 */ 407static void 408draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, 409 GLfloat x1, GLfloat y1, const GLfloat *color, 410 GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) 411{ 412 struct st_context *st = st_context(ctx); 413 struct pipe_context *pipe = st->pipe; 414 GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ 415 416 /* setup vertex data */ 417 { 418 const struct gl_framebuffer *fb = st->ctx->DrawBuffer; 419 const GLfloat fb_width = (GLfloat) fb->Width; 420 const GLfloat fb_height = (GLfloat) fb->Height; 421 const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; 422 const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; 423 const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; 424 const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; 425 const GLfloat sLeft = 0.0f, sRight = maxXcoord; 426 const GLfloat tTop = invertTex ? maxYcoord : 0.0f; 427 const GLfloat tBot = invertTex ? 0.0f : maxYcoord; 428 GLuint i; 429 430 /* upper-left */ 431 verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ 432 verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ 433 434 /* upper-right */ 435 verts[1][0][0] = clip_x1; 436 verts[1][0][1] = clip_y0; 437 438 /* lower-right */ 439 verts[2][0][0] = clip_x1; 440 verts[2][0][1] = clip_y1; 441 442 /* lower-left */ 443 verts[3][0][0] = clip_x0; 444 verts[3][0][1] = clip_y1; 445 446 verts[0][1][0] = sLeft; /* v[0].attr[1].S */ 447 verts[0][1][1] = tTop; /* v[0].attr[1].T */ 448 verts[1][1][0] = sRight; 449 verts[1][1][1] = tTop; 450 verts[2][1][0] = sRight; 451 verts[2][1][1] = tBot; 452 verts[3][1][0] = sLeft; 453 verts[3][1][1] = tBot; 454 455 /* same for all verts: */ 456 if (color) { 457 for (i = 0; i < 4; i++) { 458 verts[i][0][2] = z; /* v[i].attr[0].z */ 459 verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ 460 verts[i][2][0] = color[0]; /* v[i].attr[2].r */ 461 verts[i][2][1] = color[1]; /* v[i].attr[2].g */ 462 verts[i][2][2] = color[2]; /* v[i].attr[2].b */ 463 verts[i][2][3] = color[3]; /* v[i].attr[2].a */ 464 verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ 465 verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ 466 } 467 } 468 else { 469 for (i = 0; i < 4; i++) { 470 verts[i][0][2] = z; /*Z*/ 471 verts[i][0][3] = 1.0f; /*W*/ 472 verts[i][1][2] = 0.0f; /*R*/ 473 verts[i][1][3] = 1.0f; /*Q*/ 474 } 475 } 476 } 477 478 { 479 struct pipe_resource *buf; 480 481 /* allocate/load buffer object with vertex data */ 482 buf = pipe_buffer_create(pipe->screen, 483 PIPE_BIND_VERTEX_BUFFER, 484 sizeof(verts)); 485 pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); 486 487 util_draw_vertex_buffer(pipe, buf, 0, 488 PIPE_PRIM_QUADS, 489 4, /* verts */ 490 3); /* attribs/vert */ 491 pipe_resource_reference(&buf, NULL); 492 } 493} 494 495 496 497static void 498draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, 499 GLsizei width, GLsizei height, 500 GLfloat zoomX, GLfloat zoomY, 501 struct pipe_sampler_view *sv, 502 void *driver_vp, 503 void *driver_fp, 504 const GLfloat *color, 505 GLboolean invertTex) 506{ 507 struct st_context *st = st_context(ctx); 508 struct pipe_context *pipe = st->pipe; 509 struct cso_context *cso = st->cso_context; 510 GLfloat x0, y0, x1, y1; 511 GLsizei maxSize; 512 boolean normalized = sv->texture->target != PIPE_TEXTURE_RECT; 513 514 /* limit checks */ 515 /* XXX if DrawPixels image is larger than max texture size, break 516 * it up into chunks. 517 */ 518 maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); 519 assert(width <= maxSize); 520 assert(height <= maxSize); 521 522 cso_save_rasterizer(cso); 523 cso_save_viewport(cso); 524 cso_save_samplers(cso); 525 cso_save_fragment_sampler_views(cso); 526 cso_save_fragment_shader(cso); 527 cso_save_vertex_shader(cso); 528 cso_save_vertex_elements(cso); 529 530 /* rasterizer state: just scissor */ 531 { 532 struct pipe_rasterizer_state rasterizer; 533 memset(&rasterizer, 0, sizeof(rasterizer)); 534 rasterizer.gl_rasterization_rules = 1; 535 rasterizer.scissor = ctx->Scissor.Enabled; 536 cso_set_rasterizer(cso, &rasterizer); 537 } 538 539 /* fragment shader state: TEX lookup program */ 540 cso_set_fragment_shader_handle(cso, driver_fp); 541 542 /* vertex shader state: position + texcoord pass-through */ 543 cso_set_vertex_shader_handle(cso, driver_vp); 544 545 546 /* texture sampling state: */ 547 { 548 struct pipe_sampler_state sampler; 549 memset(&sampler, 0, sizeof(sampler)); 550 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; 551 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; 552 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; 553 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; 554 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 555 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 556 sampler.normalized_coords = normalized; 557 558 cso_single_sampler(cso, 0, &sampler); 559 if (st->pixel_xfer.pixelmap_enabled) { 560 cso_single_sampler(cso, 1, &sampler); 561 } 562 cso_single_sampler_done(cso); 563 } 564 565 /* viewport state: viewport matching window dims */ 566 { 567 const float w = (float) ctx->DrawBuffer->Width; 568 const float h = (float) ctx->DrawBuffer->Height; 569 struct pipe_viewport_state vp; 570 vp.scale[0] = 0.5f * w; 571 vp.scale[1] = -0.5f * h; 572 vp.scale[2] = 0.5f; 573 vp.scale[3] = 1.0f; 574 vp.translate[0] = 0.5f * w; 575 vp.translate[1] = 0.5f * h; 576 vp.translate[2] = 0.5f; 577 vp.translate[3] = 0.0f; 578 cso_set_viewport(cso, &vp); 579 } 580 581 cso_set_vertex_elements(cso, 3, st->velems_util_draw); 582 583 /* texture state: */ 584 if (st->pixel_xfer.pixelmap_enabled) { 585 struct pipe_sampler_view *sampler_views[2]; 586 sampler_views[0] = sv; 587 sampler_views[1] = st->pixel_xfer.pixelmap_sampler_view; 588 cso_set_fragment_sampler_views(cso, 2, sampler_views); 589 } 590 else { 591 cso_set_fragment_sampler_views(cso, 1, &sv); 592 } 593 594 /* Compute Gallium window coords (y=0=top) with pixel zoom. 595 * Recall that these coords are transformed by the current 596 * vertex shader and viewport transformation. 597 */ 598 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { 599 y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); 600 invertTex = !invertTex; 601 } 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 /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ 609 z = z * 2.0 - 1.0; 610 611 draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, 612 normalized ? ((GLfloat) width / sv->texture->width0) : (GLfloat)width, 613 normalized ? ((GLfloat) height / sv->texture->height0) : (GLfloat)height); 614 615 /* restore state */ 616 cso_restore_rasterizer(cso); 617 cso_restore_viewport(cso); 618 cso_restore_samplers(cso); 619 cso_restore_fragment_sampler_views(cso); 620 cso_restore_fragment_shader(cso); 621 cso_restore_vertex_shader(cso); 622 cso_restore_vertex_elements(cso); 623} 624 625 626static void 627draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, 628 GLsizei width, GLsizei height, GLenum format, GLenum type, 629 const struct gl_pixelstore_attrib *unpack, 630 const GLvoid *pixels) 631{ 632 struct st_context *st = st_context(ctx); 633 struct pipe_context *pipe = st->pipe; 634 struct st_renderbuffer *strb; 635 enum pipe_transfer_usage usage; 636 struct pipe_transfer *pt; 637 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; 638 GLint skipPixels; 639 ubyte *stmap; 640 struct gl_pixelstore_attrib clippedUnpack = *unpack; 641 642 if (!zoom) { 643 if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, 644 &clippedUnpack)) { 645 /* totally clipped */ 646 return; 647 } 648 } 649 650 strb = st_renderbuffer(ctx->DrawBuffer-> 651 Attachment[BUFFER_STENCIL].Renderbuffer); 652 653 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 654 y = ctx->DrawBuffer->Height - y - height; 655 } 656 657 if(format != GL_DEPTH_STENCIL && 658 util_format_get_component_bits(strb->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) 659 usage = PIPE_TRANSFER_READ_WRITE; 660 else 661 usage = PIPE_TRANSFER_WRITE; 662 663 pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0, 0, 664 usage, x, y, 665 width, height); 666 667 stmap = pipe_transfer_map(pipe, pt); 668 669 pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); 670 assert(pixels); 671 672 /* if width > MAX_WIDTH, have to process image in chunks */ 673 skipPixels = 0; 674 while (skipPixels < width) { 675 const GLint spanX = skipPixels; 676 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); 677 GLint row; 678 for (row = 0; row < height; row++) { 679 GLubyte sValues[MAX_WIDTH]; 680 GLuint zValues[MAX_WIDTH]; 681 GLenum destType = GL_UNSIGNED_BYTE; 682 const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, 683 width, height, 684 format, type, 685 row, skipPixels); 686 _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, 687 type, source, &clippedUnpack, 688 ctx->_ImageTransferState); 689 690 if (format == GL_DEPTH_STENCIL) { 691 _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, 692 (1 << 24) - 1, type, source, 693 &clippedUnpack); 694 } 695 696 if (zoom) { 697 _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " 698 "zoom not complete"); 699 } 700 701 { 702 GLint spanY; 703 704 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 705 spanY = height - row - 1; 706 } 707 else { 708 spanY = row; 709 } 710 711 /* now pack the stencil (and Z) values in the dest format */ 712 switch (pt->resource->format) { 713 case PIPE_FORMAT_S8_USCALED: 714 { 715 ubyte *dest = stmap + spanY * pt->stride + spanX; 716 assert(usage == PIPE_TRANSFER_WRITE); 717 memcpy(dest, sValues, spanWidth); 718 } 719 break; 720 case PIPE_FORMAT_Z24_UNORM_S8_USCALED: 721 if (format == GL_DEPTH_STENCIL) { 722 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); 723 GLint k; 724 assert(usage == PIPE_TRANSFER_WRITE); 725 for (k = 0; k < spanWidth; k++) { 726 dest[k] = zValues[k] | (sValues[k] << 24); 727 } 728 } 729 else { 730 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); 731 GLint k; 732 assert(usage == PIPE_TRANSFER_READ_WRITE); 733 for (k = 0; k < spanWidth; k++) { 734 dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); 735 } 736 } 737 break; 738 case PIPE_FORMAT_S8_USCALED_Z24_UNORM: 739 if (format == GL_DEPTH_STENCIL) { 740 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); 741 GLint k; 742 assert(usage == PIPE_TRANSFER_WRITE); 743 for (k = 0; k < spanWidth; k++) { 744 dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); 745 } 746 } 747 else { 748 uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); 749 GLint k; 750 assert(usage == PIPE_TRANSFER_READ_WRITE); 751 for (k = 0; k < spanWidth; k++) { 752 dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); 753 } 754 } 755 break; 756 default: 757 assert(0); 758 } 759 } 760 } 761 skipPixels += spanWidth; 762 } 763 764 _mesa_unmap_pbo_source(ctx, &clippedUnpack); 765 766 /* unmap the stencil buffer */ 767 pipe_transfer_unmap(pipe, pt); 768 pipe->transfer_destroy(pipe, pt); 769} 770 771 772/** 773 * Called via ctx->Driver.DrawPixels() 774 */ 775static void 776st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, 777 GLenum format, GLenum type, 778 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) 779{ 780 void *driver_vp, *driver_fp; 781 struct st_context *st = st_context(ctx); 782 const GLfloat *color; 783 784 if (format == GL_STENCIL_INDEX || 785 format == GL_DEPTH_STENCIL) { 786 draw_stencil_pixels(ctx, x, y, width, height, format, type, 787 unpack, pixels); 788 return; 789 } 790 791 /* Mesa state should be up to date by now */ 792 assert(ctx->NewState == 0x0); 793 794 st_validate_state(st); 795 796 if (format == GL_DEPTH_COMPONENT) { 797 driver_fp = make_fragment_shader_z(st); 798 driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); 799 color = ctx->Current.RasterColor; 800 } 801 else { 802 driver_fp = combined_drawpix_fragment_program(ctx); 803 driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); 804 color = NULL; 805 } 806 807 /* draw with textured quad */ 808 { 809 struct pipe_resource *pt 810 = make_texture(st, width, height, format, type, unpack, pixels); 811 if (pt) { 812 struct pipe_sampler_view *sv = st_create_texture_sampler_view(st->pipe, pt); 813 814 if (sv) { 815 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], 816 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, 817 sv, 818 driver_vp, 819 driver_fp, 820 color, GL_FALSE); 821 pipe_sampler_view_reference(&sv, NULL); 822 } 823 pipe_resource_reference(&pt, NULL); 824 } 825 } 826} 827 828 829 830static void 831copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 832 GLsizei width, GLsizei height, 833 GLint dstx, GLint dsty) 834{ 835 struct st_renderbuffer *rbDraw; 836 struct pipe_context *pipe = st_context(ctx)->pipe; 837 enum pipe_transfer_usage usage; 838 struct pipe_transfer *ptDraw; 839 ubyte *drawMap; 840 ubyte *buffer; 841 int i; 842 843 buffer = malloc(width * height * sizeof(ubyte)); 844 if (!buffer) { 845 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); 846 return; 847 } 848 849 /* Get the dest renderbuffer. If there's a wrapper, use the 850 * underlying renderbuffer. 851 */ 852 rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); 853 if (rbDraw->Base.Wrapped) 854 rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); 855 856 /* this will do stencil pixel transfer ops */ 857 st_read_stencil_pixels(ctx, srcx, srcy, width, height, 858 GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 859 &ctx->DefaultPacking, buffer); 860 861 if(util_format_get_component_bits(rbDraw->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) 862 usage = PIPE_TRANSFER_READ_WRITE; 863 else 864 usage = PIPE_TRANSFER_WRITE; 865 866 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 867 dsty = rbDraw->Base.Height - dsty - height; 868 } 869 870 ptDraw = pipe_get_transfer(st_context(ctx)->pipe, 871 rbDraw->texture, 0, 0, 0, 872 usage, dstx, dsty, 873 width, height); 874 875 assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); 876 assert(util_format_get_blockheight(ptDraw->resource->format) == 1); 877 878 /* map the stencil buffer */ 879 drawMap = pipe_transfer_map(pipe, ptDraw); 880 881 /* draw */ 882 /* XXX PixelZoom not handled yet */ 883 for (i = 0; i < height; i++) { 884 ubyte *dst; 885 const ubyte *src; 886 int y; 887 888 y = i; 889 890 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 891 y = height - y - 1; 892 } 893 894 dst = drawMap + y * ptDraw->stride; 895 src = buffer + i * width; 896 897 switch (ptDraw->resource->format) { 898 case PIPE_FORMAT_Z24_UNORM_S8_USCALED: 899 { 900 uint *dst4 = (uint *) dst; 901 int j; 902 assert(usage == PIPE_TRANSFER_READ_WRITE); 903 for (j = 0; j < width; j++) { 904 *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); 905 dst4++; 906 } 907 } 908 break; 909 case PIPE_FORMAT_S8_USCALED_Z24_UNORM: 910 { 911 uint *dst4 = (uint *) dst; 912 int j; 913 assert(usage == PIPE_TRANSFER_READ_WRITE); 914 for (j = 0; j < width; j++) { 915 *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); 916 dst4++; 917 } 918 } 919 break; 920 case PIPE_FORMAT_S8_USCALED: 921 assert(usage == PIPE_TRANSFER_WRITE); 922 memcpy(dst, src, width); 923 break; 924 default: 925 assert(0); 926 } 927 } 928 929 free(buffer); 930 931 /* unmap the stencil buffer */ 932 pipe_transfer_unmap(pipe, ptDraw); 933 pipe->transfer_destroy(pipe, ptDraw); 934} 935 936 937static void 938st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, 939 GLsizei width, GLsizei height, 940 GLint dstx, GLint dsty, GLenum type) 941{ 942 struct st_context *st = st_context(ctx); 943 struct pipe_context *pipe = st->pipe; 944 struct pipe_screen *screen = pipe->screen; 945 struct st_renderbuffer *rbRead; 946 void *driver_vp, *driver_fp; 947 struct pipe_resource *pt; 948 struct pipe_sampler_view *sv; 949 GLfloat *color; 950 enum pipe_format srcFormat, texFormat; 951 GLboolean invertTex = GL_FALSE; 952 GLint readX, readY, readW, readH; 953 GLuint sample_count; 954 struct gl_pixelstore_attrib pack = ctx->DefaultPacking; 955 956 st_validate_state(st); 957 958 if (type == GL_STENCIL) { 959 /* can't use texturing to do stencil */ 960 copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); 961 return; 962 } 963 964 if (type == GL_COLOR) { 965 rbRead = st_get_color_read_renderbuffer(ctx); 966 color = NULL; 967 driver_fp = combined_drawpix_fragment_program(ctx); 968 driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); 969 } 970 else { 971 assert(type == GL_DEPTH); 972 rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); 973 color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; 974 driver_fp = make_fragment_shader_z(st); 975 driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); 976 } 977 978 if (rbRead->Base.Wrapped) 979 rbRead = st_renderbuffer(rbRead->Base.Wrapped); 980 981 sample_count = rbRead->texture->nr_samples; 982 /* I believe this would be legal, presumably would need to do a resolve 983 for color, and for depth/stencil spec says to just use one of the 984 depth/stencil samples per pixel? Need some transfer clarifications. */ 985 assert(sample_count < 2); 986 987 srcFormat = rbRead->texture->format; 988 989 if (screen->is_format_supported(screen, srcFormat, st->internal_target, sample_count, 990 PIPE_BIND_SAMPLER_VIEW, 0)) { 991 texFormat = srcFormat; 992 } 993 else { 994 /* srcFormat can't be used as a texture format */ 995 if (type == GL_DEPTH) { 996 texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, 997 st->internal_target, sample_count, 998 PIPE_BIND_DEPTH_STENCIL); 999 assert(texFormat != PIPE_FORMAT_NONE); 1000 } 1001 else { 1002 /* default color format */ 1003 texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, 1004 sample_count, PIPE_BIND_SAMPLER_VIEW); 1005 assert(texFormat != PIPE_FORMAT_NONE); 1006 } 1007 } 1008 1009 /* Invert src region if needed */ 1010 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { 1011 srcy = ctx->ReadBuffer->Height - srcy - height; 1012 invertTex = !invertTex; 1013 } 1014 1015 /* Clip the read region against the src buffer bounds. 1016 * We'll still allocate a temporary buffer/texture for the original 1017 * src region size but we'll only read the region which is on-screen. 1018 * This may mean that we draw garbage pixels into the dest region, but 1019 * that's expected. 1020 */ 1021 readX = srcx; 1022 readY = srcy; 1023 readW = width; 1024 readH = height; 1025 _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); 1026 readW = MAX2(0, readW); 1027 readH = MAX2(0, readH); 1028 1029 /* alloc temporary texture */ 1030 pt = alloc_texture(st, width, height, texFormat); 1031 if (!pt) 1032 return; 1033 1034 sv = st_create_texture_sampler_view(st->pipe, pt); 1035 if (!sv) { 1036 pipe_resource_reference(&pt, NULL); 1037 return; 1038 } 1039 1040 /* Make temporary texture which is a copy of the src region. 1041 */ 1042 if (srcFormat == texFormat) { 1043 struct pipe_subresource srcsub, dstsub; 1044 srcsub.face = 0; 1045 srcsub.level = 0; 1046 dstsub.face = 0; 1047 dstsub.level = 0; 1048 /* copy source framebuffer surface into mipmap/texture */ 1049 pipe->resource_copy_region(pipe, 1050 pt, /* dest tex */ 1051 dstsub, 1052 pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ 1053 rbRead->texture, /* src tex */ 1054 srcsub, 1055 readX, readY, 0, readW, readH); /* src region */ 1056 1057 } 1058 else { 1059 /* CPU-based fallback/conversion */ 1060 struct pipe_transfer *ptRead = 1061 pipe_get_transfer(st->pipe, rbRead->texture, 0, 0, 0, 1062 PIPE_TRANSFER_READ, 1063 readX, readY, readW, readH); 1064 struct pipe_transfer *ptTex; 1065 enum pipe_transfer_usage transfer_usage; 1066 1067 if (ST_DEBUG & DEBUG_FALLBACK) 1068 debug_printf("%s: fallback processing\n", __FUNCTION__); 1069 1070 if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) 1071 transfer_usage = PIPE_TRANSFER_READ_WRITE; 1072 else 1073 transfer_usage = PIPE_TRANSFER_WRITE; 1074 1075 ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, 0, transfer_usage, 1076 0, 0, width, height); 1077 1078 /* copy image from ptRead surface to ptTex surface */ 1079 if (type == GL_COLOR) { 1080 /* alternate path using get/put_tile() */ 1081 GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); 1082 pipe_get_tile_rgba(pipe, ptRead, readX, readY, readW, readH, buf); 1083 pipe_put_tile_rgba(pipe, ptTex, pack.SkipPixels, pack.SkipRows, 1084 readW, readH, buf); 1085 free(buf); 1086 } 1087 else { 1088 /* GL_DEPTH */ 1089 GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); 1090 pipe_get_tile_z(pipe, ptRead, readX, readY, readW, readH, buf); 1091 pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, 1092 readW, readH, buf); 1093 free(buf); 1094 } 1095 1096 pipe->transfer_destroy(pipe, ptRead); 1097 pipe->transfer_destroy(pipe, ptTex); 1098 } 1099 1100 /* OK, the texture 'pt' contains the src image/pixels. Now draw a 1101 * textured quad with that texture. 1102 */ 1103 draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], 1104 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, 1105 sv, 1106 driver_vp, 1107 driver_fp, 1108 color, invertTex); 1109 1110 pipe_resource_reference(&pt, NULL); 1111 pipe_sampler_view_reference(&sv, NULL); 1112} 1113 1114 1115 1116void st_init_drawpixels_functions(struct dd_function_table *functions) 1117{ 1118 functions->DrawPixels = st_DrawPixels; 1119 functions->CopyPixels = st_CopyPixels; 1120} 1121 1122 1123void 1124st_destroy_drawpix(struct st_context *st) 1125{ 1126 st_reference_fragprog(st, &st->drawpix.z_shader, NULL); 1127 st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); 1128 if (st->drawpix.vert_shaders[0]) 1129 ureg_free_tokens(st->drawpix.vert_shaders[0]); 1130 if (st->drawpix.vert_shaders[1]) 1131 ureg_free_tokens(st->drawpix.vert_shaders[1]); 1132} 1133 1134#endif /* FEATURE_drawpix */ 1135