sp_texture.c revision cdc920a0
1/************************************************************************** 2 * 3 * Copyright 2006 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 * Authors: 29 * Keith Whitwell <keith@tungstengraphics.com> 30 * Michel Dänzer <michel@tungstengraphics.com> 31 */ 32 33#include "pipe/p_defines.h" 34#include "util/u_inlines.h" 35 36#include "util/u_format.h" 37#include "util/u_math.h" 38#include "util/u_memory.h" 39 40#include "sp_context.h" 41#include "sp_texture.h" 42#include "sp_screen.h" 43#include "sp_winsys.h" 44 45 46/** 47 * Conventional allocation path for non-display textures: 48 * Use a simple, maximally packed layout. 49 */ 50static boolean 51softpipe_texture_layout(struct pipe_screen *screen, 52 struct softpipe_texture * spt) 53{ 54 struct pipe_texture *pt = &spt->base; 55 unsigned level; 56 unsigned width = pt->width0; 57 unsigned height = pt->height0; 58 unsigned depth = pt->depth0; 59 unsigned buffer_size = 0; 60 61 for (level = 0; level <= pt->last_level; level++) { 62 spt->stride[level] = util_format_get_stride(pt->format, width); 63 64 spt->level_offset[level] = buffer_size; 65 66 buffer_size += (util_format_get_nblocksy(pt->format, height) * 67 ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) * 68 spt->stride[level]); 69 70 width = u_minify(width, 1); 71 height = u_minify(height, 1); 72 depth = u_minify(depth, 1); 73 } 74 75 spt->buffer = screen->buffer_create(screen, 32, 76 PIPE_BUFFER_USAGE_PIXEL, 77 buffer_size); 78 79 return spt->buffer != NULL; 80} 81 82 83/** 84 * Texture layout for simple color buffers. 85 */ 86static boolean 87softpipe_displaytarget_layout(struct pipe_screen *screen, 88 struct softpipe_texture * spt) 89{ 90 unsigned usage = (PIPE_BUFFER_USAGE_CPU_READ_WRITE | 91 PIPE_BUFFER_USAGE_GPU_READ_WRITE); 92 unsigned tex_usage = spt->base.tex_usage; 93 94 spt->buffer = screen->surface_buffer_create( screen, 95 spt->base.width0, 96 spt->base.height0, 97 spt->base.format, 98 usage, 99 tex_usage, 100 &spt->stride[0]); 101 102 return spt->buffer != NULL; 103} 104 105 106/** 107 * Create new pipe_texture given the template information. 108 */ 109static struct pipe_texture * 110softpipe_texture_create(struct pipe_screen *screen, 111 const struct pipe_texture *template) 112{ 113 struct softpipe_texture *spt = CALLOC_STRUCT(softpipe_texture); 114 if (!spt) 115 return NULL; 116 117 spt->base = *template; 118 pipe_reference_init(&spt->base.reference, 1); 119 spt->base.screen = screen; 120 121 spt->pot = (util_is_power_of_two(template->width0) && 122 util_is_power_of_two(template->height0) && 123 util_is_power_of_two(template->depth0)); 124 125 if (spt->base.tex_usage & (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | 126 PIPE_TEXTURE_USAGE_PRIMARY)) { 127 if (!softpipe_displaytarget_layout(screen, spt)) 128 goto fail; 129 } 130 else { 131 if (!softpipe_texture_layout(screen, spt)) 132 goto fail; 133 } 134 135 return &spt->base; 136 137 fail: 138 FREE(spt); 139 return NULL; 140} 141 142 143/** 144 * Create a new pipe_texture which wraps an existing buffer. 145 */ 146static struct pipe_texture * 147softpipe_texture_blanket(struct pipe_screen * screen, 148 const struct pipe_texture *base, 149 const unsigned *stride, 150 struct pipe_buffer *buffer) 151{ 152 struct softpipe_texture *spt; 153 assert(screen); 154 155 /* Only supports one type */ 156 if (base->target != PIPE_TEXTURE_2D || 157 base->last_level != 0 || 158 base->depth0 != 1) { 159 return NULL; 160 } 161 162 spt = CALLOC_STRUCT(softpipe_texture); 163 if (!spt) 164 return NULL; 165 166 spt->base = *base; 167 pipe_reference_init(&spt->base.reference, 1); 168 spt->base.screen = screen; 169 spt->stride[0] = stride[0]; 170 171 pipe_buffer_reference(&spt->buffer, buffer); 172 173 return &spt->base; 174} 175 176 177static void 178softpipe_texture_destroy(struct pipe_texture *pt) 179{ 180 struct softpipe_texture *spt = softpipe_texture(pt); 181 182 pipe_buffer_reference(&spt->buffer, NULL); 183 FREE(spt); 184} 185 186 187/** 188 * Get a pipe_surface "view" into a texture. 189 */ 190static struct pipe_surface * 191softpipe_get_tex_surface(struct pipe_screen *screen, 192 struct pipe_texture *pt, 193 unsigned face, unsigned level, unsigned zslice, 194 unsigned usage) 195{ 196 struct softpipe_texture *spt = softpipe_texture(pt); 197 struct pipe_surface *ps; 198 199 assert(level <= pt->last_level); 200 201 ps = CALLOC_STRUCT(pipe_surface); 202 if (ps) { 203 pipe_reference_init(&ps->reference, 1); 204 pipe_texture_reference(&ps->texture, pt); 205 ps->format = pt->format; 206 ps->width = u_minify(pt->width0, level); 207 ps->height = u_minify(pt->height0, level); 208 ps->offset = spt->level_offset[level]; 209 ps->usage = usage; 210 211 /* Because we are softpipe, anything that the state tracker 212 * thought was going to be done with the GPU will actually get 213 * done with the CPU. Let's adjust the flags to take that into 214 * account. 215 */ 216 if (ps->usage & PIPE_BUFFER_USAGE_GPU_WRITE) { 217 /* GPU_WRITE means "render" and that can involve reads (blending) */ 218 ps->usage |= PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_CPU_READ; 219 } 220 221 if (ps->usage & PIPE_BUFFER_USAGE_GPU_READ) 222 ps->usage |= PIPE_BUFFER_USAGE_CPU_READ; 223 224 if (ps->usage & (PIPE_BUFFER_USAGE_CPU_WRITE | 225 PIPE_BUFFER_USAGE_GPU_WRITE)) { 226 /* Mark the surface as dirty. The tile cache will look for this. */ 227 spt->timestamp++; 228 softpipe_screen(screen)->timestamp++; 229 } 230 231 ps->face = face; 232 ps->level = level; 233 ps->zslice = zslice; 234 235 if (pt->target == PIPE_TEXTURE_CUBE) { 236 ps->offset += face * util_format_get_nblocksy(pt->format, u_minify(pt->height0, level)) * 237 spt->stride[level]; 238 } 239 else if (pt->target == PIPE_TEXTURE_3D) { 240 ps->offset += zslice * util_format_get_nblocksy(pt->format, u_minify(pt->height0, level)) * 241 spt->stride[level]; 242 } 243 else { 244 assert(face == 0); 245 assert(zslice == 0); 246 } 247 } 248 return ps; 249} 250 251 252/** 253 * Free a pipe_surface which was created with softpipe_get_tex_surface(). 254 */ 255static void 256softpipe_tex_surface_destroy(struct pipe_surface *surf) 257{ 258 /* Effectively do the texture_update work here - if texture images 259 * needed post-processing to put them into hardware layout, this is 260 * where it would happen. For softpipe, nothing to do. 261 */ 262 assert(surf->texture); 263 pipe_texture_reference(&surf->texture, NULL); 264 FREE(surf); 265} 266 267 268/** 269 * Geta pipe_transfer object which is used for moving data in/out of 270 * a texture object. 271 * \param face one of PIPE_TEX_FACE_x or 0 272 * \param level texture mipmap level 273 * \param zslice 2D slice of a 3D texture 274 * \param usage one of PIPE_TRANSFER_READ/WRITE/READ_WRITE 275 * \param x X position of region to read/write 276 * \param y Y position of region to read/write 277 * \param width width of region to read/write 278 * \param height height of region to read/write 279 */ 280static struct pipe_transfer * 281softpipe_get_tex_transfer(struct pipe_screen *screen, 282 struct pipe_texture *texture, 283 unsigned face, unsigned level, unsigned zslice, 284 enum pipe_transfer_usage usage, 285 unsigned x, unsigned y, unsigned w, unsigned h) 286{ 287 struct softpipe_texture *sptex = softpipe_texture(texture); 288 struct softpipe_transfer *spt; 289 290 assert(texture); 291 assert(level <= texture->last_level); 292 293 /* make sure the requested region is in the image bounds */ 294 assert(x + w <= u_minify(texture->width0, level)); 295 assert(y + h <= u_minify(texture->height0, level)); 296 297 spt = CALLOC_STRUCT(softpipe_transfer); 298 if (spt) { 299 struct pipe_transfer *pt = &spt->base; 300 int nblocksy = util_format_get_nblocksy(texture->format, u_minify(texture->height0, level)); 301 pipe_texture_reference(&pt->texture, texture); 302 pt->x = x; 303 pt->y = y; 304 pt->width = w; 305 pt->height = h; 306 pt->stride = sptex->stride[level]; 307 pt->usage = usage; 308 pt->face = face; 309 pt->level = level; 310 pt->zslice = zslice; 311 312 spt->offset = sptex->level_offset[level]; 313 314 if (texture->target == PIPE_TEXTURE_CUBE) { 315 spt->offset += face * nblocksy * pt->stride; 316 } 317 else if (texture->target == PIPE_TEXTURE_3D) { 318 spt->offset += zslice * nblocksy * pt->stride; 319 } 320 else { 321 assert(face == 0); 322 assert(zslice == 0); 323 } 324 return pt; 325 } 326 return NULL; 327} 328 329 330/** 331 * Free a pipe_transfer object which was created with 332 * softpipe_get_tex_transfer(). 333 */ 334static void 335softpipe_tex_transfer_destroy(struct pipe_transfer *transfer) 336{ 337 /* Effectively do the texture_update work here - if texture images 338 * needed post-processing to put them into hardware layout, this is 339 * where it would happen. For softpipe, nothing to do. 340 */ 341 assert (transfer->texture); 342 pipe_texture_reference(&transfer->texture, NULL); 343 FREE(transfer); 344} 345 346 347/** 348 * Create memory mapping for given pipe_transfer object. 349 */ 350static void * 351softpipe_transfer_map( struct pipe_screen *screen, 352 struct pipe_transfer *transfer ) 353{ 354 ubyte *map, *xfer_map; 355 struct softpipe_texture *spt; 356 enum pipe_format format; 357 358 assert(transfer->texture); 359 spt = softpipe_texture(transfer->texture); 360 format = transfer->texture->format; 361 362 map = pipe_buffer_map(screen, spt->buffer, pipe_transfer_buffer_flags(transfer)); 363 if (map == NULL) 364 return NULL; 365 366 /* May want to different things here depending on read/write nature 367 * of the map: 368 */ 369 if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE)) { 370 /* Do something to notify sharing contexts of a texture change. 371 * In softpipe, that would mean flushing the texture cache. 372 */ 373 softpipe_screen(screen)->timestamp++; 374 } 375 376 xfer_map = map + softpipe_transfer(transfer)->offset + 377 transfer->y / util_format_get_blockheight(format) * transfer->stride + 378 transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 379 /*printf("map = %p xfer map = %p\n", map, xfer_map);*/ 380 return xfer_map; 381} 382 383 384/** 385 * Unmap memory mapping for given pipe_transfer object. 386 */ 387static void 388softpipe_transfer_unmap(struct pipe_screen *screen, 389 struct pipe_transfer *transfer) 390{ 391 struct softpipe_texture *spt; 392 393 assert(transfer->texture); 394 spt = softpipe_texture(transfer->texture); 395 396 pipe_buffer_unmap( screen, spt->buffer ); 397 398 if (transfer->usage & PIPE_TRANSFER_WRITE) { 399 /* Mark the texture as dirty to expire the tile caches. */ 400 spt->timestamp++; 401 } 402} 403 404 405static struct pipe_video_surface* 406softpipe_video_surface_create(struct pipe_screen *screen, 407 enum pipe_video_chroma_format chroma_format, 408 unsigned width, unsigned height) 409{ 410 struct softpipe_video_surface *sp_vsfc; 411 struct pipe_texture template; 412 413 assert(screen); 414 assert(width && height); 415 416 sp_vsfc = CALLOC_STRUCT(softpipe_video_surface); 417 if (!sp_vsfc) 418 return NULL; 419 420 pipe_reference_init(&sp_vsfc->base.reference, 1); 421 sp_vsfc->base.screen = screen; 422 sp_vsfc->base.chroma_format = chroma_format; 423 /*sp_vsfc->base.surface_format = PIPE_VIDEO_SURFACE_FORMAT_VUYA;*/ 424 sp_vsfc->base.width = width; 425 sp_vsfc->base.height = height; 426 427 memset(&template, 0, sizeof(struct pipe_texture)); 428 template.target = PIPE_TEXTURE_2D; 429 template.format = PIPE_FORMAT_B8G8R8X8_UNORM; 430 template.last_level = 0; 431 /* vl_mpeg12_mc_renderer expects this when it's initialized with pot_buffers=true */ 432 template.width0 = util_next_power_of_two(width); 433 template.height0 = util_next_power_of_two(height); 434 template.depth0 = 1; 435 template.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER | PIPE_TEXTURE_USAGE_RENDER_TARGET; 436 437 sp_vsfc->tex = screen->texture_create(screen, &template); 438 if (!sp_vsfc->tex) { 439 FREE(sp_vsfc); 440 return NULL; 441 } 442 443 return &sp_vsfc->base; 444} 445 446 447static void 448softpipe_video_surface_destroy(struct pipe_video_surface *vsfc) 449{ 450 struct softpipe_video_surface *sp_vsfc = softpipe_video_surface(vsfc); 451 452 pipe_texture_reference(&sp_vsfc->tex, NULL); 453 FREE(sp_vsfc); 454} 455 456 457void 458softpipe_init_screen_texture_funcs(struct pipe_screen *screen) 459{ 460 screen->texture_create = softpipe_texture_create; 461 screen->texture_blanket = softpipe_texture_blanket; 462 screen->texture_destroy = softpipe_texture_destroy; 463 464 screen->get_tex_surface = softpipe_get_tex_surface; 465 screen->tex_surface_destroy = softpipe_tex_surface_destroy; 466 467 screen->get_tex_transfer = softpipe_get_tex_transfer; 468 screen->tex_transfer_destroy = softpipe_tex_transfer_destroy; 469 screen->transfer_map = softpipe_transfer_map; 470 screen->transfer_unmap = softpipe_transfer_unmap; 471 472 screen->video_surface_create = softpipe_video_surface_create; 473 screen->video_surface_destroy = softpipe_video_surface_destroy; 474} 475 476 477/** 478 * Return pipe_buffer handle and stride for given texture object. 479 * XXX used for??? 480 */ 481boolean 482softpipe_get_texture_buffer( struct pipe_texture *texture, 483 struct pipe_buffer **buf, 484 unsigned *stride ) 485{ 486 struct softpipe_texture *tex = (struct softpipe_texture *) texture; 487 488 if (!tex) 489 return FALSE; 490 491 pipe_buffer_reference(buf, tex->buffer); 492 493 if (stride) 494 *stride = tex->stride[0]; 495 496 return TRUE; 497} 498