st_texture.c revision f5bd93fae2e4f46665eb1f09ca64cb39ff2b8a79
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#include "st_context.h" 29#include "st_format.h" 30#include "st_public.h" 31#include "st_texture.h" 32#include "st_cb_fbo.h" 33#include "st_inlines.h" 34#include "main/enums.h" 35#include "main/texfetch.h" 36#include "main/teximage.h" 37#include "main/texobj.h" 38#include "main/texstore.h" 39 40#undef Elements /* fix re-defined macro warning */ 41 42#include "pipe/p_state.h" 43#include "pipe/p_context.h" 44#include "pipe/p_defines.h" 45#include "pipe/p_inlines.h" 46#include "util/u_format.h" 47#include "util/u_rect.h" 48#include "util/u_math.h" 49 50 51#define DBG if(0) printf 52 53#if 0 54static GLenum 55target_to_target(GLenum target) 56{ 57 switch (target) { 58 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 59 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 60 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 61 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 62 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 63 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 64 return GL_TEXTURE_CUBE_MAP_ARB; 65 default: 66 return target; 67 } 68} 69#endif 70 71 72/** 73 * Allocate a new pipe_texture object 74 * width0, height0, depth0 are the dimensions of the level 0 image 75 * (the highest resolution). last_level indicates how many mipmap levels 76 * to allocate storage for. For non-mipmapped textures, this will be zero. 77 */ 78struct pipe_texture * 79st_texture_create(struct st_context *st, 80 enum pipe_texture_target target, 81 enum pipe_format format, 82 GLuint last_level, 83 GLuint width0, 84 GLuint height0, 85 GLuint depth0, 86 GLuint usage ) 87{ 88 struct pipe_texture pt, *newtex; 89 struct pipe_screen *screen = st->pipe->screen; 90 91 assert(target <= PIPE_TEXTURE_CUBE); 92 93 DBG("%s target %s format %s last_level %d\n", __FUNCTION__, 94 _mesa_lookup_enum_by_nr(target), 95 _mesa_lookup_enum_by_nr(format), last_level); 96 97 assert(format); 98 assert(screen->is_format_supported(screen, format, target, 99 PIPE_TEXTURE_USAGE_SAMPLER, 0)); 100 101 memset(&pt, 0, sizeof(pt)); 102 pt.target = target; 103 pt.format = format; 104 pt.last_level = last_level; 105 pt.width0 = width0; 106 pt.height0 = height0; 107 pt.depth0 = depth0; 108 util_format_get_block(format, &pt.block); 109 pt.tex_usage = usage; 110 111 newtex = screen->texture_create(screen, &pt); 112 113 assert(!newtex || pipe_is_referenced(&newtex->reference)); 114 115 return newtex; 116} 117 118 119/** 120 * Check if a texture image can be pulled into a unified mipmap texture. 121 */ 122GLboolean 123st_texture_match_image(const struct pipe_texture *pt, 124 const struct gl_texture_image *image, 125 GLuint face, GLuint level) 126{ 127 /* Images with borders are never pulled into mipmap textures. 128 */ 129 if (image->Border) 130 return GL_FALSE; 131 132 /* Check if this image's format matches the established texture's format. 133 */ 134 if (st_mesa_format_to_pipe_format(image->TexFormat) != pt->format) 135 return GL_FALSE; 136 137 /* Test if this image's size matches what's expected in the 138 * established texture. 139 */ 140 if (image->Width != u_minify(pt->width0, level) || 141 image->Height != u_minify(pt->height0, level) || 142 image->Depth != u_minify(pt->depth0, level)) 143 return GL_FALSE; 144 145 return GL_TRUE; 146} 147 148 149#if 000 150/* Although we use the image_offset[] array to store relative offsets 151 * to cube faces, Mesa doesn't know anything about this and expects 152 * each cube face to be treated as a separate image. 153 * 154 * These functions present that view to mesa: 155 */ 156const GLuint * 157st_texture_depth_offsets(struct pipe_texture *pt, GLuint level) 158{ 159 static const GLuint zero = 0; 160 161 if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1) 162 return &zero; 163 else 164 return pt->level[level].image_offset; 165} 166 167 168/** 169 * Return the offset to the given mipmap texture image within the 170 * texture memory buffer, in bytes. 171 */ 172GLuint 173st_texture_image_offset(const struct pipe_texture * pt, 174 GLuint face, GLuint level) 175{ 176 if (pt->target == PIPE_TEXTURE_CUBE) 177 return (pt->level[level].level_offset + 178 pt->level[level].image_offset[face] * pt->cpp); 179 else 180 return pt->level[level].level_offset; 181} 182#endif 183 184 185/** 186 * Map a teximage in a mipmap texture. 187 * \param row_stride returns row stride in bytes 188 * \param image_stride returns image stride in bytes (for 3D textures). 189 * \return address of mapping 190 */ 191GLubyte * 192st_texture_image_map(struct st_context *st, struct st_texture_image *stImage, 193 GLuint zoffset, enum pipe_transfer_usage usage, 194 GLuint x, GLuint y, GLuint w, GLuint h) 195{ 196 struct pipe_context *pipe = st->pipe; 197 struct pipe_screen *screen = pipe->screen; 198 struct pipe_texture *pt = stImage->pt; 199 200 DBG("%s \n", __FUNCTION__); 201 202 stImage->transfer = st_no_flush_get_tex_transfer(st, pt, stImage->face, 203 stImage->level, zoffset, 204 usage, x, y, w, h); 205 206 if (stImage->transfer) 207 return screen->transfer_map(screen, stImage->transfer); 208 else 209 return NULL; 210} 211 212 213void 214st_texture_image_unmap(struct st_context *st, 215 struct st_texture_image *stImage) 216{ 217 struct pipe_screen *screen = st->pipe->screen; 218 219 DBG("%s\n", __FUNCTION__); 220 221 screen->transfer_unmap(screen, stImage->transfer); 222 223 screen->tex_transfer_destroy(stImage->transfer); 224} 225 226 227 228/** 229 * Upload data to a rectangular sub-region. Lots of choices how to do this: 230 * 231 * - memcpy by span to current destination 232 * - upload data as new buffer and blit 233 * 234 * Currently always memcpy. 235 */ 236static void 237st_surface_data(struct pipe_context *pipe, 238 struct pipe_transfer *dst, 239 unsigned dstx, unsigned dsty, 240 const void *src, unsigned src_stride, 241 unsigned srcx, unsigned srcy, unsigned width, unsigned height) 242{ 243 struct pipe_screen *screen = pipe->screen; 244 void *map = screen->transfer_map(screen, dst); 245 246 util_copy_rect(map, 247 &dst->block, 248 dst->stride, 249 dstx, dsty, 250 width, height, 251 src, src_stride, 252 srcx, srcy); 253 254 screen->transfer_unmap(screen, dst); 255} 256 257 258/* Upload data for a particular image. 259 */ 260void 261st_texture_image_data(struct st_context *st, 262 struct pipe_texture *dst, 263 GLuint face, 264 GLuint level, 265 void *src, 266 GLuint src_row_stride, GLuint src_image_stride) 267{ 268 struct pipe_context *pipe = st->pipe; 269 struct pipe_screen *screen = pipe->screen; 270 GLuint depth = u_minify(dst->depth0, level); 271 GLuint i; 272 const GLubyte *srcUB = src; 273 struct pipe_transfer *dst_transfer; 274 275 DBG("%s\n", __FUNCTION__); 276 277 for (i = 0; i < depth; i++) { 278 dst_transfer = st_no_flush_get_tex_transfer(st, dst, face, level, i, 279 PIPE_TRANSFER_WRITE, 0, 0, 280 u_minify(dst->width0, level), 281 u_minify(dst->height0, level)); 282 283 st_surface_data(pipe, dst_transfer, 284 0, 0, /* dstx, dsty */ 285 srcUB, 286 src_row_stride, 287 0, 0, /* source x, y */ 288 u_minify(dst->width0, level), 289 u_minify(dst->height0, level)); /* width, height */ 290 291 screen->tex_transfer_destroy(dst_transfer); 292 293 srcUB += src_image_stride; 294 } 295} 296 297 298/* Copy mipmap image between textures 299 */ 300void 301st_texture_image_copy(struct pipe_context *pipe, 302 struct pipe_texture *dst, GLuint dstLevel, 303 struct pipe_texture *src, 304 GLuint face) 305{ 306 struct pipe_screen *screen = pipe->screen; 307 GLuint width = u_minify(dst->width0, dstLevel); 308 GLuint height = u_minify(dst->height0, dstLevel); 309 GLuint depth = u_minify(dst->depth0, dstLevel); 310 struct pipe_surface *src_surface; 311 struct pipe_surface *dst_surface; 312 GLuint i; 313 314 for (i = 0; i < depth; i++) { 315 GLuint srcLevel; 316 317 /* find src texture level of needed size */ 318 for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) { 319 if (u_minify(src->width0, srcLevel) == width && 320 u_minify(src->height0, srcLevel) == height) { 321 break; 322 } 323 } 324 assert(u_minify(src->width0, srcLevel) == width); 325 assert(u_minify(src->height0, srcLevel) == height); 326 327#if 0 328 { 329 src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i, 330 PIPE_BUFFER_USAGE_CPU_READ); 331 ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ); 332 map += src_surface->width * src_surface->height * 4 / 2; 333 printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n", 334 __FUNCTION__, 335 map[0], map[1], map[2], map[3], 336 src, srcLevel, dst, dstLevel); 337 338 screen->surface_unmap(screen, src_surface); 339 pipe_surface_reference(&src_surface, NULL); 340 } 341#endif 342 343 dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i, 344 PIPE_BUFFER_USAGE_GPU_WRITE); 345 346 src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i, 347 PIPE_BUFFER_USAGE_GPU_READ); 348 349 if (pipe->surface_copy) { 350 pipe->surface_copy(pipe, 351 dst_surface, 352 0, 0, /* destX, Y */ 353 src_surface, 354 0, 0, /* srcX, Y */ 355 width, height); 356 } else { 357 util_surface_copy(pipe, FALSE, 358 dst_surface, 359 0, 0, /* destX, Y */ 360 src_surface, 361 0, 0, /* srcX, Y */ 362 width, height); 363 } 364 365 pipe_surface_reference(&src_surface, NULL); 366 pipe_surface_reference(&dst_surface, NULL); 367 } 368} 369 370 371/** 372 * Bind a pipe surface to a texture object. After the call, 373 * the texture object is marked dirty and will be (re-)validated. 374 * 375 * If this is the first surface bound, the texture object is said to 376 * switch from normal to surface based. It will be cleared first in 377 * this case. 378 * 379 * \param ps pipe surface to be unbound 380 * \param target texture target 381 * \param level image level 382 * \param format internal format of the texture 383 */ 384int 385st_bind_texture_surface(struct pipe_surface *ps, int target, int level, 386 enum pipe_format format) 387{ 388 GET_CURRENT_CONTEXT(ctx); 389 const GLuint unit = ctx->Texture.CurrentUnit; 390 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 391 struct gl_texture_object *texObj; 392 struct gl_texture_image *texImage; 393 struct st_texture_object *stObj; 394 struct st_texture_image *stImage; 395 GLenum internalFormat; 396 397 switch (target) { 398 case ST_TEXTURE_2D: 399 target = GL_TEXTURE_2D; 400 break; 401 case ST_TEXTURE_RECT: 402 target = GL_TEXTURE_RECTANGLE_ARB; 403 break; 404 default: 405 return 0; 406 } 407 408 /* map pipe format to base format for now */ 409 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) 410 internalFormat = GL_RGBA; 411 else 412 internalFormat = GL_RGB; 413 414 texObj = _mesa_select_tex_object(ctx, texUnit, target); 415 _mesa_lock_texture(ctx, texObj); 416 417 stObj = st_texture_object(texObj); 418 /* switch to surface based */ 419 if (!stObj->surface_based) { 420 _mesa_clear_texture_object(ctx, texObj); 421 stObj->surface_based = GL_TRUE; 422 } 423 424 texImage = _mesa_get_tex_image(ctx, texObj, target, level); 425 stImage = st_texture_image(texImage); 426 427 _mesa_init_teximage_fields(ctx, target, texImage, 428 ps->width, ps->height, 1, 0, internalFormat); 429 texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat, 430 GL_RGBA, GL_UNSIGNED_BYTE); 431 _mesa_set_fetch_functions(texImage, 2); 432 pipe_texture_reference(&stImage->pt, ps->texture); 433 434 _mesa_dirty_texobj(ctx, texObj, GL_TRUE); 435 _mesa_unlock_texture(ctx, texObj); 436 437 return 1; 438} 439 440 441/** 442 * Unbind a pipe surface from a texture object. After the call, 443 * the texture object is marked dirty and will be (re-)validated. 444 * 445 * \param ps pipe surface to be unbound 446 * \param target texture target 447 * \param level image level 448 */ 449int 450st_unbind_texture_surface(struct pipe_surface *ps, int target, int level) 451{ 452 GET_CURRENT_CONTEXT(ctx); 453 const GLuint unit = ctx->Texture.CurrentUnit; 454 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 455 struct gl_texture_object *texObj; 456 struct gl_texture_image *texImage; 457 struct st_texture_object *stObj; 458 struct st_texture_image *stImage; 459 460 switch (target) { 461 case ST_TEXTURE_2D: 462 target = GL_TEXTURE_2D; 463 break; 464 case ST_TEXTURE_RECT: 465 target = GL_TEXTURE_RECTANGLE_ARB; 466 break; 467 default: 468 return 0; 469 } 470 471 texObj = _mesa_select_tex_object(ctx, texUnit, target); 472 473 _mesa_lock_texture(ctx, texObj); 474 475 texImage = _mesa_get_tex_image(ctx, texObj, target, level); 476 stObj = st_texture_object(texObj); 477 stImage = st_texture_image(texImage); 478 479 /* Make sure the pipe surface is still bound. The texture object is still 480 * considered surface based even if this is the last bound surface. */ 481 if (stImage->pt == ps->texture) { 482 pipe_texture_reference(&stImage->pt, NULL); 483 _mesa_clear_texture_image(ctx, texImage); 484 485 _mesa_dirty_texobj(ctx, texObj, GL_TRUE); 486 } 487 488 _mesa_unlock_texture(ctx, texObj); 489 490 return 1; 491} 492 493 494/** Redirect rendering into stfb's surface to a texture image */ 495int 496st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex, 497 int target, int format, int level) 498{ 499 GET_CURRENT_CONTEXT(ctx); 500 struct st_context *st = ctx->st; 501 struct pipe_context *pipe = st->pipe; 502 struct pipe_screen *screen = pipe->screen; 503 const GLuint unit = ctx->Texture.CurrentUnit; 504 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 505 struct gl_texture_object *texObj; 506 struct gl_texture_image *texImage; 507 struct st_texture_image *stImage; 508 struct st_renderbuffer *strb; 509 GLint face = 0, slice = 0; 510 511 assert(surfIndex <= ST_SURFACE_DEPTH); 512 513 strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); 514 515 if (strb->texture_save || strb->surface_save) { 516 /* Error! */ 517 return 0; 518 } 519 520 if (target == ST_TEXTURE_2D) { 521 texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX]; 522 texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level); 523 stImage = st_texture_image(texImage); 524 } 525 else { 526 /* unsupported target */ 527 return 0; 528 } 529 530 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); 531 532 /* save the renderbuffer's surface/texture info */ 533 pipe_texture_reference(&strb->texture_save, strb->texture); 534 pipe_surface_reference(&strb->surface_save, strb->surface); 535 536 /* plug in new surface/texture info */ 537 pipe_texture_reference(&strb->texture, stImage->pt); 538 strb->surface = screen->get_tex_surface(screen, strb->texture, 539 face, level, slice, 540 (PIPE_BUFFER_USAGE_GPU_READ | 541 PIPE_BUFFER_USAGE_GPU_WRITE)); 542 543 st->dirty.st |= ST_NEW_FRAMEBUFFER; 544 545 return 1; 546} 547 548 549/** Undo surface-to-texture binding */ 550int 551st_release_teximage(struct st_framebuffer *stfb, uint surfIndex, 552 int target, int format, int level) 553{ 554 GET_CURRENT_CONTEXT(ctx); 555 struct st_context *st = ctx->st; 556 struct st_renderbuffer *strb; 557 558 assert(surfIndex <= ST_SURFACE_DEPTH); 559 560 strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); 561 562 if (!strb->texture_save || !strb->surface_save) { 563 /* Error! */ 564 return 0; 565 } 566 567 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); 568 569 /* free tex surface, restore original */ 570 pipe_surface_reference(&strb->surface, strb->surface_save); 571 pipe_texture_reference(&strb->texture, strb->texture_save); 572 573 pipe_surface_reference(&strb->surface_save, NULL); 574 pipe_texture_reference(&strb->texture_save, NULL); 575 576 st->dirty.st |= ST_NEW_FRAMEBUFFER; 577 578 return 1; 579} 580 581void 582st_teximage_flush_before_map(struct st_context *st, 583 struct pipe_texture *pt, 584 unsigned int face, 585 unsigned int level, 586 enum pipe_transfer_usage usage) 587{ 588 struct pipe_context *pipe = st->pipe; 589 unsigned referenced = 590 pipe->is_texture_referenced(pipe, pt, face, level); 591 592 if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) || 593 (usage & PIPE_TRANSFER_WRITE))) 594 st->pipe->flush(st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 595} 596