1 /************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27 /** 28 * @file 29 * Surface utility functions. 30 * 31 * @author Brian Paul 32 */ 33 34 35 #include "pipe/p_defines.h" 36 #include "pipe/p_screen.h" 37 #include "pipe/p_state.h" 38 39 #include "util/u_format.h" 40 #include "util/u_inlines.h" 41 #include "util/u_rect.h" 42 #include "util/u_surface.h" 43 #include "util/u_pack_color.h" 44 45 46 /** 47 * Initialize a pipe_surface object. 'view' is considered to have 48 * uninitialized contents. 49 */ 50 void 51 u_surface_default_template(struct pipe_surface *surf, 52 const struct pipe_resource *texture) 53 { 54 memset(surf, 0, sizeof(*surf)); 55 56 surf->format = texture->format; 57 } 58 59 60 /** 61 * Copy 2D rect from one place to another. 62 * Position and sizes are in pixels. 63 * src_stride may be negative to do vertical flip of pixels from source. 64 */ 65 void 66 util_copy_rect(ubyte * dst, 67 enum pipe_format format, 68 unsigned dst_stride, 69 unsigned dst_x, 70 unsigned dst_y, 71 unsigned width, 72 unsigned height, 73 const ubyte * src, 74 int src_stride, 75 unsigned src_x, 76 unsigned src_y) 77 { 78 unsigned i; 79 int src_stride_pos = src_stride < 0 ? -src_stride : src_stride; 80 int blocksize = util_format_get_blocksize(format); 81 int blockwidth = util_format_get_blockwidth(format); 82 int blockheight = util_format_get_blockheight(format); 83 84 assert(blocksize > 0); 85 assert(blockwidth > 0); 86 assert(blockheight > 0); 87 88 dst_x /= blockwidth; 89 dst_y /= blockheight; 90 width = (width + blockwidth - 1)/blockwidth; 91 height = (height + blockheight - 1)/blockheight; 92 src_x /= blockwidth; 93 src_y /= blockheight; 94 95 dst += dst_x * blocksize; 96 src += src_x * blocksize; 97 dst += dst_y * dst_stride; 98 src += src_y * src_stride_pos; 99 width *= blocksize; 100 101 if (width == dst_stride && (int)width == src_stride) 102 memcpy(dst, src, height * width); 103 else { 104 for (i = 0; i < height; i++) { 105 memcpy(dst, src, width); 106 dst += dst_stride; 107 src += src_stride; 108 } 109 } 110 } 111 112 113 /** 114 * Copy 3D box from one place to another. 115 * Position and sizes are in pixels. 116 */ 117 void 118 util_copy_box(ubyte * dst, 119 enum pipe_format format, 120 unsigned dst_stride, unsigned dst_slice_stride, 121 unsigned dst_x, unsigned dst_y, unsigned dst_z, 122 unsigned width, unsigned height, unsigned depth, 123 const ubyte * src, 124 int src_stride, unsigned src_slice_stride, 125 unsigned src_x, unsigned src_y, unsigned src_z) 126 { 127 unsigned z; 128 dst += dst_z * dst_slice_stride; 129 src += src_z * src_slice_stride; 130 for (z = 0; z < depth; ++z) { 131 util_copy_rect(dst, 132 format, 133 dst_stride, 134 dst_x, dst_y, 135 width, height, 136 src, 137 src_stride, 138 src_x, src_y); 139 140 dst += dst_slice_stride; 141 src += src_slice_stride; 142 } 143 } 144 145 146 void 147 util_fill_rect(ubyte * dst, 148 enum pipe_format format, 149 unsigned dst_stride, 150 unsigned dst_x, 151 unsigned dst_y, 152 unsigned width, 153 unsigned height, 154 union util_color *uc) 155 { 156 const struct util_format_description *desc = util_format_description(format); 157 unsigned i, j; 158 unsigned width_size; 159 int blocksize = desc->block.bits / 8; 160 int blockwidth = desc->block.width; 161 int blockheight = desc->block.height; 162 163 assert(blocksize > 0); 164 assert(blockwidth > 0); 165 assert(blockheight > 0); 166 167 dst_x /= blockwidth; 168 dst_y /= blockheight; 169 width = (width + blockwidth - 1)/blockwidth; 170 height = (height + blockheight - 1)/blockheight; 171 172 dst += dst_x * blocksize; 173 dst += dst_y * dst_stride; 174 width_size = width * blocksize; 175 176 switch (blocksize) { 177 case 1: 178 if(dst_stride == width_size) 179 memset(dst, uc->ub, height * width_size); 180 else { 181 for (i = 0; i < height; i++) { 182 memset(dst, uc->ub, width_size); 183 dst += dst_stride; 184 } 185 } 186 break; 187 case 2: 188 for (i = 0; i < height; i++) { 189 uint16_t *row = (uint16_t *)dst; 190 for (j = 0; j < width; j++) 191 *row++ = uc->us; 192 dst += dst_stride; 193 } 194 break; 195 case 4: 196 for (i = 0; i < height; i++) { 197 uint32_t *row = (uint32_t *)dst; 198 for (j = 0; j < width; j++) 199 *row++ = uc->ui[0]; 200 dst += dst_stride; 201 } 202 break; 203 default: 204 for (i = 0; i < height; i++) { 205 ubyte *row = dst; 206 for (j = 0; j < width; j++) { 207 memcpy(row, uc, blocksize); 208 row += blocksize; 209 } 210 dst += dst_stride; 211 } 212 break; 213 } 214 } 215 216 217 void 218 util_fill_box(ubyte * dst, 219 enum pipe_format format, 220 unsigned stride, 221 unsigned layer_stride, 222 unsigned x, 223 unsigned y, 224 unsigned z, 225 unsigned width, 226 unsigned height, 227 unsigned depth, 228 union util_color *uc) 229 { 230 unsigned layer; 231 dst += z * layer_stride; 232 for (layer = z; layer < depth; layer++) { 233 util_fill_rect(dst, format, 234 stride, 235 x, y, width, height, uc); 236 dst += layer_stride; 237 } 238 } 239 240 241 /** 242 * Fallback function for pipe->resource_copy_region(). 243 * Note: (X,Y)=(0,0) is always the upper-left corner. 244 */ 245 void 246 util_resource_copy_region(struct pipe_context *pipe, 247 struct pipe_resource *dst, 248 unsigned dst_level, 249 unsigned dst_x, unsigned dst_y, unsigned dst_z, 250 struct pipe_resource *src, 251 unsigned src_level, 252 const struct pipe_box *src_box) 253 { 254 struct pipe_transfer *src_trans, *dst_trans; 255 uint8_t *dst_map; 256 const uint8_t *src_map; 257 enum pipe_format src_format, dst_format; 258 struct pipe_box dst_box; 259 260 assert(src && dst); 261 if (!src || !dst) 262 return; 263 264 assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) || 265 (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER)); 266 267 src_format = src->format; 268 dst_format = dst->format; 269 270 assert(util_format_get_blocksize(dst_format) == util_format_get_blocksize(src_format)); 271 assert(util_format_get_blockwidth(dst_format) == util_format_get_blockwidth(src_format)); 272 assert(util_format_get_blockheight(dst_format) == util_format_get_blockheight(src_format)); 273 274 src_map = pipe->transfer_map(pipe, 275 src, 276 src_level, 277 PIPE_TRANSFER_READ, 278 src_box, &src_trans); 279 assert(src_map); 280 if (!src_map) { 281 goto no_src_map; 282 } 283 284 dst_box.x = dst_x; 285 dst_box.y = dst_y; 286 dst_box.z = dst_z; 287 dst_box.width = src_box->width; 288 dst_box.height = src_box->height; 289 dst_box.depth = src_box->depth; 290 291 dst_map = pipe->transfer_map(pipe, 292 dst, 293 dst_level, 294 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE, 295 &dst_box, &dst_trans); 296 assert(dst_map); 297 if (!dst_map) { 298 goto no_dst_map; 299 } 300 301 if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) { 302 assert(src_box->height == 1); 303 assert(src_box->depth == 1); 304 memcpy(dst_map, src_map, src_box->width); 305 } else { 306 util_copy_box(dst_map, 307 dst_format, 308 dst_trans->stride, dst_trans->layer_stride, 309 0, 0, 0, 310 src_box->width, src_box->height, src_box->depth, 311 src_map, 312 src_trans->stride, src_trans->layer_stride, 313 0, 0, 0); 314 } 315 316 pipe->transfer_unmap(pipe, dst_trans); 317 no_dst_map: 318 pipe->transfer_unmap(pipe, src_trans); 319 no_src_map: 320 ; 321 } 322 323 324 325 #define UBYTE_TO_USHORT(B) ((B) | ((B) << 8)) 326 327 328 /* Return if the box is totally inside the resource. 329 */ 330 static boolean 331 is_box_inside_resource(const struct pipe_resource *res, 332 const struct pipe_box *box, 333 unsigned level) 334 { 335 unsigned width = 1, height = 1, depth = 1; 336 337 switch (res->target) { 338 case PIPE_BUFFER: 339 width = res->width0; 340 height = 1; 341 depth = 1; 342 break; 343 case PIPE_TEXTURE_1D: 344 width = u_minify(res->width0, level); 345 height = 1; 346 depth = 1; 347 break; 348 case PIPE_TEXTURE_2D: 349 case PIPE_TEXTURE_RECT: 350 width = u_minify(res->width0, level); 351 height = u_minify(res->height0, level); 352 depth = 1; 353 break; 354 case PIPE_TEXTURE_3D: 355 width = u_minify(res->width0, level); 356 height = u_minify(res->height0, level); 357 depth = u_minify(res->depth0, level); 358 break; 359 case PIPE_TEXTURE_CUBE: 360 width = u_minify(res->width0, level); 361 height = u_minify(res->height0, level); 362 depth = 6; 363 break; 364 case PIPE_TEXTURE_1D_ARRAY: 365 width = u_minify(res->width0, level); 366 height = 1; 367 depth = res->array_size; 368 break; 369 case PIPE_TEXTURE_2D_ARRAY: 370 width = u_minify(res->width0, level); 371 height = u_minify(res->height0, level); 372 depth = res->array_size; 373 break; 374 case PIPE_TEXTURE_CUBE_ARRAY: 375 width = u_minify(res->width0, level); 376 height = u_minify(res->height0, level); 377 depth = res->array_size; 378 assert(res->array_size % 6 == 0); 379 break; 380 case PIPE_MAX_TEXTURE_TYPES:; 381 } 382 383 return box->x >= 0 && 384 box->x + box->width <= (int) width && 385 box->y >= 0 && 386 box->y + box->height <= (int) height && 387 box->z >= 0 && 388 box->z + box->depth <= (int) depth; 389 } 390 391 static unsigned 392 get_sample_count(const struct pipe_resource *res) 393 { 394 return res->nr_samples ? res->nr_samples : 1; 395 } 396 397 /** 398 * Try to do a blit using resource_copy_region. The function calls 399 * resource_copy_region if the blit description is compatible with it. 400 * 401 * It returns TRUE if the blit was done using resource_copy_region. 402 * 403 * It returns FALSE otherwise and the caller must fall back to a more generic 404 * codepath for the blit operation. (e.g. by using u_blitter) 405 */ 406 boolean 407 util_try_blit_via_copy_region(struct pipe_context *ctx, 408 const struct pipe_blit_info *blit) 409 { 410 unsigned mask = util_format_get_mask(blit->dst.format); 411 412 /* No format conversions. */ 413 if (blit->src.resource->format != blit->src.format || 414 blit->dst.resource->format != blit->dst.format || 415 !util_is_format_compatible( 416 util_format_description(blit->src.resource->format), 417 util_format_description(blit->dst.resource->format))) { 418 return FALSE; 419 } 420 421 /* No masks, no filtering, no scissor. */ 422 if ((blit->mask & mask) != mask || 423 blit->filter != PIPE_TEX_FILTER_NEAREST || 424 blit->scissor_enable) { 425 return FALSE; 426 } 427 428 /* No flipping. */ 429 if (blit->src.box.width < 0 || 430 blit->src.box.height < 0 || 431 blit->src.box.depth < 0) { 432 return FALSE; 433 } 434 435 /* No scaling. */ 436 if (blit->src.box.width != blit->dst.box.width || 437 blit->src.box.height != blit->dst.box.height || 438 blit->src.box.depth != blit->dst.box.depth) { 439 return FALSE; 440 } 441 442 /* No out-of-bounds access. */ 443 if (!is_box_inside_resource(blit->src.resource, &blit->src.box, 444 blit->src.level) || 445 !is_box_inside_resource(blit->dst.resource, &blit->dst.box, 446 blit->dst.level)) { 447 return FALSE; 448 } 449 450 /* Sample counts must match. */ 451 if (get_sample_count(blit->src.resource) != 452 get_sample_count(blit->dst.resource)) { 453 return FALSE; 454 } 455 456 ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level, 457 blit->dst.box.x, blit->dst.box.y, blit->dst.box.z, 458 blit->src.resource, blit->src.level, 459 &blit->src.box); 460 return TRUE; 461 } 462