st_cb_drawpixels.c revision e3f3e22cf7e9af4c5416d37329b7b8ee50f0cfcb
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 "shader/program.h" 39#include "shader/prog_parameter.h" 40#include "shader/prog_print.h" 41 42#include "st_context.h" 43#include "st_atom.h" 44#include "st_atom_constbuf.h" 45#include "st_draw.h" 46#include "st_program.h" 47#include "st_cb_drawpixels.h" 48#include "st_cb_readpixels.h" 49#include "st_cb_fbo.h" 50#include "st_cb_texture.h" 51#include "st_draw.h" 52#include "st_format.h" 53#include "st_mesa_to_tgsi.h" 54#include "st_texture.h" 55#include "pipe/p_context.h" 56#include "pipe/p_defines.h" 57#include "pipe/p_inlines.h" 58#include "util/p_tile.h" 59#include "util/u_draw_quad.h" 60#include "shader/prog_instruction.h" 61#include "cso_cache/cso_context.h" 62 63 64/** 65 * Check if the given program is: 66 * 0: MOVE result.color, fragment.color; 67 * 1: END; 68 */ 69static GLboolean 70is_passthrough_program(const struct gl_fragment_program *prog) 71{ 72 if (prog->Base.NumInstructions == 2) { 73 const struct prog_instruction *inst = prog->Base.Instructions; 74 if (inst[0].Opcode == OPCODE_MOV && 75 inst[1].Opcode == OPCODE_END && 76 inst[0].DstReg.File == PROGRAM_OUTPUT && 77 inst[0].DstReg.Index == FRAG_RESULT_COLR && 78 inst[0].DstReg.WriteMask == WRITEMASK_XYZW && 79 inst[0].SrcReg[0].File == PROGRAM_INPUT && 80 inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && 81 inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { 82 return GL_TRUE; 83 } 84 } 85 return GL_FALSE; 86} 87 88 89 90/** 91 * Make fragment shader for glDraw/CopyPixels. This shader is made 92 * by combining the pixel transfer shader with the user-defined shader. 93 */ 94static struct st_fragment_program * 95combined_drawpix_fragment_program(GLcontext *ctx) 96{ 97 struct st_context *st = ctx->st; 98 struct st_fragment_program *stfp; 99 100 if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn 101 && st->fp->serialNo == st->pixel_xfer.user_prog_sn) { 102 /* the pixel tranfer program has not changed and the user-defined 103 * program has not changed, so re-use the combined program. 104 */ 105 stfp = st->pixel_xfer.combined_prog; 106 } 107 else { 108 /* Concatenate the pixel transfer program with the current user- 109 * defined program. 110 */ 111 if (is_passthrough_program(&st->fp->Base)) { 112 stfp = (struct st_fragment_program *) 113 _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base); 114 } 115 else { 116#if 0 117 printf("Base program:\n"); 118 _mesa_print_program(&st->fp->Base.Base); 119 printf("DrawPix program:\n"); 120 _mesa_print_program(&st->pixel_xfer.program->Base.Base); 121#endif 122 stfp = (struct st_fragment_program *) 123 _mesa_combine_programs(ctx, 124 &st->pixel_xfer.program->Base.Base, 125 &st->fp->Base.Base); 126 } 127 128#if 0 129 { 130 struct gl_program *p = &stfp->Base.Base; 131 printf("Combined DrawPixels program:\n"); 132 _mesa_print_program(p); 133 printf("InputsRead: 0x%x\n", p->InputsRead); 134 printf("OutputsWritten: 0x%x\n", p->OutputsWritten); 135 _mesa_print_parameter_list(p->Parameters); 136 } 137#endif 138 139 /* translate to TGSI tokens */ 140 st_translate_fragment_program(st, stfp, NULL); 141 142 /* save new program, update serial numbers */ 143 st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo; 144 st->pixel_xfer.user_prog_sn = st->fp->serialNo; 145 st->pixel_xfer.combined_prog_sn = stfp->serialNo; 146 st->pixel_xfer.combined_prog = stfp; 147 } 148 149 /* Ideally we'd have updated the pipe constants during the normal 150 * st/atom mechanism. But we can't since this is specific to glDrawPixels. 151 */ 152 st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT); 153 154 return stfp; 155} 156 157 158/** 159 * Create fragment shader that does a TEX() instruction to get a Z 160 * value, then writes to FRAG_RESULT_DEPR. 161 * Pass fragment color through as-is. 162 */ 163static struct st_fragment_program * 164make_fragment_shader_z(struct st_context *st) 165{ 166 GLcontext *ctx = st->ctx; 167 struct gl_program *p; 168 GLuint ic = 0; 169 170 if (st->drawpix.z_shader) { 171 return st->drawpix.z_shader; 172 } 173 174 /* 175 * Create shader now 176 */ 177 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); 178 if (!p) 179 return NULL; 180 181 p->NumInstructions = 3; 182 183 p->Instructions = _mesa_alloc_instructions(p->NumInstructions); 184 if (!p->Instructions) { 185 ctx->Driver.DeleteProgram(ctx, p); 186 return NULL; 187 } 188 _mesa_init_instructions(p->Instructions, p->NumInstructions); 189 190 /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ 191 p->Instructions[ic].Opcode = OPCODE_TEX; 192 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; 193 p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR; 194 p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; 195 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; 196 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; 197 p->Instructions[ic].TexSrcUnit = 0; 198 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; 199 ic++; 200 201 /* MOV result.color, fragment.color */ 202 p->Instructions[ic].Opcode = OPCODE_MOV; 203 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; 204 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR; 205 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; 206 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0; 207 ic++; 208 209 /* END; */ 210 p->Instructions[ic++].Opcode = OPCODE_END; 211 212 assert(ic == p->NumInstructions); 213 214 p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; 215 p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR); 216 p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ 217 218 st->drawpix.z_shader = (struct st_fragment_program *) p; 219 st_translate_fragment_program(st, st->drawpix.z_shader, NULL); 220 221 return st->drawpix.z_shader; 222} 223 224 225 226/** 227 * Create a simple vertex shader that just passes through the 228 * vertex position and texcoord (and optionally, color). 229 */ 230static struct st_vertex_program * 231st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor) 232{ 233 GLcontext *ctx = st->ctx; 234 struct st_vertex_program *stvp; 235 struct gl_program *p; 236 GLuint ic = 0; 237 238 if (st->drawpix.vert_shaders[passColor]) 239 return st->drawpix.vert_shaders[passColor]; 240 241 /* 242 * Create shader now 243 */ 244 p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); 245 if (!p) 246 return NULL; 247 248 if (passColor) 249 p->NumInstructions = 4; 250 else 251 p->NumInstructions = 3; 252 253 p->Instructions = _mesa_alloc_instructions(p->NumInstructions); 254 if (!p->Instructions) { 255 ctx->Driver.DeleteProgram(ctx, p); 256 return NULL; 257 } 258 _mesa_init_instructions(p->Instructions, p->NumInstructions); 259 /* MOV result.pos, vertex.pos; */ 260 p->Instructions[0].Opcode = OPCODE_MOV; 261 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT; 262 p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS; 263 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT; 264 p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS; 265 /* MOV result.texcoord0, vertex.texcoord0; */ 266 p->Instructions[1].Opcode = OPCODE_MOV; 267 p->Instructions[1].DstReg.File = PROGRAM_OUTPUT; 268 p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0; 269 p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT; 270 p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0; 271 ic = 2; 272 if (passColor) { 273 /* MOV result.color0, vertex.color0; */ 274 p->Instructions[ic].Opcode = OPCODE_MOV; 275 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; 276 p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0; 277 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; 278 p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0; 279 ic++; 280 } 281 282 /* END; */ 283 p->Instructions[ic].Opcode = OPCODE_END; 284 ic++; 285 286 assert(ic == p->NumInstructions); 287 288 p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0; 289 p->OutputsWritten = ((1 << VERT_RESULT_TEX0) | 290 (1 << VERT_RESULT_HPOS)); 291 if (passColor) { 292 p->InputsRead |= VERT_BIT_COLOR0; 293 p->OutputsWritten |= (1 << VERT_RESULT_COL0); 294 } 295 296 stvp = (struct st_vertex_program *) p; 297 st_translate_vertex_program(st, stvp, NULL, NULL, NULL); 298 299 st->drawpix.vert_shaders[passColor] = stvp; 300 301 return stvp; 302} 303 304 305static GLenum 306_mesa_base_format(GLenum format) 307{ 308 switch (format) { 309 case GL_DEPTH_COMPONENT: 310 return GL_DEPTH_COMPONENT; 311 case GL_STENCIL_INDEX: 312 return GL_STENCIL_INDEX; 313 default: 314 return GL_RGBA; 315 } 316} 317 318 319/** 320 * Make texture containing an image for glDrawPixels image. 321 * If 'pixels' is NULL, leave the texture image data undefined. 322 */ 323static struct pipe_texture * 324make_texture(struct st_context *st, 325 GLsizei width, GLsizei height, GLenum format, GLenum type, 326 const struct gl_pixelstore_attrib *unpack, 327 const GLvoid *pixels) 328{ 329 GLcontext *ctx = st->ctx; 330 struct pipe_context *pipe = st->pipe; 331 struct pipe_screen *screen = pipe->screen; 332 const struct gl_texture_format *mformat; 333 struct pipe_texture *pt; 334 enum pipe_format pipeFormat; 335 GLuint cpp; 336 GLenum baseFormat; 337 338 baseFormat = _mesa_base_format(format); 339 340 mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type); 341 assert(mformat); 342 343 pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat); 344 assert(pipeFormat); 345 cpp = st_sizeof_format(pipeFormat); 346 347 pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels); 348 if (!pixels) 349 return NULL; 350 351 pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height, 352 1, 0, 353 PIPE_TEXTURE_USAGE_SAMPLER); 354 if (!pt) { 355 _mesa_unmap_drawpix_pbo(ctx, unpack); 356 return NULL; 357 } 358 359 { 360 struct pipe_surface *surface; 361 static const GLuint dstImageOffsets = 0; 362 GLboolean success; 363 GLubyte *dest; 364 const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; 365 366 /* we'll do pixel transfer in a fragment shader */ 367 ctx->_ImageTransferState = 0x0; 368 369 surface = screen->get_tex_surface(screen, pt, 0, 0, 0, 370 PIPE_BUFFER_USAGE_CPU_WRITE); 371 372 /* map texture surface */ 373 dest = screen->surface_map(screen, surface, 374 PIPE_BUFFER_USAGE_CPU_WRITE); 375 376 /* Put image into texture surface. 377 * Note that the image is actually going to be upside down in 378 * the texture. We deal with that with texcoords. 379 */ 380 success = mformat->StoreImage(ctx, 2, /* dims */ 381 baseFormat, /* baseInternalFormat */ 382 mformat, /* gl_texture_format */ 383 dest, /* dest */ 384 0, 0, 0, /* dstX/Y/Zoffset */ 385 surface->stride, /* dstRowStride, bytes */ 386 &dstImageOffsets, /* dstImageOffsets */ 387 width, height, 1, /* size */ 388 format, type, /* src format/type */ 389 pixels, /* data source */ 390 unpack); 391 392 /* unmap */ 393 screen->surface_unmap(screen, surface); 394 pipe_surface_reference(&surface, NULL); 395 396 assert(success); 397 398 /* restore */ 399 ctx->_ImageTransferState = imageTransferStateSave; 400 } 401 402 _mesa_unmap_drawpix_pbo(ctx, unpack); 403 404 return pt; 405} 406 407 408/** 409 * Draw quad with texcoords and optional color. 410 * Coords are window coords with y=0=bottom. 411 * \param color may be null 412 * \param invertTex if true, flip texcoords vertically 413 */ 414static void 415draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, 416 GLfloat x1, GLfloat y1, const GLfloat *color, 417 GLboolean invertTex) 418{ 419 struct st_context *st = ctx->st; 420 struct pipe_context *pipe = ctx->st->pipe; 421 GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ 422 423 /* setup vertex data */ 424 { 425 const struct gl_framebuffer *fb = st->ctx->DrawBuffer; 426 const GLfloat fb_width = (GLfloat) fb->Width; 427 const GLfloat fb_height = (GLfloat) fb->Height; 428 const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; 429 const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; 430 const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; 431 const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; 432 const GLfloat sLeft = 0.0f, sRight = 1.0f; 433 const GLfloat tTop = invertTex, tBot = 1.0f - tTop; 434 GLuint tex, i; 435 436 /* upper-left */ 437 verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ 438 verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ 439 440 /* upper-right */ 441 verts[1][0][0] = clip_x1; 442 verts[1][0][1] = clip_y0; 443 444 /* lower-right */ 445 verts[2][0][0] = clip_x1; 446 verts[2][0][1] = clip_y1; 447 448 /* lower-left */ 449 verts[3][0][0] = clip_x0; 450 verts[3][0][1] = clip_y1; 451 452 tex = color ? 2 : 1; 453 verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */ 454 verts[0][tex][1] = tTop; /* v[0].attr[tex].t */ 455 verts[1][tex][0] = sRight; 456 verts[1][tex][1] = tTop; 457 verts[2][tex][0] = sRight; 458 verts[2][tex][1] = tBot; 459 verts[3][tex][0] = sLeft; 460 verts[3][tex][1] = tBot; 461 462 /* same for all verts: */ 463 if (color) { 464 for (i = 0; i < 4; i++) { 465 verts[i][0][2] = z; /*Z*/ 466 verts[i][0][3] = 1.0f; /*W*/ 467 verts[i][1][0] = color[0]; 468 verts[i][1][1] = color[1]; 469 verts[i][1][2] = color[2]; 470 verts[i][1][3] = color[3]; 471 verts[i][2][2] = 0.0f; /*R*/ 472 verts[i][2][3] = 1.0f; /*Q*/ 473 } 474 } 475 else { 476 for (i = 0; i < 4; i++) { 477 verts[i][0][2] = z; /*Z*/ 478 verts[i][0][3] = 1.0f; /*W*/ 479 verts[i][1][2] = 0.0f; /*R*/ 480 verts[i][1][3] = 1.0f; /*Q*/ 481 } 482 } 483 } 484 485 { 486 struct pipe_buffer *buf; 487 ubyte *map; 488 489 /* allocate/load buffer object with vertex data */ 490 buf = pipe_buffer_create(pipe, 32, PIPE_BUFFER_USAGE_VERTEX, 491 sizeof(verts)); 492 map = pipe_buffer_map(pipe, buf, PIPE_BUFFER_USAGE_CPU_WRITE); 493 memcpy(map, verts, sizeof(verts)); 494 pipe_buffer_unmap(pipe, buf); 495 496 util_draw_vertex_buffer(pipe, buf, 497 PIPE_PRIM_QUADS, 498 4, /* verts */ 499 3); /* attribs/vert */ 500 pipe_buffer_reference(pipe->winsys, &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 //if(!color) 608 draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex); 609 //else 610 //printf("skip draw quad\n"); 611 /* restore state */ 612 cso_restore_rasterizer(cso); 613 cso_restore_viewport(cso); 614 cso_restore_samplers(cso); 615 cso_restore_sampler_textures(cso); 616 cso_restore_fragment_shader(cso); 617 cso_restore_vertex_shader(cso); 618} 619 620 621/** 622 * Check if a GL format/type combination is a match to the given pipe format. 623 * XXX probably move this to a re-usable place. 624 */ 625static GLboolean 626compatible_formats(GLenum format, GLenum type, enum pipe_format pipeFormat) 627{ 628 static const GLuint one = 1; 629 GLubyte littleEndian = *((GLubyte *) &one); 630 631 if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM && 632 format == GL_RGBA && 633 type == GL_UNSIGNED_BYTE && 634 !littleEndian) { 635 return GL_TRUE; 636 } 637 else if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM && 638 format == GL_ABGR_EXT && 639 type == GL_UNSIGNED_BYTE && 640 littleEndian) { 641 return GL_TRUE; 642 } 643 else if (pipeFormat == PIPE_FORMAT_A8R8G8B8_UNORM && 644 format == GL_BGRA && 645 type == GL_UNSIGNED_BYTE && 646 littleEndian) { 647 return GL_TRUE; 648 } 649 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM && 650 format == GL_RGB && 651 type == GL_UNSIGNED_SHORT_5_6_5) { 652 /* endian don't care */ 653 return GL_TRUE; 654 } 655 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM && 656 format == GL_BGR && 657 type == GL_UNSIGNED_SHORT_5_6_5_REV) { 658 /* endian don't care */ 659 return GL_TRUE; 660 } 661 else if (pipeFormat == PIPE_FORMAT_S8_UNORM && 662 format == GL_STENCIL_INDEX && 663 type == GL_UNSIGNED_BYTE) { 664 return GL_TRUE; 665 } 666 else if (pipeFormat == PIPE_FORMAT_Z32_UNORM && 667 format == GL_DEPTH_COMPONENT && 668 type == GL_UNSIGNED_INT) { 669 return GL_TRUE; 670 } 671 /* XXX add more cases */ 672 else { 673 return GL_FALSE; 674 } 675} 676 677 678/** 679 * Check if any per-fragment ops are enabled. 680 * XXX probably move this to a re-usable place. 681 */ 682static GLboolean 683any_fragment_ops(const struct st_context *st) 684{ 685 if (st->state.depth_stencil.alpha.enabled || 686 st->state.depth_stencil.depth.enabled || 687 st->state.blend.blend_enable || 688 st->state.blend.logicop_enable) 689 /* XXX more checks */ 690 return GL_TRUE; 691 else 692 return GL_FALSE; 693} 694 695 696/** 697 * Check if any pixel transfer ops are enabled. 698 * XXX probably move this to a re-usable place. 699 */ 700static GLboolean 701any_pixel_transfer_ops(const struct st_context *st) 702{ 703 if (st->ctx->Pixel.RedScale != 1.0 || 704 st->ctx->Pixel.RedBias != 0.0 || 705 st->ctx->Pixel.GreenScale != 1.0 || 706 st->ctx->Pixel.GreenBias != 0.0 || 707 st->ctx->Pixel.BlueScale != 1.0 || 708 st->ctx->Pixel.BlueBias != 0.0 || 709 st->ctx->Pixel.AlphaScale != 1.0 || 710 st->ctx->Pixel.AlphaBias != 0.0 || 711 st->ctx->Pixel.MapColorFlag) 712 /* XXX more checks */ 713 return GL_TRUE; 714 else 715 return GL_FALSE; 716} 717 718 719/** 720 * Draw image with a blit, or other non-textured quad method. 721 */ 722static void 723draw_blit(struct st_context *st, 724 GLsizei width, GLsizei height, 725 GLenum format, GLenum type, const GLvoid *pixels) 726{ 727 728 729} 730 731 732static void 733draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, 734 GLsizei width, GLsizei height, GLenum type, 735 const struct gl_pixelstore_attrib *unpack, 736 const GLvoid *pixels) 737{ 738 struct st_context *st = ctx->st; 739 struct pipe_context *pipe = st->pipe; 740 struct pipe_screen *screen = pipe->screen; 741 struct st_renderbuffer *strb; 742 struct pipe_surface *ps; 743 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; 744 GLint skipPixels; 745 ubyte *stmap; 746 747 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 748 749 strb = st_renderbuffer(ctx->DrawBuffer-> 750 Attachment[BUFFER_STENCIL].Renderbuffer); 751 ps = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, 752 PIPE_BUFFER_USAGE_CPU_WRITE); 753 754 /* map the stencil buffer */ 755 stmap = screen->surface_map(screen, ps, 756 PIPE_BUFFER_USAGE_CPU_WRITE); 757 758 /* if width > MAX_WIDTH, have to process image in chunks */ 759 skipPixels = 0; 760 while (skipPixels < width) { 761 const GLint spanX = x + skipPixels; 762 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); 763 GLint row; 764 for (row = 0; row < height; row++) { 765 GLint spanY = y + row; 766 GLubyte values[MAX_WIDTH]; 767 GLenum destType = GL_UNSIGNED_BYTE; 768 const GLvoid *source = _mesa_image_address2d(unpack, pixels, 769 width, height, 770 GL_COLOR_INDEX, type, 771 row, skipPixels); 772 _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, 773 type, source, unpack, 774 ctx->_ImageTransferState); 775 if (zoom) { 776 /* 777 _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth, 778 spanX, spanY, values); 779 */ 780 } 781 else { 782 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 783 spanY = ctx->DrawBuffer->Height - spanY - 1; 784 } 785 786 switch (ps->format) { 787 case PIPE_FORMAT_S8_UNORM: 788 { 789 ubyte *dest = stmap + spanY * ps->stride + spanX; 790 memcpy(dest, values, spanWidth); 791 } 792 break; 793 case PIPE_FORMAT_S8Z24_UNORM: 794 { 795 uint *dest = (uint *) (stmap + spanY * ps->stride + spanX*4); 796 GLint k; 797 for (k = 0; k < spanWidth; k++) { 798 uint p = dest[k]; 799 p = (p & 0xffffff) | (values[k] << 24); 800 dest[k] = p; 801 } 802 } 803 break; 804 default: 805 assert(0); 806 } 807 } 808 } 809 skipPixels += spanWidth; 810 } 811 812 /* unmap the stencil buffer */ 813 screen->surface_unmap(screen, ps); 814 pipe_surface_reference(&ps, NULL); 815} 816 817 818/** 819 * Called via ctx->Driver.DrawPixels() 820 */ 821static void 822st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, 823 GLenum format, GLenum type, 824 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) 825{ 826 struct st_fragment_program *stfp; 827 struct st_vertex_program *stvp; 828 struct st_context *st = ctx->st; 829 struct pipe_surface *ps; 830 GLuint bufferFormat; 831 const GLfloat *color; 832 833 if (format == GL_STENCIL_INDEX) { 834 draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels); 835 return; 836 } 837 838 st_validate_state(st); 839 840 if (format == GL_DEPTH_COMPONENT) { 841 ps = st->state.framebuffer.zsbuf; 842 stfp = make_fragment_shader_z(ctx->st); 843 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE); 844 color = ctx->Current.RasterColor; 845 } 846 else if (format == GL_STENCIL_INDEX) { 847 ps = st->state.framebuffer.zsbuf; 848 /* XXX special case - can't use texture map */ 849 color = NULL; 850 } 851 else { 852 ps = st->state.framebuffer.cbufs[0]; 853 stfp = combined_drawpix_fragment_program(ctx); 854 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE); 855 color = NULL; 856 } 857 858 bufferFormat = ps->format; 859 860 if (1/*any_fragment_ops(st) || 861 any_pixel_transfer_ops(st) || 862 !compatible_formats(format, type, ps->format)*/) { 863 /* textured quad */ 864 struct pipe_texture *pt 865 = make_texture(ctx->st, width, height, format, type, unpack, pixels); 866 if (pt) { 867 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], 868 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, 869 pt, stvp, stfp, color, GL_FALSE); 870 pipe_texture_reference(&pt, NULL); 871 } 872 } 873 else { 874 /* blit */ 875 draw_blit(st, width, height, format, type, pixels); 876 } 877} 878 879 880 881static void 882copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 883 GLsizei width, GLsizei height, 884 GLint dstx, GLint dsty) 885{ 886 struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); 887 struct pipe_screen *screen = ctx->st->pipe->screen; 888 struct pipe_surface *psDraw; 889 ubyte *drawMap; 890 ubyte *buffer; 891 int i; 892 893 buffer = malloc(width * height * sizeof(ubyte)); 894 if (!buffer) { 895 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); 896 return; 897 } 898 899 /* this will do stencil pixel transfer ops */ 900 st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE, 901 &ctx->DefaultPacking, buffer); 902 903 psDraw = screen->get_tex_surface(screen, rbDraw->texture, 0, 0, 0, 904 PIPE_BUFFER_USAGE_CPU_WRITE); 905 906 assert(psDraw->block.width == 1); 907 assert(psDraw->block.height == 1); 908 909 /* map the stencil buffer */ 910 drawMap = screen->surface_map(screen, psDraw, PIPE_BUFFER_USAGE_CPU_WRITE); 911 912 /* draw */ 913 /* XXX PixelZoom not handled yet */ 914 for (i = 0; i < height; i++) { 915 ubyte *dst; 916 const ubyte *src; 917 int y; 918 919 y = dsty + i; 920 921 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 922 y = ctx->DrawBuffer->Height - y - 1; 923 } 924 925 dst = drawMap + y * psDraw->stride + dstx * psDraw->block.size; 926 src = buffer + i * width; 927 928 switch (psDraw->format) { 929 case PIPE_FORMAT_S8Z24_UNORM: 930 { 931 uint *dst4 = (uint *) dst; 932 int j; 933 for (j = 0; j < width; j++) { 934 *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); 935 dst4++; 936 } 937 } 938 break; 939 case PIPE_FORMAT_S8_UNORM: 940 memcpy(dst, src, width); 941 break; 942 default: 943 assert(0); 944 } 945 } 946 947 free(buffer); 948 949 /* unmap the stencil buffer */ 950 screen->surface_unmap(screen, psDraw); 951 pipe_surface_reference(&psDraw, NULL); 952} 953 954 955static void 956st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, 957 GLsizei width, GLsizei height, 958 GLint dstx, GLint dsty, GLenum type) 959{ 960 struct st_context *st = ctx->st; 961 struct pipe_context *pipe = st->pipe; 962 struct pipe_screen *screen = pipe->screen; 963 struct st_renderbuffer *rbRead; 964 struct st_vertex_program *stvp; 965 struct st_fragment_program *stfp; 966 struct pipe_surface *psTex; 967 struct pipe_texture *pt; 968 GLfloat *color; 969 enum pipe_format srcFormat, texFormat; 970 971 /* make sure rendering has completed */ 972 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 973 974 st_validate_state(st); 975 976 if (type == GL_STENCIL) { 977 /* can't use texturing to do stencil */ 978 copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); 979 return; 980 } 981 982 if (type == GL_COLOR) { 983 rbRead = st_get_color_read_renderbuffer(ctx); 984 color = NULL; 985 stfp = combined_drawpix_fragment_program(ctx); 986 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE); 987 } 988 else { 989 assert(type == GL_DEPTH); 990 rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); 991 color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; 992 stfp = make_fragment_shader_z(ctx->st); 993 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE); 994 } 995 996 srcFormat = rbRead->texture->format; 997 998 if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D, 999 PIPE_TEXTURE_USAGE_SAMPLER, 0)) { 1000 texFormat = srcFormat; 1001 } 1002 else { 1003 /* srcFormat can't be used as a texture format */ 1004 if (type == GL_DEPTH) { 1005 texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE_2D, 1006 PIPE_TEXTURE_USAGE_DEPTH_STENCIL); 1007 assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */ 1008 } 1009 else { 1010 /* default color format */ 1011 texFormat = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D, 1012 PIPE_TEXTURE_USAGE_SAMPLER); 1013 assert(texFormat != PIPE_FORMAT_NONE); 1014 } 1015 } 1016 1017 pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0, 1018 width, height, 1, 0, 1019 PIPE_TEXTURE_USAGE_SAMPLER); 1020 if (!pt) 1021 return; 1022 1023 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 1024 srcy = ctx->DrawBuffer->Height - srcy - height; 1025 } 1026 1027 if (srcFormat == texFormat) { 1028 /* copy source framebuffer surface into mipmap/texture */ 1029 struct pipe_surface *psRead = screen->get_tex_surface(screen, 1030 rbRead->texture, 0, 0, 0, 1031 PIPE_BUFFER_USAGE_GPU_READ); 1032 psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, 1033 PIPE_BUFFER_USAGE_GPU_WRITE ); 1034 pipe->surface_copy(pipe, 1035 FALSE, 1036 psTex, /* dest */ 1037 0, 0, /* destx/y */ 1038 psRead, 1039 srcx, srcy, width, height); 1040 pipe_surface_reference(&psRead, NULL); 1041 } 1042 else { 1043 /* CPU-based fallback/conversion */ 1044 struct pipe_surface *psRead = screen->get_tex_surface(screen, 1045 rbRead->texture, 0, 0, 0, 1046 PIPE_BUFFER_USAGE_CPU_READ); 1047 1048 psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, 1049 PIPE_BUFFER_USAGE_CPU_WRITE ); 1050 1051 if (type == GL_COLOR) { 1052 /* alternate path using get/put_tile() */ 1053 GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); 1054 1055 pipe_get_tile_rgba(psRead, srcx, srcy, width, height, buf); 1056 pipe_put_tile_rgba(psTex, 0, 0, width, height, buf); 1057 1058 free(buf); 1059 } 1060 else { 1061 /* GL_DEPTH */ 1062 GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); 1063 pipe_get_tile_z(psRead, srcx, srcy, width, height, buf); 1064 pipe_put_tile_z(psTex, 0, 0, width, height, buf); 1065 free(buf); 1066 } 1067 pipe_surface_reference(&psRead, NULL); 1068 } 1069 1070 pipe_surface_reference(&psTex, NULL); 1071 1072 /* draw textured quad */ 1073 draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], 1074 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, 1075 pt, stvp, stfp, color, GL_TRUE); 1076 1077 pipe_texture_reference(&pt, NULL); 1078} 1079 1080 1081 1082void st_init_drawpixels_functions(struct dd_function_table *functions) 1083{ 1084 functions->DrawPixels = st_DrawPixels; 1085 functions->CopyPixels = st_CopyPixels; 1086} 1087 1088 1089void 1090st_destroy_drawpix(struct st_context *st) 1091{ 1092 st_reference_fragprog(st, &st->drawpix.z_shader, NULL); 1093 st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); 1094 st_reference_vertprog(st, &st->drawpix.vert_shaders[0], NULL); 1095 st_reference_vertprog(st, &st->drawpix.vert_shaders[1], NULL); 1096} 1097 1098 1099