st_texture.c revision 287c94ea4987033f9c99a2f91c5750c9083504ca
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 39#undef Elements /* fix re-defined macro warning */ 40 41#include "pipe/p_state.h" 42#include "pipe/p_context.h" 43#include "pipe/p_defines.h" 44#include "util/u_inlines.h" 45#include "util/u_format.h" 46#include "util/u_rect.h" 47#include "util/u_math.h" 48 49 50#define DBG if(0) printf 51 52#if 0 53static GLenum 54target_to_target(GLenum target) 55{ 56 switch (target) { 57 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 58 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 59 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 60 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 61 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 62 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 63 return GL_TEXTURE_CUBE_MAP_ARB; 64 default: 65 return target; 66 } 67} 68#endif 69 70 71/** 72 * Allocate a new pipe_resource object 73 * width0, height0, depth0 are the dimensions of the level 0 image 74 * (the highest resolution). last_level indicates how many mipmap levels 75 * to allocate storage for. For non-mipmapped textures, this will be zero. 76 */ 77struct pipe_resource * 78st_texture_create(struct st_context *st, 79 enum pipe_texture_target target, 80 enum pipe_format format, 81 GLuint last_level, 82 GLuint width0, 83 GLuint height0, 84 GLuint depth0, 85 GLuint bind ) 86{ 87 struct pipe_resource pt, *newtex; 88 struct pipe_screen *screen = st->pipe->screen; 89 90 assert(target <= PIPE_TEXTURE_CUBE); 91 92 DBG("%s target %s format %s last_level %d\n", __FUNCTION__, 93 _mesa_lookup_enum_by_nr(target), 94 _mesa_lookup_enum_by_nr(format), last_level); 95 96 assert(format); 97 assert(screen->is_format_supported(screen, format, target, 98 PIPE_BIND_SAMPLER_VIEW, 0)); 99 100 memset(&pt, 0, sizeof(pt)); 101 pt.target = target; 102 pt.format = format; 103 pt.last_level = last_level; 104 pt.width0 = width0; 105 pt.height0 = height0; 106 pt.depth0 = depth0; 107 pt._usage = PIPE_USAGE_DEFAULT; 108 pt.bind = bind; 109 pt.flags = 0; 110 111 newtex = screen->resource_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_resource *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_resource *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_resource * 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_resource *pt = stImage->pt; 198 199 DBG("%s \n", __FUNCTION__); 200 201 stImage->transfer = st_no_flush_get_tex_transfer(st, pt, stImage->face, 202 stImage->level, zoffset, 203 usage, x, y, w, h); 204 205 if (stImage->transfer) 206 return pipe_transfer_map(pipe, stImage->transfer); 207 else 208 return NULL; 209} 210 211 212void 213st_texture_image_unmap(struct st_context *st, 214 struct st_texture_image *stImage) 215{ 216 struct pipe_context *pipe = st->pipe; 217 218 DBG("%s\n", __FUNCTION__); 219 220 pipe_transfer_unmap(pipe, stImage->transfer); 221 222 pipe->transfer_destroy(pipe, stImage->transfer); 223} 224 225 226 227/** 228 * Upload data to a rectangular sub-region. Lots of choices how to do this: 229 * 230 * - memcpy by span to current destination 231 * - upload data as new buffer and blit 232 * 233 * Currently always memcpy. 234 */ 235static void 236st_surface_data(struct pipe_context *pipe, 237 struct pipe_transfer *dst, 238 unsigned dstx, unsigned dsty, 239 const void *src, unsigned src_stride, 240 unsigned srcx, unsigned srcy, unsigned width, unsigned height) 241{ 242 void *map = pipe_transfer_map(pipe, dst); 243 244 assert(dst->resource); 245 util_copy_rect(map, 246 dst->resource->format, 247 dst->stride, 248 dstx, dsty, 249 width, height, 250 src, src_stride, 251 srcx, srcy); 252 253 pipe_transfer_unmap(pipe, dst); 254} 255 256 257/* Upload data for a particular image. 258 */ 259void 260st_texture_image_data(struct st_context *st, 261 struct pipe_resource *dst, 262 GLuint face, 263 GLuint level, 264 void *src, 265 GLuint src_row_stride, GLuint src_image_stride) 266{ 267 struct pipe_context *pipe = st->pipe; 268 GLuint depth = u_minify(dst->depth0, level); 269 GLuint i; 270 const GLubyte *srcUB = src; 271 struct pipe_transfer *dst_transfer; 272 273 DBG("%s\n", __FUNCTION__); 274 275 for (i = 0; i < depth; i++) { 276 dst_transfer = st_no_flush_get_tex_transfer(st, dst, face, level, i, 277 PIPE_TRANSFER_WRITE, 0, 0, 278 u_minify(dst->width0, level), 279 u_minify(dst->height0, level)); 280 281 st_surface_data(pipe, dst_transfer, 282 0, 0, /* dstx, dsty */ 283 srcUB, 284 src_row_stride, 285 0, 0, /* source x, y */ 286 u_minify(dst->width0, level), 287 u_minify(dst->height0, level)); /* width, height */ 288 289 pipe->transfer_destroy(pipe, dst_transfer); 290 291 srcUB += src_image_stride; 292 } 293} 294 295 296/* Copy mipmap image between textures 297 */ 298void 299st_texture_image_copy(struct pipe_context *pipe, 300 struct pipe_resource *dst, GLuint dstLevel, 301 struct pipe_resource *src, 302 GLuint face) 303{ 304 struct pipe_screen *screen = pipe->screen; 305 GLuint width = u_minify(dst->width0, dstLevel); 306 GLuint height = u_minify(dst->height0, dstLevel); 307 GLuint depth = u_minify(dst->depth0, dstLevel); 308 struct pipe_surface *src_surface; 309 struct pipe_surface *dst_surface; 310 GLuint i; 311 312 for (i = 0; i < depth; i++) { 313 GLuint srcLevel; 314 315 /* find src texture level of needed size */ 316 for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) { 317 if (u_minify(src->width0, srcLevel) == width && 318 u_minify(src->height0, srcLevel) == height) { 319 break; 320 } 321 } 322 assert(u_minify(src->width0, srcLevel) == width); 323 assert(u_minify(src->height0, srcLevel) == height); 324 325#if 0 326 { 327 src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i, 328 PIPE_BUFFER_USAGE_CPU_READ); 329 ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ); 330 map += src_surface->width * src_surface->height * 4 / 2; 331 printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n", 332 __FUNCTION__, 333 map[0], map[1], map[2], map[3], 334 src, srcLevel, dst, dstLevel); 335 336 screen->surface_unmap(screen, src_surface); 337 pipe_surface_reference(&src_surface, NULL); 338 } 339#endif 340 341 dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i, 342 PIPE_BIND_BLIT_DESTINATION); 343 344 src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i, 345 PIPE_BIND_BLIT_SOURCE); 346 347 pipe->surface_copy(pipe, 348 dst_surface, 349 0, 0, /* destX, Y */ 350 src_surface, 351 0, 0, /* srcX, Y */ 352 width, height); 353 354 pipe_surface_reference(&src_surface, NULL); 355 pipe_surface_reference(&dst_surface, NULL); 356 } 357} 358 359 360/** 361 * Bind a pipe surface to a texture object. After the call, 362 * the texture object is marked dirty and will be (re-)validated. 363 * 364 * If this is the first surface bound, the texture object is said to 365 * switch from normal to surface based. It will be cleared first in 366 * this case. 367 * 368 * \param ps pipe surface to be unbound 369 * \param target texture target 370 * \param level image level 371 * \param format internal format of the texture 372 */ 373int 374st_bind_texture_surface(struct pipe_surface *ps, int target, int level, 375 enum pipe_format format) 376{ 377 GET_CURRENT_CONTEXT(ctx); 378 const GLuint unit = ctx->Texture.CurrentUnit; 379 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 380 struct gl_texture_object *texObj; 381 struct gl_texture_image *texImage; 382 struct st_texture_object *stObj; 383 struct st_texture_image *stImage; 384 GLenum internalFormat; 385 386 switch (target) { 387 case ST_TEXTURE_2D: 388 target = GL_TEXTURE_2D; 389 break; 390 case ST_TEXTURE_RECT: 391 target = GL_TEXTURE_RECTANGLE_ARB; 392 break; 393 default: 394 return 0; 395 } 396 397 /* map pipe format to base format for now */ 398 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) 399 internalFormat = GL_RGBA; 400 else 401 internalFormat = GL_RGB; 402 403 texObj = _mesa_select_tex_object(ctx, texUnit, target); 404 _mesa_lock_texture(ctx, texObj); 405 406 stObj = st_texture_object(texObj); 407 /* switch to surface based */ 408 if (!stObj->surface_based) { 409 _mesa_clear_texture_object(ctx, texObj); 410 stObj->surface_based = GL_TRUE; 411 } 412 413 texImage = _mesa_get_tex_image(ctx, texObj, target, level); 414 stImage = st_texture_image(texImage); 415 416 _mesa_init_teximage_fields(ctx, target, texImage, 417 ps->width, ps->height, 1, 0, internalFormat); 418 texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat, 419 GL_RGBA, GL_UNSIGNED_BYTE); 420 _mesa_set_fetch_functions(texImage, 2); 421 pipe_resource_reference(&stImage->pt, ps->texture); 422 423 _mesa_dirty_texobj(ctx, texObj, GL_TRUE); 424 _mesa_unlock_texture(ctx, texObj); 425 426 return 1; 427} 428 429 430/** 431 * Unbind a pipe surface from a texture object. After the call, 432 * the texture object is marked dirty and will be (re-)validated. 433 * 434 * \param ps pipe surface to be unbound 435 * \param target texture target 436 * \param level image level 437 */ 438int 439st_unbind_texture_surface(struct pipe_surface *ps, int target, int level) 440{ 441 GET_CURRENT_CONTEXT(ctx); 442 const GLuint unit = ctx->Texture.CurrentUnit; 443 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 444 struct gl_texture_object *texObj; 445 struct gl_texture_image *texImage; 446 struct st_texture_object *stObj; 447 struct st_texture_image *stImage; 448 449 switch (target) { 450 case ST_TEXTURE_2D: 451 target = GL_TEXTURE_2D; 452 break; 453 case ST_TEXTURE_RECT: 454 target = GL_TEXTURE_RECTANGLE_ARB; 455 break; 456 default: 457 return 0; 458 } 459 460 texObj = _mesa_select_tex_object(ctx, texUnit, target); 461 462 _mesa_lock_texture(ctx, texObj); 463 464 texImage = _mesa_get_tex_image(ctx, texObj, target, level); 465 stObj = st_texture_object(texObj); 466 stImage = st_texture_image(texImage); 467 468 /* Make sure the pipe surface is still bound. The texture object is still 469 * considered surface based even if this is the last bound surface. */ 470 if (stImage->pt == ps->texture) { 471 pipe_resource_reference(&stImage->pt, NULL); 472 _mesa_clear_texture_image(ctx, texImage); 473 474 _mesa_dirty_texobj(ctx, texObj, GL_TRUE); 475 } 476 477 _mesa_unlock_texture(ctx, texObj); 478 479 return 1; 480} 481 482 483/** Redirect rendering into stfb's surface to a texture image */ 484int 485st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex, 486 int target, int format, int level) 487{ 488 GET_CURRENT_CONTEXT(ctx); 489 struct st_context *st = ctx->st; 490 struct pipe_context *pipe = st->pipe; 491 struct pipe_screen *screen = pipe->screen; 492 const GLuint unit = ctx->Texture.CurrentUnit; 493 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 494 struct gl_texture_object *texObj; 495 struct gl_texture_image *texImage; 496 struct st_texture_image *stImage; 497 struct st_renderbuffer *strb; 498 GLint face = 0, slice = 0; 499 500 assert(surfIndex <= ST_SURFACE_DEPTH); 501 502 strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); 503 504 if (strb->texture_save || strb->surface_save) { 505 /* Error! */ 506 return 0; 507 } 508 509 if (target == ST_TEXTURE_2D) { 510 texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX]; 511 texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level); 512 stImage = st_texture_image(texImage); 513 } 514 else { 515 /* unsupported target */ 516 return 0; 517 } 518 519 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); 520 521 /* save the renderbuffer's surface/texture info */ 522 pipe_resource_reference(&strb->texture_save, strb->texture); 523 pipe_surface_reference(&strb->surface_save, strb->surface); 524 pipe_sampler_view_reference(&strb->sampler_view_save, strb->sampler_view); 525 526 /* plug in new surface/texture info */ 527 pipe_resource_reference(&strb->texture, stImage->pt); 528 529 /* XXX: Shouldn't we release reference to old surface here? 530 */ 531 532 strb->surface = screen->get_tex_surface(screen, strb->texture, 533 face, level, slice, 534 (PIPE_BIND_RENDER_TARGET | 535 PIPE_BIND_BLIT_SOURCE | 536 PIPE_BIND_BLIT_DESTINATION)); 537 538 pipe_sampler_view_reference(&strb->sampler_view, NULL); 539 540 st->dirty.st |= ST_NEW_FRAMEBUFFER; 541 542 return 1; 543} 544 545 546/** Undo surface-to-texture binding */ 547int 548st_release_teximage(struct st_framebuffer *stfb, uint surfIndex, 549 int target, int format, int level) 550{ 551 GET_CURRENT_CONTEXT(ctx); 552 struct st_context *st = ctx->st; 553 struct st_renderbuffer *strb; 554 555 assert(surfIndex <= ST_SURFACE_DEPTH); 556 557 strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); 558 559 if (!strb->texture_save || !strb->surface_save) { 560 /* Error! */ 561 return 0; 562 } 563 564 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); 565 566 /* free tex surface, restore original */ 567 pipe_surface_reference(&strb->surface, strb->surface_save); 568 pipe_resource_reference(&strb->texture, strb->texture_save); 569 pipe_sampler_view_reference(&strb->sampler_view, strb->sampler_view_save); 570 571 pipe_surface_reference(&strb->surface_save, NULL); 572 pipe_resource_reference(&strb->texture_save, NULL); 573 pipe_sampler_view_reference(&strb->sampler_view, NULL); 574 575 st->dirty.st |= ST_NEW_FRAMEBUFFER; 576 577 return 1; 578} 579 580void 581st_teximage_flush_before_map(struct st_context *st, 582 struct pipe_resource *pt, 583 unsigned int face, 584 unsigned int level, 585 enum pipe_transfer_usage usage) 586{ 587 struct pipe_context *pipe = st->pipe; 588 unsigned referenced = 589 pipe->is_resource_referenced(pipe, pt, face, level); 590 591 if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) || 592 (usage & PIPE_TRANSFER_WRITE))) 593 st->pipe->flush(st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 594} 595