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 unsigned bind) 54 { 55 memset(surf, 0, sizeof(*surf)); 56 57 surf->format = texture->format; 58 /* XXX should filter out all non-rt/ds bind flags ? */ 59 surf->usage = bind; 60 } 61 62 /** 63 * Helper to quickly create an RGBA rendering surface of a certain size. 64 * \param textureOut returns the new texture 65 * \param surfaceOut returns the new surface 66 * \return TRUE for success, FALSE if failure 67 */ 68 boolean 69 util_create_rgba_surface(struct pipe_context *pipe, 70 uint width, uint height, 71 uint bind, 72 struct pipe_resource **textureOut, 73 struct pipe_surface **surfaceOut) 74 { 75 static const enum pipe_format rgbaFormats[] = { 76 PIPE_FORMAT_B8G8R8A8_UNORM, 77 PIPE_FORMAT_A8R8G8B8_UNORM, 78 PIPE_FORMAT_A8B8G8R8_UNORM, 79 PIPE_FORMAT_NONE 80 }; 81 const uint target = PIPE_TEXTURE_2D; 82 enum pipe_format format = PIPE_FORMAT_NONE; 83 struct pipe_resource templ; 84 struct pipe_surface surf_templ; 85 struct pipe_screen *screen = pipe->screen; 86 uint i; 87 88 /* Choose surface format */ 89 for (i = 0; rgbaFormats[i]; i++) { 90 if (screen->is_format_supported(screen, rgbaFormats[i], 91 target, 0, bind)) { 92 format = rgbaFormats[i]; 93 break; 94 } 95 } 96 if (format == PIPE_FORMAT_NONE) 97 return FALSE; /* unable to get an rgba format!?! */ 98 99 /* create texture */ 100 memset(&templ, 0, sizeof(templ)); 101 templ.target = target; 102 templ.format = format; 103 templ.last_level = 0; 104 templ.width0 = width; 105 templ.height0 = height; 106 templ.depth0 = 1; 107 templ.array_size = 1; 108 templ.bind = bind; 109 110 *textureOut = screen->resource_create(screen, &templ); 111 if (!*textureOut) 112 return FALSE; 113 114 /* create surface */ 115 u_surface_default_template(&surf_templ, *textureOut, bind); 116 /* create surface / view into texture */ 117 *surfaceOut = pipe->create_surface(pipe, 118 *textureOut, 119 &surf_templ); 120 if (!*surfaceOut) { 121 pipe_resource_reference(textureOut, NULL); 122 return FALSE; 123 } 124 125 return TRUE; 126 } 127 128 129 /** 130 * Release the surface and texture from util_create_rgba_surface(). 131 */ 132 void 133 util_destroy_rgba_surface(struct pipe_resource *texture, 134 struct pipe_surface *surface) 135 { 136 pipe_surface_reference(&surface, NULL); 137 pipe_resource_reference(&texture, NULL); 138 } 139 140 141 142 /** 143 * Fallback function for pipe->resource_copy_region(). 144 * Note: (X,Y)=(0,0) is always the upper-left corner. 145 */ 146 void 147 util_resource_copy_region(struct pipe_context *pipe, 148 struct pipe_resource *dst, 149 unsigned dst_level, 150 unsigned dst_x, unsigned dst_y, unsigned dst_z, 151 struct pipe_resource *src, 152 unsigned src_level, 153 const struct pipe_box *src_box) 154 { 155 struct pipe_transfer *src_trans, *dst_trans; 156 void *dst_map; 157 const void *src_map; 158 enum pipe_format src_format, dst_format; 159 unsigned w = src_box->width; 160 unsigned h = src_box->height; 161 162 assert(src && dst); 163 if (!src || !dst) 164 return; 165 166 assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) || 167 (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER)); 168 169 src_format = src->format; 170 dst_format = dst->format; 171 172 src_trans = pipe_get_transfer(pipe, 173 src, 174 src_level, 175 src_box->z, 176 PIPE_TRANSFER_READ, 177 src_box->x, src_box->y, w, h); 178 179 dst_trans = pipe_get_transfer(pipe, 180 dst, 181 dst_level, 182 dst_z, 183 PIPE_TRANSFER_WRITE, 184 dst_x, dst_y, w, h); 185 186 assert(util_format_get_blocksize(dst_format) == util_format_get_blocksize(src_format)); 187 assert(util_format_get_blockwidth(dst_format) == util_format_get_blockwidth(src_format)); 188 assert(util_format_get_blockheight(dst_format) == util_format_get_blockheight(src_format)); 189 190 src_map = pipe->transfer_map(pipe, src_trans); 191 dst_map = pipe->transfer_map(pipe, dst_trans); 192 193 assert(src_map); 194 assert(dst_map); 195 196 if (src_map && dst_map) { 197 if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) { 198 memcpy(dst_map, src_map, w); 199 } else { 200 util_copy_rect(dst_map, 201 dst_format, 202 dst_trans->stride, 203 0, 0, 204 w, h, 205 src_map, 206 src_trans->stride, 207 0, 208 0); 209 } 210 } 211 212 pipe->transfer_unmap(pipe, src_trans); 213 pipe->transfer_unmap(pipe, dst_trans); 214 215 pipe->transfer_destroy(pipe, src_trans); 216 pipe->transfer_destroy(pipe, dst_trans); 217 } 218 219 220 221 #define UBYTE_TO_USHORT(B) ((B) | ((B) << 8)) 222 223 224 /** 225 * Fallback for pipe->clear_render_target() function. 226 * XXX this looks too hackish to be really useful. 227 * cpp > 4 looks like a gross hack at best... 228 * Plus can't use these transfer fallbacks when clearing 229 * multisampled surfaces for instance. 230 */ 231 void 232 util_clear_render_target(struct pipe_context *pipe, 233 struct pipe_surface *dst, 234 const union pipe_color_union *color, 235 unsigned dstx, unsigned dsty, 236 unsigned width, unsigned height) 237 { 238 struct pipe_transfer *dst_trans; 239 void *dst_map; 240 union util_color uc; 241 242 assert(dst->texture); 243 if (!dst->texture) 244 return; 245 /* XXX: should handle multiple layers */ 246 dst_trans = pipe_get_transfer(pipe, 247 dst->texture, 248 dst->u.tex.level, 249 dst->u.tex.first_layer, 250 PIPE_TRANSFER_WRITE, 251 dstx, dsty, width, height); 252 253 dst_map = pipe->transfer_map(pipe, dst_trans); 254 255 assert(dst_map); 256 257 if (dst_map) { 258 assert(dst_trans->stride > 0); 259 260 util_pack_color(color->f, dst->texture->format, &uc); 261 util_fill_rect(dst_map, dst->texture->format, 262 dst_trans->stride, 263 0, 0, width, height, &uc); 264 } 265 266 pipe->transfer_unmap(pipe, dst_trans); 267 pipe->transfer_destroy(pipe, dst_trans); 268 } 269 270 /** 271 * Fallback for pipe->clear_stencil() function. 272 * sw fallback doesn't look terribly useful here. 273 * Plus can't use these transfer fallbacks when clearing 274 * multisampled surfaces for instance. 275 */ 276 void 277 util_clear_depth_stencil(struct pipe_context *pipe, 278 struct pipe_surface *dst, 279 unsigned clear_flags, 280 double depth, 281 unsigned stencil, 282 unsigned dstx, unsigned dsty, 283 unsigned width, unsigned height) 284 { 285 struct pipe_transfer *dst_trans; 286 ubyte *dst_map; 287 boolean need_rmw = FALSE; 288 289 if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) && 290 ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) && 291 util_format_is_depth_and_stencil(dst->format)) 292 need_rmw = TRUE; 293 294 assert(dst->texture); 295 if (!dst->texture) 296 return; 297 dst_trans = pipe_get_transfer(pipe, 298 dst->texture, 299 dst->u.tex.level, 300 dst->u.tex.first_layer, 301 (need_rmw ? PIPE_TRANSFER_READ_WRITE : 302 PIPE_TRANSFER_WRITE), 303 dstx, dsty, width, height); 304 305 dst_map = pipe->transfer_map(pipe, dst_trans); 306 307 assert(dst_map); 308 309 if (dst_map) { 310 unsigned dst_stride = dst_trans->stride; 311 unsigned zstencil = util_pack_z_stencil(dst->texture->format, depth, stencil); 312 unsigned i, j; 313 assert(dst_trans->stride > 0); 314 315 switch (util_format_get_blocksize(dst->format)) { 316 case 1: 317 assert(dst->format == PIPE_FORMAT_S8_UINT); 318 if(dst_stride == width) 319 memset(dst_map, (ubyte) zstencil, height * width); 320 else { 321 for (i = 0; i < height; i++) { 322 memset(dst_map, (ubyte) zstencil, width); 323 dst_map += dst_stride; 324 } 325 } 326 break; 327 case 2: 328 assert(dst->format == PIPE_FORMAT_Z16_UNORM); 329 for (i = 0; i < height; i++) { 330 uint16_t *row = (uint16_t *)dst_map; 331 for (j = 0; j < width; j++) 332 *row++ = (uint16_t) zstencil; 333 dst_map += dst_stride; 334 } 335 break; 336 case 4: 337 if (!need_rmw) { 338 for (i = 0; i < height; i++) { 339 uint32_t *row = (uint32_t *)dst_map; 340 for (j = 0; j < width; j++) 341 *row++ = zstencil; 342 dst_map += dst_stride; 343 } 344 } 345 else { 346 uint32_t dst_mask; 347 if (dst->format == PIPE_FORMAT_Z24_UNORM_S8_UINT) 348 dst_mask = 0xffffff00; 349 else { 350 assert(dst->format == PIPE_FORMAT_S8_UINT_Z24_UNORM); 351 dst_mask = 0xffffff; 352 } 353 if (clear_flags & PIPE_CLEAR_DEPTH) 354 dst_mask = ~dst_mask; 355 for (i = 0; i < height; i++) { 356 uint32_t *row = (uint32_t *)dst_map; 357 for (j = 0; j < width; j++) { 358 uint32_t tmp = *row & dst_mask; 359 *row++ = tmp | (zstencil & ~dst_mask); 360 } 361 dst_map += dst_stride; 362 } 363 } 364 break; 365 case 8: 366 { 367 uint64_t zstencil = util_pack64_z_stencil(dst->texture->format, 368 depth, stencil); 369 370 assert(dst->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT); 371 372 if (!need_rmw) { 373 for (i = 0; i < height; i++) { 374 uint64_t *row = (uint64_t *)dst_map; 375 for (j = 0; j < width; j++) 376 *row++ = zstencil; 377 dst_map += dst_stride; 378 } 379 } 380 else { 381 uint64_t src_mask; 382 383 if (clear_flags & PIPE_CLEAR_DEPTH) 384 src_mask = 0x00000000ffffffffull; 385 else 386 src_mask = 0x000000ff00000000ull; 387 388 for (i = 0; i < height; i++) { 389 uint64_t *row = (uint64_t *)dst_map; 390 for (j = 0; j < width; j++) { 391 uint64_t tmp = *row & ~src_mask; 392 *row++ = tmp | (zstencil & src_mask); 393 } 394 dst_map += dst_stride; 395 } 396 } 397 break; 398 } 399 default: 400 assert(0); 401 break; 402 } 403 } 404 405 pipe->transfer_unmap(pipe, dst_trans); 406 pipe->transfer_destroy(pipe, dst_trans); 407 } 408