st_cb_drawpixels.c revision c9ed86a96483063f3d6789ed16645a3dca77d726
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 /* only make programs once and re-use */ 168 static struct st_fragment_program *stfp = NULL; 169 struct gl_program *p; 170 GLuint ic = 0; 171 172 if (stfp) 173 return stfp; 174 175 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); 176 if (!p) 177 return NULL; 178 179 p->NumInstructions = 3; 180 181 p->Instructions = _mesa_alloc_instructions(p->NumInstructions); 182 if (!p->Instructions) { 183 ctx->Driver.DeleteProgram(ctx, p); 184 return NULL; 185 } 186 _mesa_init_instructions(p->Instructions, p->NumInstructions); 187 188 /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ 189 p->Instructions[ic].Opcode = OPCODE_TEX; 190 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; 191 p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPR; 192 p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; 193 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; 194 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; 195 p->Instructions[ic].TexSrcUnit = 0; 196 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; 197 ic++; 198 199 /* MOV result.color, fragment.color */ 200 p->Instructions[ic].Opcode = OPCODE_MOV; 201 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; 202 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR; 203 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; 204 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0; 205 ic++; 206 207 /* END; */ 208 p->Instructions[ic++].Opcode = OPCODE_END; 209 210 assert(ic == p->NumInstructions); 211 212 p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; 213 p->OutputsWritten = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_DEPR); 214 p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ 215 216 stfp = (struct st_fragment_program *) p; 217 st_translate_fragment_program(st, stfp, NULL); 218 219 return stfp; 220} 221 222 223 224/** 225 * Create a simple vertex shader that just passes through the 226 * vertex position and texcoord (and optionally, color). 227 */ 228static struct st_vertex_program * 229st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor) 230{ 231 /* only make programs once and re-use */ 232 static struct st_vertex_program *progs[2] = { NULL, NULL }; 233 GLcontext *ctx = st->ctx; 234 struct st_vertex_program *stvp; 235 struct gl_program *p; 236 GLuint ic = 0; 237 238 if (progs[passColor]) 239 return progs[passColor]; 240 241 p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); 242 if (!p) 243 return NULL; 244 245 if (passColor) 246 p->NumInstructions = 4; 247 else 248 p->NumInstructions = 3; 249 250 p->Instructions = _mesa_alloc_instructions(p->NumInstructions); 251 if (!p->Instructions) { 252 ctx->Driver.DeleteProgram(ctx, p); 253 return NULL; 254 } 255 _mesa_init_instructions(p->Instructions, p->NumInstructions); 256 /* MOV result.pos, vertex.pos; */ 257 p->Instructions[0].Opcode = OPCODE_MOV; 258 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT; 259 p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS; 260 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT; 261 p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS; 262 /* MOV result.texcoord0, vertex.texcoord0; */ 263 p->Instructions[1].Opcode = OPCODE_MOV; 264 p->Instructions[1].DstReg.File = PROGRAM_OUTPUT; 265 p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0; 266 p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT; 267 p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0; 268 ic = 2; 269 if (passColor) { 270 /* MOV result.color0, vertex.color0; */ 271 p->Instructions[ic].Opcode = OPCODE_MOV; 272 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; 273 p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0; 274 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; 275 p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0; 276 ic++; 277 } 278 279 /* END; */ 280 p->Instructions[ic].Opcode = OPCODE_END; 281 ic++; 282 283 assert(ic == p->NumInstructions); 284 285 p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0; 286 p->OutputsWritten = ((1 << VERT_RESULT_TEX0) | 287 (1 << VERT_RESULT_HPOS)); 288 if (passColor) { 289 p->InputsRead |= VERT_BIT_COLOR0; 290 p->OutputsWritten |= (1 << VERT_RESULT_COL0); 291 } 292 293 stvp = (struct st_vertex_program *) p; 294 st_translate_vertex_program(st, stvp, NULL); 295 296 progs[passColor] = stvp; 297 298 return stvp; 299} 300 301 302static GLenum 303_mesa_base_format(GLenum format) 304{ 305 switch (format) { 306 case GL_DEPTH_COMPONENT: 307 return GL_DEPTH_COMPONENT; 308 case GL_STENCIL_INDEX: 309 return GL_STENCIL_INDEX; 310 default: 311 return GL_RGBA; 312 } 313} 314 315 316/** 317 * Make texture containing an image for glDrawPixels image. 318 * If 'pixels' is NULL, leave the texture image data undefined. 319 */ 320static struct pipe_texture * 321make_texture(struct st_context *st, 322 GLsizei width, GLsizei height, GLenum format, GLenum type, 323 const struct gl_pixelstore_attrib *unpack, 324 const GLvoid *pixels) 325{ 326 GLcontext *ctx = st->ctx; 327 struct pipe_context *pipe = st->pipe; 328 struct pipe_screen *screen = pipe->screen; 329 const struct gl_texture_format *mformat; 330 struct pipe_texture *pt; 331 enum pipe_format pipeFormat; 332 GLuint cpp; 333 GLenum baseFormat; 334 335 baseFormat = _mesa_base_format(format); 336 337 mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type); 338 assert(mformat); 339 340 pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat); 341 assert(pipeFormat); 342 cpp = st_sizeof_format(pipeFormat); 343 344 pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels); 345 if (!pixels) 346 return NULL; 347 348 pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height, 349 1, 0); 350 if (!pt) { 351 _mesa_unmap_drawpix_pbo(ctx, unpack); 352 return NULL; 353 } 354 355 { 356 struct pipe_surface *surface; 357 static const GLuint dstImageOffsets = 0; 358 GLboolean success; 359 GLubyte *dest; 360 const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; 361 362 /* we'll do pixel transfer in a fragment shader */ 363 ctx->_ImageTransferState = 0x0; 364 365 surface = screen->get_tex_surface(screen, pt, 0, 0, 0, 366 PIPE_BUFFER_USAGE_CPU_WRITE); 367 368 /* map texture surface */ 369 dest = screen->surface_map(screen, surface, 370 PIPE_BUFFER_USAGE_CPU_WRITE); 371 372 /* Put image into texture surface. 373 * Note that the image is actually going to be upside down in 374 * the texture. We deal with that with texcoords. 375 */ 376 success = mformat->StoreImage(ctx, 2, /* dims */ 377 baseFormat, /* baseInternalFormat */ 378 mformat, /* gl_texture_format */ 379 dest, /* dest */ 380 0, 0, 0, /* dstX/Y/Zoffset */ 381 surface->pitch * cpp, /* dstRowStride, bytes */ 382 &dstImageOffsets, /* dstImageOffsets */ 383 width, height, 1, /* size */ 384 format, type, /* src format/type */ 385 pixels, /* data source */ 386 unpack); 387 388 /* unmap */ 389 screen->surface_unmap(screen, surface); 390 pipe_surface_reference(&surface, NULL); 391 392 assert(success); 393 394 /* restore */ 395 ctx->_ImageTransferState = imageTransferStateSave; 396 } 397 398 _mesa_unmap_drawpix_pbo(ctx, unpack); 399 400 return pt; 401} 402 403 404/** 405 * Draw quad with texcoords and optional color. 406 * Coords are window coords with y=0=bottom. 407 * \param color may be null 408 * \param invertTex if true, flip texcoords vertically 409 */ 410static void 411draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, 412 GLfloat x1, GLfloat y1, const GLfloat *color, 413 GLboolean invertTex) 414{ 415 struct st_context *st = ctx->st; 416 struct pipe_context *pipe = ctx->st->pipe; 417 GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ 418 419 /* setup vertex data */ 420 { 421 const struct gl_framebuffer *fb = st->ctx->DrawBuffer; 422 const GLfloat fb_width = fb->Width; 423 const GLfloat fb_height = fb->Height; 424 const GLfloat clip_x0 = x0 / fb_width * 2.0 - 1.0; 425 const GLfloat clip_y0 = y0 / fb_height * 2.0 - 1.0; 426 const GLfloat clip_x1 = x1 / fb_width * 2.0 - 1.0; 427 const GLfloat clip_y1 = y1 / fb_height * 2.0 - 1.0; 428 const GLfloat sLeft = 0.0F, sRight = 1.0F; 429 const GLfloat tTop = invertTex, tBot = 1.0 - tTop; 430 GLuint tex, i; 431 432 /* upper-left */ 433 verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ 434 verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ 435 436 /* upper-right */ 437 verts[1][0][0] = clip_x1; 438 verts[1][0][1] = clip_y0; 439 440 /* lower-right */ 441 verts[2][0][0] = clip_x1; 442 verts[2][0][1] = clip_y1; 443 444 /* lower-left */ 445 verts[3][0][0] = clip_x0; 446 verts[3][0][1] = clip_y1; 447 448 tex = color ? 2 : 1; 449 verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */ 450 verts[0][tex][1] = tTop; /* v[0].attr[tex].t */ 451 verts[1][tex][0] = sRight; 452 verts[1][tex][1] = tTop; 453 verts[2][tex][0] = sRight; 454 verts[2][tex][1] = tBot; 455 verts[3][tex][0] = sLeft; 456 verts[3][tex][1] = tBot; 457 458 /* same for all verts: */ 459 if (color) { 460 for (i = 0; i < 4; i++) { 461 verts[i][0][2] = z; /*Z*/ 462 verts[i][0][3] = 1.0; /*W*/ 463 verts[i][1][0] = color[0]; 464 verts[i][1][1] = color[1]; 465 verts[i][1][2] = color[2]; 466 verts[i][1][3] = color[3]; 467 verts[i][2][2] = 0.0; /*R*/ 468 verts[i][2][3] = 1.0; /*Q*/ 469 } 470 } 471 else { 472 for (i = 0; i < 4; i++) { 473 verts[i][0][2] = z; /*Z*/ 474 verts[i][0][3] = 1.0; /*W*/ 475 verts[i][1][2] = 0.0; /*R*/ 476 verts[i][1][3] = 1.0; /*Q*/ 477 } 478 } 479 } 480 481 { 482 struct pipe_buffer *buf; 483 ubyte *map; 484 485 /* allocate/load buffer object with vertex data */ 486 buf = pipe_buffer_create(pipe,32, PIPE_BUFFER_USAGE_VERTEX, 487 sizeof(verts)); 488 map = pipe_buffer_map(pipe, buf, PIPE_BUFFER_USAGE_CPU_WRITE); 489 memcpy(map, verts, sizeof(verts)); 490 pipe_buffer_unmap(pipe, buf); 491 492 util_draw_vertex_buffer(pipe, buf, 493 PIPE_PRIM_QUADS, 494 4, /* verts */ 495 3); /* attribs/vert */ 496 497 pipe_buffer_destroy(pipe, buf); 498 } 499} 500 501 502 503static void 504draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, 505 GLsizei width, GLsizei height, 506 GLfloat zoomX, GLfloat zoomY, 507 struct pipe_texture *pt, 508 struct st_vertex_program *stvp, 509 struct st_fragment_program *stfp, 510 const GLfloat *color, 511 GLboolean invertTex) 512{ 513 struct st_context *st = ctx->st; 514 struct pipe_context *pipe = ctx->st->pipe; 515 struct cso_context *cso = ctx->st->cso_context; 516 GLfloat x0, y0, x1, y1; 517 GLuint maxSize; 518 519 /* limit checks */ 520 /* XXX if DrawPixels image is larger than max texture size, break 521 * it up into chunks. 522 */ 523 maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); 524 assert(width <= maxSize); 525 assert(height <= maxSize); 526 527 cso_save_rasterizer(cso); 528 cso_save_viewport(cso); 529 cso_save_samplers(cso); 530 cso_save_sampler_textures(cso); 531 cso_save_fragment_shader(cso); 532 cso_save_vertex_shader(cso); 533 534 /* rasterizer state: just scissor */ 535 { 536 struct pipe_rasterizer_state rasterizer; 537 memset(&rasterizer, 0, sizeof(rasterizer)); 538 rasterizer.gl_rasterization_rules = 1; 539 rasterizer.scissor = ctx->Scissor.Enabled; 540 cso_set_rasterizer(cso, &rasterizer); 541 } 542 543 /* fragment shader state: TEX lookup program */ 544 cso_set_fragment_shader_handle(cso, stfp->driver_shader); 545 546 /* vertex shader state: position + texcoord pass-through */ 547 cso_set_vertex_shader_handle(cso, stvp->driver_shader); 548 549 550 /* texture sampling state: */ 551 { 552 struct pipe_sampler_state sampler; 553 memset(&sampler, 0, sizeof(sampler)); 554 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; 555 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; 556 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; 557 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; 558 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 559 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 560 sampler.normalized_coords = 1; 561 562 cso_single_sampler(cso, 0, &sampler); 563 if (st->pixel_xfer.pixelmap_enabled) { 564 cso_single_sampler(cso, 1, &sampler); 565 } 566 cso_single_sampler_done(cso); 567 } 568 569 /* viewport state: viewport matching window dims */ 570 { 571 const float width = ctx->DrawBuffer->Width; 572 const float height = ctx->DrawBuffer->Height; 573 struct pipe_viewport_state vp; 574 vp.scale[0] = 0.5 * width; 575 vp.scale[1] = -0.5 * height; 576 vp.scale[2] = 1.0; 577 vp.scale[3] = 1.0; 578 vp.translate[0] = 0.5 * width; 579 vp.translate[1] = 0.5 * height; 580 vp.translate[2] = 0.0; 581 vp.translate[3] = 0.0; 582 cso_set_viewport(cso, &vp); 583 } 584 585 /* texture state: */ 586 if (st->pixel_xfer.pixelmap_enabled) { 587 struct pipe_texture *textures[2]; 588 textures[0] = pt; 589 textures[1] = st->pixel_xfer.pixelmap_texture; 590 pipe->set_sampler_textures(pipe, 2, textures); 591 } 592 else { 593 pipe->set_sampler_textures(pipe, 1, &pt); 594 } 595 596 /* Compute window coords (y=0=bottom) with pixel zoom. 597 * Recall that these coords are transformed by the current 598 * vertex shader and viewport transformation. 599 */ 600 x0 = x; 601 x1 = x + width * ctx->Pixel.ZoomX; 602 y0 = y; 603 y1 = y + height * ctx->Pixel.ZoomY; 604 draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex); 605 606 /* restore state */ 607 cso_restore_rasterizer(cso); 608 cso_restore_viewport(cso); 609 cso_restore_samplers(cso); 610 cso_restore_sampler_textures(cso); 611 cso_restore_fragment_shader(cso); 612 cso_restore_vertex_shader(cso); 613} 614 615 616/** 617 * Check if a GL format/type combination is a match to the given pipe format. 618 * XXX probably move this to a re-usable place. 619 */ 620static GLboolean 621compatible_formats(GLenum format, GLenum type, enum pipe_format pipeFormat) 622{ 623 static const GLuint one = 1; 624 GLubyte littleEndian = *((GLubyte *) &one); 625 626 if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM && 627 format == GL_RGBA && 628 type == GL_UNSIGNED_BYTE && 629 !littleEndian) { 630 return GL_TRUE; 631 } 632 else if (pipeFormat == PIPE_FORMAT_R8G8B8A8_UNORM && 633 format == GL_ABGR_EXT && 634 type == GL_UNSIGNED_BYTE && 635 littleEndian) { 636 return GL_TRUE; 637 } 638 else if (pipeFormat == PIPE_FORMAT_A8R8G8B8_UNORM && 639 format == GL_BGRA && 640 type == GL_UNSIGNED_BYTE && 641 littleEndian) { 642 return GL_TRUE; 643 } 644 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM && 645 format == GL_RGB && 646 type == GL_UNSIGNED_SHORT_5_6_5) { 647 /* endian don't care */ 648 return GL_TRUE; 649 } 650 else if (pipeFormat == PIPE_FORMAT_R5G6B5_UNORM && 651 format == GL_BGR && 652 type == GL_UNSIGNED_SHORT_5_6_5_REV) { 653 /* endian don't care */ 654 return GL_TRUE; 655 } 656 else if (pipeFormat == PIPE_FORMAT_S8_UNORM && 657 format == GL_STENCIL_INDEX && 658 type == GL_UNSIGNED_BYTE) { 659 return GL_TRUE; 660 } 661 else if (pipeFormat == PIPE_FORMAT_Z32_UNORM && 662 format == GL_DEPTH_COMPONENT && 663 type == GL_UNSIGNED_INT) { 664 return GL_TRUE; 665 } 666 /* XXX add more cases */ 667 else { 668 return GL_FALSE; 669 } 670} 671 672 673/** 674 * Check if any per-fragment ops are enabled. 675 * XXX probably move this to a re-usable place. 676 */ 677static GLboolean 678any_fragment_ops(const struct st_context *st) 679{ 680 if (st->state.depth_stencil.alpha.enabled || 681 st->state.depth_stencil.depth.enabled || 682 st->state.blend.blend_enable || 683 st->state.blend.logicop_enable) 684 /* XXX more checks */ 685 return GL_TRUE; 686 else 687 return GL_FALSE; 688} 689 690 691/** 692 * Check if any pixel transfer ops are enabled. 693 * XXX probably move this to a re-usable place. 694 */ 695static GLboolean 696any_pixel_transfer_ops(const struct st_context *st) 697{ 698 if (st->ctx->Pixel.RedScale != 1.0 || 699 st->ctx->Pixel.RedBias != 0.0 || 700 st->ctx->Pixel.GreenScale != 1.0 || 701 st->ctx->Pixel.GreenBias != 0.0 || 702 st->ctx->Pixel.BlueScale != 1.0 || 703 st->ctx->Pixel.BlueBias != 0.0 || 704 st->ctx->Pixel.AlphaScale != 1.0 || 705 st->ctx->Pixel.AlphaBias != 0.0 || 706 st->ctx->Pixel.MapColorFlag) 707 /* XXX more checks */ 708 return GL_TRUE; 709 else 710 return GL_FALSE; 711} 712 713 714/** 715 * Draw image with a blit, or other non-textured quad method. 716 */ 717static void 718draw_blit(struct st_context *st, 719 GLsizei width, GLsizei height, 720 GLenum format, GLenum type, const GLvoid *pixels) 721{ 722 723 724} 725 726 727static void 728draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, 729 GLsizei width, GLsizei height, GLenum type, 730 const struct gl_pixelstore_attrib *unpack, 731 const GLvoid *pixels) 732{ 733 struct st_context *st = ctx->st; 734 struct pipe_context *pipe = st->pipe; 735 struct pipe_screen *screen = pipe->screen; 736 struct pipe_surface *ps = st->state.framebuffer.zsbuf; 737 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; 738 GLint skipPixels; 739 ubyte *stmap; 740 741 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 742 743 /* map the stencil buffer */ 744 stmap = screen->surface_map(screen, ps, 745 PIPE_BUFFER_USAGE_CPU_WRITE); 746 747 /* if width > MAX_WIDTH, have to process image in chunks */ 748 skipPixels = 0; 749 while (skipPixels < width) { 750 const GLint spanX = x + skipPixels; 751 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); 752 GLint row; 753 for (row = 0; row < height; row++) { 754 GLint spanY = y + row; 755 GLubyte values[MAX_WIDTH]; 756 GLenum destType = GL_UNSIGNED_BYTE; 757 const GLvoid *source = _mesa_image_address2d(unpack, pixels, 758 width, height, 759 GL_COLOR_INDEX, type, 760 row, skipPixels); 761 _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, 762 type, source, unpack, 763 ctx->_ImageTransferState); 764 if (zoom) { 765 /* 766 _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth, 767 spanX, spanY, values); 768 */ 769 } 770 else { 771 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 772 spanY = ctx->DrawBuffer->Height - spanY - 1; 773 } 774 775 switch (ps->format) { 776 case PIPE_FORMAT_U_S8: 777 { 778 ubyte *dest = stmap + spanY * ps->pitch + spanX; 779 memcpy(dest, values, spanWidth); 780 } 781 break; 782 case PIPE_FORMAT_S8Z24_UNORM: 783 { 784 uint *dest = (uint *) stmap + spanY * ps->pitch + spanX; 785 GLint k; 786 for (k = 0; k < spanWidth; k++) { 787 uint p = dest[k]; 788 p = (p & 0xffffff) | (values[k] << 24); 789 dest[k] = p; 790 } 791 } 792 break; 793 default: 794 assert(0); 795 } 796 } 797 } 798 skipPixels += spanWidth; 799 } 800 801 /* unmap the stencil buffer */ 802 screen->surface_unmap(screen, ps); 803} 804 805 806/** 807 * Called via ctx->Driver.DrawPixels() 808 */ 809static void 810st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, 811 GLenum format, GLenum type, 812 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) 813{ 814 struct st_fragment_program *stfp; 815 struct st_vertex_program *stvp; 816 struct st_context *st = ctx->st; 817 struct pipe_surface *ps; 818 GLuint bufferFormat; 819 const GLfloat *color; 820 821 if (format == GL_STENCIL_INDEX) { 822 draw_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels); 823 return; 824 } 825 826 st_validate_state(st); 827 828 if (format == GL_DEPTH_COMPONENT) { 829 ps = st->state.framebuffer.zsbuf; 830 stfp = make_fragment_shader_z(ctx->st); 831 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE); 832 color = ctx->Current.RasterColor; 833 } 834 else if (format == GL_STENCIL_INDEX) { 835 ps = st->state.framebuffer.zsbuf; 836 /* XXX special case - can't use texture map */ 837 color = NULL; 838 } 839 else { 840 ps = st->state.framebuffer.cbufs[0]; 841 stfp = combined_drawpix_fragment_program(ctx); 842 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE); 843 color = NULL; 844 } 845 846 bufferFormat = ps->format; 847 848 if (1/*any_fragment_ops(st) || 849 any_pixel_transfer_ops(st) || 850 !compatible_formats(format, type, ps->format)*/) { 851 /* textured quad */ 852 struct pipe_texture *pt 853 = make_texture(ctx->st, width, height, format, type, unpack, pixels); 854 if (pt) { 855 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], 856 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, 857 pt, stvp, stfp, color, GL_FALSE); 858 pipe_texture_reference(&pt, NULL); 859 } 860 } 861 else { 862 /* blit */ 863 draw_blit(st, width, height, format, type, pixels); 864 } 865} 866 867 868 869static void 870copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 871 GLsizei width, GLsizei height, 872 GLint dstx, GLint dsty) 873{ 874 struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); 875 struct pipe_screen *screen = ctx->st->pipe->screen; 876 struct pipe_surface *psDraw = rbDraw->surface; 877 ubyte *drawMap; 878 ubyte *buffer; 879 int i; 880 881 buffer = malloc(width * height * sizeof(ubyte)); 882 if (!buffer) { 883 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); 884 return; 885 } 886 887 /* this will do stencil pixel transfer ops */ 888 st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_UNSIGNED_BYTE, 889 &ctx->DefaultPacking, buffer); 890 891 /* map the stencil buffer */ 892 drawMap = screen->surface_map(screen, psDraw, PIPE_BUFFER_USAGE_CPU_WRITE); 893 894 /* draw */ 895 /* XXX PixelZoom not handled yet */ 896 for (i = 0; i < height; i++) { 897 ubyte *dst; 898 const ubyte *src; 899 int y; 900 901 y = dsty + i; 902 903 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 904 y = ctx->DrawBuffer->Height - y - 1; 905 } 906 907 dst = drawMap + (y * psDraw->pitch + dstx) * psDraw->cpp; 908 src = buffer + i * width; 909 910 switch (psDraw->format) { 911 case PIPE_FORMAT_S8Z24_UNORM: 912 { 913 uint *dst4 = (uint *) dst; 914 int j; 915 for (j = 0; j < width; j++) { 916 *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); 917 dst4++; 918 } 919 } 920 break; 921 case PIPE_FORMAT_U_S8: 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 screen->surface_unmap(screen, psDraw); 933} 934 935 936static void 937st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, 938 GLsizei width, GLsizei height, 939 GLint dstx, GLint dsty, GLenum type) 940{ 941 struct st_context *st = ctx->st; 942 struct pipe_context *pipe = st->pipe; 943 struct pipe_screen *screen = pipe->screen; 944 struct st_renderbuffer *rbRead; 945 struct st_vertex_program *stvp; 946 struct st_fragment_program *stfp; 947 struct pipe_surface *psRead; 948 struct pipe_surface *psTex; 949 struct pipe_texture *pt; 950 GLfloat *color; 951 enum pipe_format srcFormat, texFormat; 952 953 /* make sure rendering has completed */ 954 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 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 stfp = combined_drawpix_fragment_program(ctx); 968 stvp = st_make_passthrough_vertex_shader(ctx->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 stfp = make_fragment_shader_z(ctx->st); 975 stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE); 976 } 977 978 psRead = rbRead->surface; 979 srcFormat = psRead->format; 980 981 if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE)) { 982 texFormat = srcFormat; 983 } 984 else { 985 /* srcFormat can't be used as a texture format */ 986 if (type == GL_DEPTH) { 987 texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE); 988 assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */ 989 } 990 else { 991 /* todo */ 992 assert(0); 993 } 994 } 995 996 pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0, 997 width, height, 1, 0); 998 if (!pt) 999 return; 1000 1001 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { 1002 srcy = ctx->DrawBuffer->Height - srcy - height; 1003 } 1004 1005 if (srcFormat == texFormat) { 1006 psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, 1007 PIPE_BUFFER_USAGE_GPU_WRITE ); 1008 1009 /* copy source framebuffer surface into mipmap/texture */ 1010 pipe->surface_copy(pipe, 1011 FALSE, 1012 psTex, /* dest */ 1013 0, 0, /* destx/y */ 1014 psRead, 1015 srcx, srcy, width, height); 1016 } 1017 else { 1018 psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, 1019 PIPE_BUFFER_USAGE_CPU_WRITE ); 1020 1021 if (type == GL_COLOR) { 1022 /* alternate path using get/put_tile() */ 1023 GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); 1024 1025 pipe_get_tile_rgba(pipe, psRead, srcx, srcy, width, height, buf); 1026 pipe_put_tile_rgba(pipe, psTex, 0, 0, width, height, buf); 1027 1028 free(buf); 1029 } 1030 else { 1031 /* GL_DEPTH */ 1032 GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); 1033 pipe_get_tile_z(pipe, psRead, srcx, srcy, width, height, buf); 1034 pipe_put_tile_z(pipe, psTex, 0, 0, width, height, buf); 1035 free(buf); 1036 } 1037 } 1038 1039 /* draw textured quad */ 1040 draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], 1041 width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, 1042 pt, stvp, stfp, color, GL_TRUE); 1043 1044 pipe_surface_reference(&psTex, NULL); 1045 pipe_texture_reference(&pt, NULL); 1046} 1047 1048 1049 1050void st_init_drawpixels_functions(struct dd_function_table *functions) 1051{ 1052 functions->DrawPixels = st_DrawPixels; 1053 functions->CopyPixels = st_CopyPixels; 1054} 1055