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