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 (at) tungstengraphics.com> 30 * Michel Dnzer <michel (at) 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 #include "util/u_transfer.h" 40 41 #include "sp_context.h" 42 #include "sp_flush.h" 43 #include "sp_texture.h" 44 #include "sp_screen.h" 45 46 #include "state_tracker/sw_winsys.h" 47 48 49 /** 50 * Conventional allocation path for non-display textures: 51 * Use a simple, maximally packed layout. 52 */ 53 static boolean 54 softpipe_resource_layout(struct pipe_screen *screen, 55 struct softpipe_resource *spr) 56 { 57 struct pipe_resource *pt = &spr->base; 58 unsigned level; 59 unsigned width = pt->width0; 60 unsigned height = pt->height0; 61 unsigned depth = pt->depth0; 62 unsigned buffer_size = 0; 63 64 for (level = 0; level <= pt->last_level; level++) { 65 unsigned slices; 66 67 if (pt->target == PIPE_TEXTURE_CUBE) 68 slices = 6; 69 else if (pt->target == PIPE_TEXTURE_3D) 70 slices = depth; 71 else 72 slices = pt->array_size; 73 74 spr->stride[level] = util_format_get_stride(pt->format, width); 75 76 spr->level_offset[level] = buffer_size; 77 78 buffer_size += (util_format_get_nblocksy(pt->format, height) * 79 slices * spr->stride[level]); 80 81 width = u_minify(width, 1); 82 height = u_minify(height, 1); 83 depth = u_minify(depth, 1); 84 } 85 86 spr->data = align_malloc(buffer_size, 16); 87 88 return spr->data != NULL; 89 } 90 91 92 /** 93 * Texture layout for simple color buffers. 94 */ 95 static boolean 96 softpipe_displaytarget_layout(struct pipe_screen *screen, 97 struct softpipe_resource *spr) 98 { 99 struct sw_winsys *winsys = softpipe_screen(screen)->winsys; 100 101 /* Round up the surface size to a multiple of the tile size? 102 */ 103 spr->dt = winsys->displaytarget_create(winsys, 104 spr->base.bind, 105 spr->base.format, 106 spr->base.width0, 107 spr->base.height0, 108 16, 109 &spr->stride[0] ); 110 111 return spr->dt != NULL; 112 } 113 114 115 /** 116 * Create new pipe_resource given the template information. 117 */ 118 static struct pipe_resource * 119 softpipe_resource_create(struct pipe_screen *screen, 120 const struct pipe_resource *templat) 121 { 122 struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource); 123 if (!spr) 124 return NULL; 125 126 assert(templat->format != PIPE_FORMAT_NONE); 127 128 spr->base = *templat; 129 pipe_reference_init(&spr->base.reference, 1); 130 spr->base.screen = screen; 131 132 spr->pot = (util_is_power_of_two(templat->width0) && 133 util_is_power_of_two(templat->height0) && 134 util_is_power_of_two(templat->depth0)); 135 136 if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET | 137 PIPE_BIND_SCANOUT | 138 PIPE_BIND_SHARED)) { 139 if (!softpipe_displaytarget_layout(screen, spr)) 140 goto fail; 141 } 142 else { 143 if (!softpipe_resource_layout(screen, spr)) 144 goto fail; 145 } 146 147 return &spr->base; 148 149 fail: 150 FREE(spr); 151 return NULL; 152 } 153 154 155 static void 156 softpipe_resource_destroy(struct pipe_screen *pscreen, 157 struct pipe_resource *pt) 158 { 159 struct softpipe_screen *screen = softpipe_screen(pscreen); 160 struct softpipe_resource *spr = softpipe_resource(pt); 161 162 if (spr->dt) { 163 /* display target */ 164 struct sw_winsys *winsys = screen->winsys; 165 winsys->displaytarget_destroy(winsys, spr->dt); 166 } 167 else if (!spr->userBuffer) { 168 /* regular texture */ 169 align_free(spr->data); 170 } 171 172 FREE(spr); 173 } 174 175 176 static struct pipe_resource * 177 softpipe_resource_from_handle(struct pipe_screen *screen, 178 const struct pipe_resource *templat, 179 struct winsys_handle *whandle) 180 { 181 struct sw_winsys *winsys = softpipe_screen(screen)->winsys; 182 struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource); 183 if (!spr) 184 return NULL; 185 186 spr->base = *templat; 187 pipe_reference_init(&spr->base.reference, 1); 188 spr->base.screen = screen; 189 190 spr->pot = (util_is_power_of_two(templat->width0) && 191 util_is_power_of_two(templat->height0) && 192 util_is_power_of_two(templat->depth0)); 193 194 spr->dt = winsys->displaytarget_from_handle(winsys, 195 templat, 196 whandle, 197 &spr->stride[0]); 198 if (!spr->dt) 199 goto fail; 200 201 return &spr->base; 202 203 fail: 204 FREE(spr); 205 return NULL; 206 } 207 208 209 static boolean 210 softpipe_resource_get_handle(struct pipe_screen *screen, 211 struct pipe_resource *pt, 212 struct winsys_handle *whandle) 213 { 214 struct sw_winsys *winsys = softpipe_screen(screen)->winsys; 215 struct softpipe_resource *spr = softpipe_resource(pt); 216 217 assert(spr->dt); 218 if (!spr->dt) 219 return FALSE; 220 221 return winsys->displaytarget_get_handle(winsys, spr->dt, whandle); 222 } 223 224 225 /** 226 * Helper function to compute offset (in bytes) for a particular 227 * texture level/face/slice from the start of the buffer. 228 */ 229 static unsigned 230 sp_get_tex_image_offset(const struct softpipe_resource *spr, 231 unsigned level, unsigned layer) 232 { 233 const unsigned hgt = u_minify(spr->base.height0, level); 234 const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt); 235 unsigned offset = spr->level_offset[level]; 236 237 if (spr->base.target == PIPE_TEXTURE_CUBE || 238 spr->base.target == PIPE_TEXTURE_3D || 239 spr->base.target == PIPE_TEXTURE_2D_ARRAY) { 240 offset += layer * nblocksy * spr->stride[level]; 241 } 242 else if (spr->base.target == PIPE_TEXTURE_1D_ARRAY) { 243 offset += layer * spr->stride[level]; 244 } 245 else { 246 assert(layer == 0); 247 } 248 249 return offset; 250 } 251 252 253 /** 254 * Get a pipe_surface "view" into a texture resource. 255 */ 256 static struct pipe_surface * 257 softpipe_create_surface(struct pipe_context *pipe, 258 struct pipe_resource *pt, 259 const struct pipe_surface *surf_tmpl) 260 { 261 struct pipe_surface *ps; 262 unsigned level = surf_tmpl->u.tex.level; 263 264 assert(level <= pt->last_level); 265 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); 266 267 ps = CALLOC_STRUCT(pipe_surface); 268 if (ps) { 269 pipe_reference_init(&ps->reference, 1); 270 pipe_resource_reference(&ps->texture, pt); 271 ps->context = pipe; 272 ps->format = surf_tmpl->format; 273 ps->width = u_minify(pt->width0, level); 274 ps->height = u_minify(pt->height0, level); 275 ps->usage = surf_tmpl->usage; 276 277 ps->u.tex.level = level; 278 ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer; 279 ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer; 280 } 281 return ps; 282 } 283 284 285 /** 286 * Free a pipe_surface which was created with softpipe_create_surface(). 287 */ 288 static void 289 softpipe_surface_destroy(struct pipe_context *pipe, 290 struct pipe_surface *surf) 291 { 292 /* Effectively do the texture_update work here - if texture images 293 * needed post-processing to put them into hardware layout, this is 294 * where it would happen. For softpipe, nothing to do. 295 */ 296 assert(surf->texture); 297 pipe_resource_reference(&surf->texture, NULL); 298 FREE(surf); 299 } 300 301 302 /** 303 * Geta pipe_transfer object which is used for moving data in/out of 304 * a resource object. 305 * \param pipe rendering context 306 * \param resource the resource to transfer in/out of 307 * \param level which mipmap level 308 * \param usage bitmask of PIPE_TRANSFER_x flags 309 * \param box the 1D/2D/3D region of interest 310 */ 311 static struct pipe_transfer * 312 softpipe_get_transfer(struct pipe_context *pipe, 313 struct pipe_resource *resource, 314 unsigned level, 315 unsigned usage, 316 const struct pipe_box *box) 317 { 318 struct softpipe_resource *spr = softpipe_resource(resource); 319 struct softpipe_transfer *spt; 320 321 assert(resource); 322 assert(level <= resource->last_level); 323 324 /* make sure the requested region is in the image bounds */ 325 assert(box->x + box->width <= u_minify(resource->width0, level)); 326 if (resource->target == PIPE_TEXTURE_1D_ARRAY) { 327 assert(box->y + box->height <= resource->array_size); 328 } 329 else { 330 assert(box->y + box->height <= u_minify(resource->height0, level)); 331 if (resource->target == PIPE_TEXTURE_2D_ARRAY) { 332 assert(box->z + box->depth <= resource->array_size); 333 } 334 else if (resource->target == PIPE_TEXTURE_CUBE) { 335 assert(box->z < 6); 336 } 337 else { 338 assert(box->z + box->depth <= (u_minify(resource->depth0, level))); 339 } 340 } 341 342 /* 343 * Transfers, like other pipe operations, must happen in order, so flush the 344 * context if necessary. 345 */ 346 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 347 boolean read_only = !(usage & PIPE_TRANSFER_WRITE); 348 boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK); 349 if (!softpipe_flush_resource(pipe, resource, 350 level, box->depth > 1 ? -1 : box->z, 351 0, /* flush_flags */ 352 read_only, 353 TRUE, /* cpu_access */ 354 do_not_block)) { 355 /* 356 * It would have blocked, but state tracker requested no to. 357 */ 358 assert(do_not_block); 359 return NULL; 360 } 361 } 362 363 spt = CALLOC_STRUCT(softpipe_transfer); 364 if (spt) { 365 struct pipe_transfer *pt = &spt->base; 366 enum pipe_format format = resource->format; 367 const unsigned hgt = u_minify(spr->base.height0, level); 368 const unsigned nblocksy = util_format_get_nblocksy(format, hgt); 369 370 pipe_resource_reference(&pt->resource, resource); 371 pt->level = level; 372 pt->usage = usage; 373 pt->box = *box; 374 pt->stride = spr->stride[level]; 375 pt->layer_stride = pt->stride * nblocksy; 376 377 spt->offset = sp_get_tex_image_offset(spr, level, box->z); 378 379 spt->offset += 380 box->y / util_format_get_blockheight(format) * spt->base.stride + 381 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 382 383 return pt; 384 } 385 return NULL; 386 } 387 388 389 /** 390 * Free a pipe_transfer object which was created with 391 * softpipe_get_transfer(). 392 */ 393 static void 394 softpipe_transfer_destroy(struct pipe_context *pipe, 395 struct pipe_transfer *transfer) 396 { 397 pipe_resource_reference(&transfer->resource, NULL); 398 FREE(transfer); 399 } 400 401 402 /** 403 * Create memory mapping for given pipe_transfer object. 404 */ 405 static void * 406 softpipe_transfer_map(struct pipe_context *pipe, 407 struct pipe_transfer *transfer) 408 { 409 struct softpipe_transfer *spt = softpipe_transfer(transfer); 410 struct softpipe_resource *spr = softpipe_resource(transfer->resource); 411 struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; 412 uint8_t *map; 413 414 /* resources backed by display target treated specially: 415 */ 416 if (spr->dt) { 417 map = winsys->displaytarget_map(winsys, spr->dt, transfer->usage); 418 } 419 else { 420 map = spr->data; 421 } 422 423 if (map == NULL) 424 return NULL; 425 else 426 return map + spt->offset; 427 } 428 429 430 /** 431 * Unmap memory mapping for given pipe_transfer object. 432 */ 433 static void 434 softpipe_transfer_unmap(struct pipe_context *pipe, 435 struct pipe_transfer *transfer) 436 { 437 struct softpipe_resource *spr; 438 439 assert(transfer->resource); 440 spr = softpipe_resource(transfer->resource); 441 442 if (spr->dt) { 443 /* display target */ 444 struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; 445 winsys->displaytarget_unmap(winsys, spr->dt); 446 } 447 448 if (transfer->usage & PIPE_TRANSFER_WRITE) { 449 /* Mark the texture as dirty to expire the tile caches. */ 450 spr->timestamp++; 451 } 452 } 453 454 /** 455 * Create buffer which wraps user-space data. 456 */ 457 struct pipe_resource * 458 softpipe_user_buffer_create(struct pipe_screen *screen, 459 void *ptr, 460 unsigned bytes, 461 unsigned bind_flags) 462 { 463 struct softpipe_resource *spr; 464 465 spr = CALLOC_STRUCT(softpipe_resource); 466 if (!spr) 467 return NULL; 468 469 pipe_reference_init(&spr->base.reference, 1); 470 spr->base.screen = screen; 471 spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */ 472 spr->base.bind = bind_flags; 473 spr->base.usage = PIPE_USAGE_IMMUTABLE; 474 spr->base.flags = 0; 475 spr->base.width0 = bytes; 476 spr->base.height0 = 1; 477 spr->base.depth0 = 1; 478 spr->base.array_size = 1; 479 spr->userBuffer = TRUE; 480 spr->data = ptr; 481 482 return &spr->base; 483 } 484 485 486 void 487 softpipe_init_texture_funcs(struct pipe_context *pipe) 488 { 489 pipe->get_transfer = softpipe_get_transfer; 490 pipe->transfer_destroy = softpipe_transfer_destroy; 491 pipe->transfer_map = softpipe_transfer_map; 492 pipe->transfer_unmap = softpipe_transfer_unmap; 493 494 pipe->transfer_flush_region = u_default_transfer_flush_region; 495 pipe->transfer_inline_write = u_default_transfer_inline_write; 496 497 pipe->create_surface = softpipe_create_surface; 498 pipe->surface_destroy = softpipe_surface_destroy; 499 } 500 501 502 void 503 softpipe_init_screen_texture_funcs(struct pipe_screen *screen) 504 { 505 screen->resource_create = softpipe_resource_create; 506 screen->resource_destroy = softpipe_resource_destroy; 507 screen->resource_from_handle = softpipe_resource_from_handle; 508 screen->resource_get_handle = softpipe_resource_get_handle; 509 } 510