st_cb_drawpixels.c revision 294401814d1d89cc731de1c22c25333aa5d59374
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 "imports.h" 34 35#include "st_context.h" 36#include "st_atom.h" 37#include "st_cache.h" 38#include "st_draw.h" 39#include "st_program.h" 40#include "st_cb_drawpixels.h" 41#include "st_cb_texture.h" 42#include "st_draw.h" 43#include "st_format.h" 44#include "pipe/p_context.h" 45#include "pipe/p_defines.h" 46#include "pipe/tgsi/mesa/mesa_to_tgsi.h" 47#include "shader/prog_instruction.h" 48#include "vf/vf.h" 49 50 51 52/** 53 * Create a simple fragment shader that does a TEX() instruction to get 54 * the fragment color. 55 */ 56static struct st_fragment_program * 57make_fragment_shader(struct st_context *st) 58{ 59 GLcontext *ctx = st->ctx; 60 struct st_fragment_program *stfp; 61 struct gl_program *p; 62 GLboolean b; 63 64 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); 65 if (!p) 66 return NULL; 67 68 p->NumInstructions = 2; 69 p->Instructions = _mesa_alloc_instructions(2); 70 if (!p->Instructions) { 71 ctx->Driver.DeleteProgram(ctx, p); 72 return NULL; 73 } 74 _mesa_init_instructions(p->Instructions, 2); 75 /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */ 76 p->Instructions[0].Opcode = OPCODE_TEX; 77 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT; 78 p->Instructions[0].DstReg.Index = FRAG_RESULT_COLR; 79 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT; 80 p->Instructions[0].SrcReg[0].Index = FRAG_ATTRIB_TEX0; 81 p->Instructions[0].TexSrcUnit = 0; 82 p->Instructions[0].TexSrcTarget = TEXTURE_2D_INDEX; 83 /* END; */ 84 p->Instructions[1].Opcode = OPCODE_END; 85 86 p->InputsRead = FRAG_BIT_TEX0; 87 p->OutputsWritten = (1 << FRAG_RESULT_COLR); 88 89 stfp = (struct st_fragment_program *) p; 90 /* compile into tgsi format */ 91 b = tgsi_mesa_compile_fp_program(&stfp->Base, 92 stfp->tokens, ST_FP_MAX_TOKENS); 93 assert(b); 94 95 return stfp; 96} 97 98 99/** 100 * Create a simple vertex shader that just passes through the 101 * vertex position and color. 102 */ 103static struct st_vertex_program * 104make_vertex_shader(struct st_context *st) 105{ 106 GLcontext *ctx = st->ctx; 107 struct st_vertex_program *stvp; 108 struct gl_program *p; 109 GLboolean b; 110 111 p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); 112 if (!p) 113 return NULL; 114 115 p->NumInstructions = 3; 116 p->Instructions = _mesa_alloc_instructions(3); 117 if (!p->Instructions) { 118 ctx->Driver.DeleteProgram(ctx, p); 119 return NULL; 120 } 121 _mesa_init_instructions(p->Instructions, 3); 122 /* MOV result.pos, vertex.pos; */ 123 p->Instructions[0].Opcode = OPCODE_MOV; 124 p->Instructions[0].DstReg.File = PROGRAM_OUTPUT; 125 p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS; 126 p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT; 127 p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS; 128 /* MOV result.color, vertex.color; */ 129 p->Instructions[1].Opcode = OPCODE_MOV; 130 p->Instructions[1].DstReg.File = PROGRAM_OUTPUT; 131 p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0; 132 p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT; 133 p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0; 134 /* END; */ 135 p->Instructions[2].Opcode = OPCODE_END; 136 137 p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0; 138 p->OutputsWritten = ((1 << VERT_RESULT_TEX0) | 139 (1 << VERT_RESULT_HPOS)); 140 141 stvp = (struct st_vertex_program *) p; 142 /* compile into tgsi format */ 143 b = tgsi_mesa_compile_vp_program(&stvp->Base, 144 stvp->tokens, ST_FP_MAX_TOKENS); 145 assert(b); 146 147 return stvp; 148} 149 150 151 152static struct pipe_mipmap_tree * 153make_mipmap_tree(struct st_context *st, 154 GLsizei width, GLsizei height, GLenum format, GLenum type, 155 const struct gl_pixelstore_attrib *unpack, 156 const GLvoid *pixels) 157{ 158 struct pipe_context *pipe = st->pipe; 159 const struct gl_texture_format *mformat; 160 const GLbitfield flags = PIPE_SURFACE_FLAG_TEXTURE; 161 struct pipe_mipmap_tree *mt; 162 GLuint pipeFormat, cpp; 163 164 mformat = st_ChooseTextureFormat(st->ctx, GL_RGBA, format, type); 165 assert(mformat); 166 167 pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat); 168 assert(pipeFormat); 169 cpp = st_sizeof_format(pipeFormat); 170 171 mt = CALLOC_STRUCT(pipe_mipmap_tree); 172 173 if (unpack->BufferObj && unpack->BufferObj->Name) { 174 /* 175 mt->region = buffer_object_region(unpack->BufferObj); 176 */ 177 } 178 else { 179 static const GLuint dstImageOffsets = 0; 180 GLboolean success; 181 GLubyte *dest; 182 GLuint pitch; 183 184 /* allocate texture region/storage */ 185 mt->region = st->pipe->region_alloc(st->pipe, cpp, width, height, flags); 186 pitch = mt->region->pitch; 187 188 /* map texture region */ 189 dest = pipe->region_map(pipe, mt->region); 190 191 /* Put image into texture region. 192 * Note that the image is actually going to be upside down in 193 * the texture. We deal with that with texcoords. 194 */ 195 success = mformat->StoreImage(st->ctx, 2, /* dims */ 196 GL_RGBA, /* baseInternalFormat */ 197 mformat, /* gl_texture_format */ 198 dest, /* dest */ 199 0, 0, 0, /* dstX/Y/Zoffset */ 200 pitch * cpp, /* dstRowStride, bytes */ 201 &dstImageOffsets, /* dstImageOffsets */ 202 width, height, 1, /* size */ 203 format, type, /* src format/type */ 204 pixels, /* data source */ 205 unpack); 206 207 /* unmap */ 208 pipe->region_unmap(pipe, mt->region); 209 210 assert(success); 211 } 212 213 mt->target = PIPE_TEXTURE_2D; 214 mt->internal_format = GL_RGBA; 215 mt->format = pipeFormat; 216 mt->first_level = 0; 217 mt->last_level = 0; 218 mt->width0 = width; 219 mt->height0 = height; 220 mt->depth0 = 1; 221 mt->cpp = cpp; 222 mt->compressed = 0; 223 mt->pitch = mt->region->pitch; 224 mt->depth_pitch = 0; 225 mt->total_height = height; 226 mt->level[0].level_offset = 0; 227 mt->level[0].width = width; 228 mt->level[0].height = height; 229 mt->level[0].depth = 1; 230 mt->level[0].nr_images = 1; 231 mt->level[0].image_offset = NULL; 232 mt->refcount = 1; 233 234 return mt; 235} 236 237 238static void 239free_mipmap_tree(struct pipe_context *pipe, struct pipe_mipmap_tree *mt) 240{ 241 pipe->region_release(pipe, &mt->region); 242 free(mt); 243} 244 245 246/** 247 * Draw textured quad. 248 * Coords are window coords with y=0=bottom. 249 */ 250static void 251draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, 252 GLfloat x1, GLfloat y1) 253{ 254 static const GLuint attribs[2] = { 255 0, /* pos */ 256 8 /* tex0 */ 257 }; 258 GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */ 259 GLuint i; 260 261 /* upper-left */ 262 verts[0][0][0] = x0; 263 verts[0][0][1] = y0; 264 verts[0][1][0] = 0.0; 265 verts[0][1][1] = 0.0; 266 267 /* upper-right */ 268 verts[1][0][0] = x1; 269 verts[1][0][1] = y0; 270 verts[1][1][0] = 1.0; 271 verts[1][1][1] = 0.0; 272 273 /* lower-right */ 274 verts[2][0][0] = x1; 275 verts[2][0][1] = y1; 276 verts[2][1][0] = 1.0; 277 verts[2][1][1] = 1.0; 278 279 /* lower-left */ 280 verts[3][0][0] = x0; 281 verts[3][0][1] = y1; 282 verts[3][1][0] = 0.0; 283 verts[3][1][1] = 1.0; 284 285 /* same for all verts: */ 286 for (i = 0; i < 4; i++) { 287 verts[i][0][2] = z; /*Z*/ 288 verts[i][0][3] = 1.0; /*W*/ 289 verts[i][1][2] = 0.0; /*R*/ 290 verts[i][1][3] = 1.0; /*Q*/ 291 } 292 293 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2, attribs); 294} 295 296 297static void 298draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, 299 GLsizei width, GLsizei height, GLenum format, GLenum type, 300 const struct gl_pixelstore_attrib *unpack, 301 const GLvoid *pixels) 302{ 303 const GLuint unit = 0; 304 struct pipe_context *pipe = ctx->st->pipe; 305 struct pipe_mipmap_tree *mt; 306 GLfloat x0, y0, x1, y1; 307 GLuint maxWidth, maxHeight; 308 309 /* limit checks */ 310 /* XXX if DrawPixels image is larger than max texture size, break 311 * it up into chunks. 312 */ 313 pipe->max_texture_size(pipe, PIPE_TEXTURE_2D, &maxWidth, &maxHeight, NULL); 314 assert(width <= maxWidth); 315 assert(height <= maxHeight); 316 317 /* setup state: just scissor */ 318 { 319 struct pipe_rasterizer_state setup; 320 struct pipe_rasterizer_state *cached; 321 memset(&setup, 0, sizeof(setup)); 322 if (ctx->Scissor.Enabled) 323 setup.scissor = 1; 324 cached = st_cached_rasterizer_state(ctx->st, &setup); 325 pipe->bind_rasterizer_state(pipe, cached); 326 } 327 328 /* fragment shader state: TEX lookup program */ 329 { 330 static struct st_fragment_program *stfp = NULL; 331 struct pipe_shader_state fs; 332 if (!stfp) { 333 stfp = make_fragment_shader(ctx->st); 334 } 335 memset(&fs, 0, sizeof(fs)); 336 fs.inputs_read = stfp->Base.Base.InputsRead; 337 fs.tokens = &stfp->tokens[0]; 338 pipe->set_fs_state(pipe, &fs); 339 } 340 341 /* vertex shader state: position + texcoord pass-through */ 342 { 343 static struct st_vertex_program *stvp = NULL; 344 struct pipe_shader_state vs; 345 if (!stvp) { 346 stvp = make_vertex_shader(ctx->st); 347 } 348 memset(&vs, 0, sizeof(vs)); 349 vs.inputs_read = stvp->Base.Base.InputsRead; 350 vs.outputs_written = stvp->Base.Base.OutputsWritten; 351 vs.tokens = &stvp->tokens[0]; 352 pipe->set_vs_state(pipe, &vs); 353 } 354 355 /* texture sampling state: */ 356 { 357 struct pipe_sampler_state sampler; 358 memset(&sampler, 0, sizeof(sampler)); 359 sampler.wrap_s = PIPE_TEX_WRAP_REPEAT; 360 sampler.wrap_t = PIPE_TEX_WRAP_REPEAT; 361 sampler.wrap_r = PIPE_TEX_WRAP_REPEAT; 362 sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; 363 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 364 sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 365 const struct pipe_sampler_state *state = st_cached_sampler_state(ctx->st, &sampler); 366 pipe->bind_sampler_state(pipe, unit, state); 367 } 368 369 /* viewport state: viewport matching window dims */ 370 { 371 const float width = ctx->DrawBuffer->Width; 372 const float height = ctx->DrawBuffer->Height; 373 struct pipe_viewport_state vp; 374 vp.scale[0] = 0.5 * width; 375 vp.scale[1] = -0.5 * height; 376 vp.scale[2] = 0.5; 377 vp.scale[3] = 1.0; 378 vp.translate[0] = 0.5 * width; 379 vp.translate[1] = 0.5 * height; 380 vp.translate[2] = 0.5; 381 vp.translate[3] = 0.0; 382 pipe->set_viewport_state(pipe, &vp); 383 } 384 385 /* mipmap tree state: */ 386 { 387 mt = make_mipmap_tree(ctx->st, width, height, format, type, 388 unpack, pixels); 389 pipe->set_texture_state(pipe, unit, mt); 390 } 391 392 /* Compute window coords (y=0=bottom) with pixel zoom. 393 * Recall that these coords are transformed by the current 394 * vertex shader and viewport transformation. 395 */ 396 x0 = x; 397 x1 = x + width * ctx->Pixel.ZoomX; 398 y0 = y; 399 y1 = y + height * ctx->Pixel.ZoomY; 400 401 /* draw textured quad */ 402 draw_quad(ctx, x0, y0, z, x1, y1); 403 404 /* restore GL state */ 405 pipe->bind_rasterizer_state(pipe, ctx->st->state.rasterizer); 406 pipe->set_fs_state(pipe, &ctx->st->state.fs); 407 pipe->set_vs_state(pipe, &ctx->st->state.vs); 408 pipe->set_texture_state(pipe, unit, ctx->st->state.texture[unit]); 409 pipe->bind_sampler_state(pipe, unit, ctx->st->state.sampler[unit]); 410 pipe->set_viewport_state(pipe, &ctx->st->state.viewport); 411 412 free_mipmap_tree(pipe, mt); 413} 414 415 416/** 417 * Check if a GL format/type combination is a match to the given pipe format. 418 * XXX probably move this to a re-usable place. 419 */ 420static GLboolean 421compatible_formats(GLenum format, GLenum type, GLuint pipeFormat) 422{ 423 static const GLuint one = 1; 424 GLubyte littleEndian = *((GLubyte *) &one); 425 426 if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 && 427 format == GL_RGBA && 428 type == GL_UNSIGNED_BYTE && 429 !littleEndian) { 430 return GL_TRUE; 431 } 432 else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 && 433 format == GL_ABGR_EXT && 434 type == GL_UNSIGNED_BYTE && 435 littleEndian) { 436 return GL_TRUE; 437 } 438 else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 && 439 format == GL_BGRA && 440 type == GL_UNSIGNED_BYTE && 441 littleEndian) { 442 return GL_TRUE; 443 } 444 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 && 445 format == GL_RGB && 446 type == GL_UNSIGNED_SHORT_5_6_5) { 447 /* endian don't care */ 448 return GL_TRUE; 449 } 450 else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 && 451 format == GL_BGR && 452 type == GL_UNSIGNED_SHORT_5_6_5_REV) { 453 /* endian don't care */ 454 return GL_TRUE; 455 } 456 else if (pipeFormat == PIPE_FORMAT_U_S8 && 457 format == GL_STENCIL_INDEX && 458 type == GL_UNSIGNED_BYTE) { 459 return GL_TRUE; 460 } 461 else if (pipeFormat == PIPE_FORMAT_U_Z32 && 462 format == GL_DEPTH_COMPONENT && 463 type == GL_UNSIGNED_INT) { 464 return GL_TRUE; 465 } 466 /* XXX add more cases */ 467 else { 468 return GL_FALSE; 469 } 470} 471 472 473/** 474 * Check if any per-fragment ops are enabled. 475 * XXX probably move this to a re-usable place. 476 */ 477static GLboolean 478any_fragment_ops(const struct st_context *st) 479{ 480 if (st->state.alpha_test.enabled || 481 st->state.blend->blend_enable || 482 st->state.blend->logicop_enable || 483 st->state.depth_stencil->depth.enabled) 484 /* XXX more checks */ 485 return GL_TRUE; 486 else 487 return GL_FALSE; 488} 489 490 491/** 492 * Check if any pixel transfer ops are enabled. 493 * XXX probably move this to a re-usable place. 494 */ 495static GLboolean 496any_pixel_transfer_ops(const struct st_context *st) 497{ 498 if (st->ctx->Pixel.RedScale != 1.0 || 499 st->ctx->Pixel.RedBias != 0.0 || 500 st->ctx->Pixel.GreenScale != 1.0 || 501 st->ctx->Pixel.GreenBias != 0.0 || 502 st->ctx->Pixel.BlueScale != 1.0 || 503 st->ctx->Pixel.BlueBias != 0.0 || 504 st->ctx->Pixel.AlphaScale != 1.0 || 505 st->ctx->Pixel.AlphaBias != 0.0 || 506 st->ctx->Pixel.MapColorFlag) 507 /* XXX more checks */ 508 return GL_TRUE; 509 else 510 return GL_FALSE; 511} 512 513 514/** 515 * Draw image with a blit, or other non-textured quad method. 516 */ 517static void 518draw_blit(struct st_context *st, 519 GLsizei width, GLsizei height, 520 GLenum format, GLenum type, const GLvoid *pixels) 521{ 522 523 524} 525 526 527/** 528 * Called via ctx->Driver.DrawPixels() 529 */ 530static void 531st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, 532 GLenum format, GLenum type, 533 const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) 534{ 535 struct st_context *st = ctx->st; 536 struct pipe_surface *ps; 537 GLuint bufferFormat; 538 539 st_validate_state(st); 540 541 if (format == GL_DEPTH_COMPONENT) { 542 ps = st->state.framebuffer.zbuf; 543 } 544 else if (format == GL_STENCIL_INDEX) { 545 ps = st->state.framebuffer.sbuf; 546 } 547 else { 548 ps = st->state.framebuffer.cbufs[0]; 549 } 550 551 bufferFormat = ps->format; 552 553 if (any_fragment_ops(st) || 554 any_pixel_transfer_ops(st) || 555 !compatible_formats(format, type, ps->format)) { 556 /* textured quad */ 557 draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], width, height, 558 format, type, unpack, pixels); 559 } 560 else { 561 /* blit */ 562 draw_blit(st, width, height, format, type, pixels); 563 } 564} 565 566 567static void 568st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, 569 const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) 570{ 571 struct st_context *st = ctx->st; 572 573 st_validate_state(st); 574 575 fprintf(stderr, "st_Bitmap not implemented yet\n"); 576 /* XXX to do */ 577} 578 579 580static void 581st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, 582 GLsizei width, GLsizei height, 583 GLint dstx, GLint dsty, GLenum type) 584{ 585 struct st_context *st = ctx->st; 586 587 st_validate_state(st); 588 589 fprintf(stderr, "st_CopyPixels not implemented yet\n"); 590 /* XXX to do */ 591} 592 593 594 595void st_init_drawpixels_functions(struct dd_function_table *functions) 596{ 597 functions->DrawPixels = st_DrawPixels; 598 functions->CopyPixels = st_CopyPixels; 599 functions->Bitmap = st_Bitmap; 600} 601