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