1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2009 VMware, Inc. All Rights Reserved. 4848b8605Smrg * 5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 6848b8605Smrg * copy of this software and associated documentation files (the 7848b8605Smrg * "Software"), to deal in the Software without restriction, including 8848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 9848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 10848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 11848b8605Smrg * the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice (including the 14848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 15848b8605Smrg * of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24848b8605Smrg * 25848b8605Smrg **************************************************************************/ 26848b8605Smrg 27848b8605Smrg/** 28848b8605Smrg * @file 29848b8605Smrg * Surface utility functions. 30848b8605Smrg * 31848b8605Smrg * @author Brian Paul 32848b8605Smrg */ 33848b8605Smrg 34848b8605Smrg 35848b8605Smrg#include "pipe/p_defines.h" 36848b8605Smrg#include "pipe/p_screen.h" 37848b8605Smrg#include "pipe/p_state.h" 38848b8605Smrg 39848b8605Smrg#include "util/u_format.h" 40848b8605Smrg#include "util/u_inlines.h" 41848b8605Smrg#include "util/u_rect.h" 42848b8605Smrg#include "util/u_surface.h" 43848b8605Smrg#include "util/u_pack_color.h" 44848b8605Smrg 45848b8605Smrg 46848b8605Smrg/** 47848b8605Smrg * Initialize a pipe_surface object. 'view' is considered to have 48848b8605Smrg * uninitialized contents. 49848b8605Smrg */ 50848b8605Smrgvoid 51848b8605Smrgu_surface_default_template(struct pipe_surface *surf, 52848b8605Smrg const struct pipe_resource *texture) 53848b8605Smrg{ 54848b8605Smrg memset(surf, 0, sizeof(*surf)); 55848b8605Smrg 56848b8605Smrg surf->format = texture->format; 57848b8605Smrg} 58848b8605Smrg 59848b8605Smrg 60848b8605Smrg/** 61848b8605Smrg * Copy 2D rect from one place to another. 62848b8605Smrg * Position and sizes are in pixels. 63848b8605Smrg * src_stride may be negative to do vertical flip of pixels from source. 64848b8605Smrg */ 65848b8605Smrgvoid 66848b8605Smrgutil_copy_rect(ubyte * dst, 67848b8605Smrg enum pipe_format format, 68848b8605Smrg unsigned dst_stride, 69848b8605Smrg unsigned dst_x, 70848b8605Smrg unsigned dst_y, 71848b8605Smrg unsigned width, 72848b8605Smrg unsigned height, 73848b8605Smrg const ubyte * src, 74848b8605Smrg int src_stride, 75848b8605Smrg unsigned src_x, 76848b8605Smrg unsigned src_y) 77848b8605Smrg{ 78848b8605Smrg unsigned i; 79848b8605Smrg int src_stride_pos = src_stride < 0 ? -src_stride : src_stride; 80848b8605Smrg int blocksize = util_format_get_blocksize(format); 81848b8605Smrg int blockwidth = util_format_get_blockwidth(format); 82848b8605Smrg int blockheight = util_format_get_blockheight(format); 83848b8605Smrg 84848b8605Smrg assert(blocksize > 0); 85848b8605Smrg assert(blockwidth > 0); 86848b8605Smrg assert(blockheight > 0); 87848b8605Smrg 88848b8605Smrg dst_x /= blockwidth; 89848b8605Smrg dst_y /= blockheight; 90848b8605Smrg width = (width + blockwidth - 1)/blockwidth; 91848b8605Smrg height = (height + blockheight - 1)/blockheight; 92848b8605Smrg src_x /= blockwidth; 93848b8605Smrg src_y /= blockheight; 94848b8605Smrg 95848b8605Smrg dst += dst_x * blocksize; 96848b8605Smrg src += src_x * blocksize; 97848b8605Smrg dst += dst_y * dst_stride; 98848b8605Smrg src += src_y * src_stride_pos; 99848b8605Smrg width *= blocksize; 100848b8605Smrg 101b8e80941Smrg if (width == dst_stride && width == (unsigned)src_stride) 102848b8605Smrg memcpy(dst, src, height * width); 103848b8605Smrg else { 104848b8605Smrg for (i = 0; i < height; i++) { 105848b8605Smrg memcpy(dst, src, width); 106848b8605Smrg dst += dst_stride; 107848b8605Smrg src += src_stride; 108848b8605Smrg } 109848b8605Smrg } 110848b8605Smrg} 111848b8605Smrg 112848b8605Smrg 113848b8605Smrg/** 114848b8605Smrg * Copy 3D box from one place to another. 115848b8605Smrg * Position and sizes are in pixels. 116848b8605Smrg */ 117848b8605Smrgvoid 118848b8605Smrgutil_copy_box(ubyte * dst, 119848b8605Smrg enum pipe_format format, 120848b8605Smrg unsigned dst_stride, unsigned dst_slice_stride, 121848b8605Smrg unsigned dst_x, unsigned dst_y, unsigned dst_z, 122848b8605Smrg unsigned width, unsigned height, unsigned depth, 123848b8605Smrg const ubyte * src, 124848b8605Smrg int src_stride, unsigned src_slice_stride, 125848b8605Smrg unsigned src_x, unsigned src_y, unsigned src_z) 126848b8605Smrg{ 127848b8605Smrg unsigned z; 128848b8605Smrg dst += dst_z * dst_slice_stride; 129848b8605Smrg src += src_z * src_slice_stride; 130848b8605Smrg for (z = 0; z < depth; ++z) { 131848b8605Smrg util_copy_rect(dst, 132848b8605Smrg format, 133848b8605Smrg dst_stride, 134848b8605Smrg dst_x, dst_y, 135848b8605Smrg width, height, 136848b8605Smrg src, 137848b8605Smrg src_stride, 138848b8605Smrg src_x, src_y); 139848b8605Smrg 140848b8605Smrg dst += dst_slice_stride; 141848b8605Smrg src += src_slice_stride; 142848b8605Smrg } 143848b8605Smrg} 144848b8605Smrg 145848b8605Smrg 146848b8605Smrgvoid 147848b8605Smrgutil_fill_rect(ubyte * dst, 148848b8605Smrg enum pipe_format format, 149848b8605Smrg unsigned dst_stride, 150848b8605Smrg unsigned dst_x, 151848b8605Smrg unsigned dst_y, 152848b8605Smrg unsigned width, 153848b8605Smrg unsigned height, 154848b8605Smrg union util_color *uc) 155848b8605Smrg{ 156848b8605Smrg const struct util_format_description *desc = util_format_description(format); 157848b8605Smrg unsigned i, j; 158848b8605Smrg unsigned width_size; 159848b8605Smrg int blocksize = desc->block.bits / 8; 160848b8605Smrg int blockwidth = desc->block.width; 161848b8605Smrg int blockheight = desc->block.height; 162848b8605Smrg 163848b8605Smrg assert(blocksize > 0); 164848b8605Smrg assert(blockwidth > 0); 165848b8605Smrg assert(blockheight > 0); 166848b8605Smrg 167848b8605Smrg dst_x /= blockwidth; 168848b8605Smrg dst_y /= blockheight; 169848b8605Smrg width = (width + blockwidth - 1)/blockwidth; 170848b8605Smrg height = (height + blockheight - 1)/blockheight; 171848b8605Smrg 172848b8605Smrg dst += dst_x * blocksize; 173848b8605Smrg dst += dst_y * dst_stride; 174848b8605Smrg width_size = width * blocksize; 175848b8605Smrg 176848b8605Smrg switch (blocksize) { 177848b8605Smrg case 1: 178848b8605Smrg if(dst_stride == width_size) 179848b8605Smrg memset(dst, uc->ub, height * width_size); 180848b8605Smrg else { 181848b8605Smrg for (i = 0; i < height; i++) { 182848b8605Smrg memset(dst, uc->ub, width_size); 183848b8605Smrg dst += dst_stride; 184848b8605Smrg } 185848b8605Smrg } 186848b8605Smrg break; 187848b8605Smrg case 2: 188848b8605Smrg for (i = 0; i < height; i++) { 189848b8605Smrg uint16_t *row = (uint16_t *)dst; 190848b8605Smrg for (j = 0; j < width; j++) 191848b8605Smrg *row++ = uc->us; 192848b8605Smrg dst += dst_stride; 193848b8605Smrg } 194848b8605Smrg break; 195848b8605Smrg case 4: 196848b8605Smrg for (i = 0; i < height; i++) { 197848b8605Smrg uint32_t *row = (uint32_t *)dst; 198848b8605Smrg for (j = 0; j < width; j++) 199848b8605Smrg *row++ = uc->ui[0]; 200848b8605Smrg dst += dst_stride; 201848b8605Smrg } 202848b8605Smrg break; 203848b8605Smrg default: 204848b8605Smrg for (i = 0; i < height; i++) { 205848b8605Smrg ubyte *row = dst; 206848b8605Smrg for (j = 0; j < width; j++) { 207848b8605Smrg memcpy(row, uc, blocksize); 208848b8605Smrg row += blocksize; 209848b8605Smrg } 210848b8605Smrg dst += dst_stride; 211848b8605Smrg } 212848b8605Smrg break; 213848b8605Smrg } 214848b8605Smrg} 215848b8605Smrg 216848b8605Smrg 217848b8605Smrgvoid 218848b8605Smrgutil_fill_box(ubyte * dst, 219848b8605Smrg enum pipe_format format, 220848b8605Smrg unsigned stride, 221848b8605Smrg unsigned layer_stride, 222848b8605Smrg unsigned x, 223848b8605Smrg unsigned y, 224848b8605Smrg unsigned z, 225848b8605Smrg unsigned width, 226848b8605Smrg unsigned height, 227848b8605Smrg unsigned depth, 228848b8605Smrg union util_color *uc) 229848b8605Smrg{ 230848b8605Smrg unsigned layer; 231848b8605Smrg dst += z * layer_stride; 232848b8605Smrg for (layer = z; layer < depth; layer++) { 233848b8605Smrg util_fill_rect(dst, format, 234848b8605Smrg stride, 235848b8605Smrg x, y, width, height, uc); 236848b8605Smrg dst += layer_stride; 237848b8605Smrg } 238848b8605Smrg} 239848b8605Smrg 240848b8605Smrg 241848b8605Smrg/** 242848b8605Smrg * Fallback function for pipe->resource_copy_region(). 243b8e80941Smrg * We support copying between different formats (including compressed/ 244b8e80941Smrg * uncompressed) if the bytes per block or pixel matches. If copying 245b8e80941Smrg * compressed -> uncompressed, the dst region is reduced by the block 246b8e80941Smrg * width, height. If copying uncompressed -> compressed, the dest region 247b8e80941Smrg * is expanded by the block width, height. See GL_ARB_copy_image. 248848b8605Smrg * Note: (X,Y)=(0,0) is always the upper-left corner. 249848b8605Smrg */ 250848b8605Smrgvoid 251848b8605Smrgutil_resource_copy_region(struct pipe_context *pipe, 252848b8605Smrg struct pipe_resource *dst, 253848b8605Smrg unsigned dst_level, 254848b8605Smrg unsigned dst_x, unsigned dst_y, unsigned dst_z, 255848b8605Smrg struct pipe_resource *src, 256848b8605Smrg unsigned src_level, 257b8e80941Smrg const struct pipe_box *src_box_in) 258848b8605Smrg{ 259848b8605Smrg struct pipe_transfer *src_trans, *dst_trans; 260848b8605Smrg uint8_t *dst_map; 261848b8605Smrg const uint8_t *src_map; 262b8e80941Smrg enum pipe_format src_format; 263b8e80941Smrg enum pipe_format dst_format; 264b8e80941Smrg struct pipe_box src_box, dst_box; 265b8e80941Smrg unsigned src_bs, dst_bs, src_bw, dst_bw, src_bh, dst_bh; 266848b8605Smrg 267848b8605Smrg assert(src && dst); 268848b8605Smrg if (!src || !dst) 269848b8605Smrg return; 270848b8605Smrg 271848b8605Smrg assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) || 272848b8605Smrg (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER)); 273848b8605Smrg 274848b8605Smrg src_format = src->format; 275848b8605Smrg dst_format = dst->format; 276848b8605Smrg 277b8e80941Smrg /* init src box */ 278b8e80941Smrg src_box = *src_box_in; 279b8e80941Smrg 280b8e80941Smrg /* init dst box */ 281b8e80941Smrg dst_box.x = dst_x; 282b8e80941Smrg dst_box.y = dst_y; 283b8e80941Smrg dst_box.z = dst_z; 284b8e80941Smrg dst_box.width = src_box.width; 285b8e80941Smrg dst_box.height = src_box.height; 286b8e80941Smrg dst_box.depth = src_box.depth; 287b8e80941Smrg 288b8e80941Smrg src_bs = util_format_get_blocksize(src_format); 289b8e80941Smrg src_bw = util_format_get_blockwidth(src_format); 290b8e80941Smrg src_bh = util_format_get_blockheight(src_format); 291b8e80941Smrg dst_bs = util_format_get_blocksize(dst_format); 292b8e80941Smrg dst_bw = util_format_get_blockwidth(dst_format); 293b8e80941Smrg dst_bh = util_format_get_blockheight(dst_format); 294b8e80941Smrg 295b8e80941Smrg /* Note: all box positions and sizes are in pixels */ 296b8e80941Smrg if (src_bw > 1 && dst_bw == 1) { 297b8e80941Smrg /* Copy from compressed to uncompressed. 298b8e80941Smrg * Shrink dest box by the src block size. 299b8e80941Smrg */ 300b8e80941Smrg dst_box.width /= src_bw; 301b8e80941Smrg dst_box.height /= src_bh; 302b8e80941Smrg } 303b8e80941Smrg else if (src_bw == 1 && dst_bw > 1) { 304b8e80941Smrg /* Copy from uncompressed to compressed. 305b8e80941Smrg * Expand dest box by the dest block size. 306b8e80941Smrg */ 307b8e80941Smrg dst_box.width *= dst_bw; 308b8e80941Smrg dst_box.height *= dst_bh; 309b8e80941Smrg } 310b8e80941Smrg else { 311b8e80941Smrg /* compressed -> compressed or uncompressed -> uncompressed copy */ 312b8e80941Smrg assert(src_bw == dst_bw); 313b8e80941Smrg assert(src_bh == dst_bh); 314b8e80941Smrg } 315b8e80941Smrg 316b8e80941Smrg assert(src_bs == dst_bs); 317b8e80941Smrg if (src_bs != dst_bs) { 318b8e80941Smrg /* This can happen if we fail to do format checking before hand. 319b8e80941Smrg * Don't crash below. 320b8e80941Smrg */ 321b8e80941Smrg return; 322b8e80941Smrg } 323b8e80941Smrg 324b8e80941Smrg /* check that region boxes are block aligned */ 325b8e80941Smrg assert(src_box.x % src_bw == 0); 326b8e80941Smrg assert(src_box.y % src_bh == 0); 327b8e80941Smrg assert(dst_box.x % dst_bw == 0); 328b8e80941Smrg assert(dst_box.y % dst_bh == 0); 329b8e80941Smrg 330b8e80941Smrg /* check that region boxes are not out of bounds */ 331b8e80941Smrg assert(src_box.x + src_box.width <= (int)u_minify(src->width0, src_level)); 332b8e80941Smrg assert(src_box.y + src_box.height <= (int)u_minify(src->height0, src_level)); 333b8e80941Smrg assert(dst_box.x + dst_box.width <= (int)u_minify(dst->width0, dst_level)); 334b8e80941Smrg assert(dst_box.y + dst_box.height <= (int)u_minify(dst->height0, dst_level)); 335b8e80941Smrg 336b8e80941Smrg /* check that total number of src, dest bytes match */ 337b8e80941Smrg assert((src_box.width / src_bw) * (src_box.height / src_bh) * src_bs == 338b8e80941Smrg (dst_box.width / dst_bw) * (dst_box.height / dst_bh) * dst_bs); 339848b8605Smrg 340848b8605Smrg src_map = pipe->transfer_map(pipe, 341848b8605Smrg src, 342848b8605Smrg src_level, 343848b8605Smrg PIPE_TRANSFER_READ, 344b8e80941Smrg &src_box, &src_trans); 345848b8605Smrg assert(src_map); 346848b8605Smrg if (!src_map) { 347848b8605Smrg goto no_src_map; 348848b8605Smrg } 349848b8605Smrg 350848b8605Smrg dst_map = pipe->transfer_map(pipe, 351848b8605Smrg dst, 352848b8605Smrg dst_level, 353b8e80941Smrg PIPE_TRANSFER_WRITE | 354b8e80941Smrg PIPE_TRANSFER_DISCARD_RANGE, &dst_box, 355b8e80941Smrg &dst_trans); 356848b8605Smrg assert(dst_map); 357848b8605Smrg if (!dst_map) { 358848b8605Smrg goto no_dst_map; 359848b8605Smrg } 360848b8605Smrg 361848b8605Smrg if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) { 362b8e80941Smrg assert(src_box.height == 1); 363b8e80941Smrg assert(src_box.depth == 1); 364b8e80941Smrg memcpy(dst_map, src_map, src_box.width); 365848b8605Smrg } else { 366848b8605Smrg util_copy_box(dst_map, 367b8e80941Smrg src_format, 368848b8605Smrg dst_trans->stride, dst_trans->layer_stride, 369848b8605Smrg 0, 0, 0, 370b8e80941Smrg src_box.width, src_box.height, src_box.depth, 371848b8605Smrg src_map, 372848b8605Smrg src_trans->stride, src_trans->layer_stride, 373848b8605Smrg 0, 0, 0); 374848b8605Smrg } 375848b8605Smrg 376848b8605Smrg pipe->transfer_unmap(pipe, dst_trans); 377848b8605Smrgno_dst_map: 378848b8605Smrg pipe->transfer_unmap(pipe, src_trans); 379848b8605Smrgno_src_map: 380848b8605Smrg ; 381848b8605Smrg} 382848b8605Smrg 383b8e80941Smrgstatic void 384b8e80941Smrgutil_clear_color_texture_helper(struct pipe_transfer *dst_trans, 385b8e80941Smrg ubyte *dst_map, 386b8e80941Smrg enum pipe_format format, 387b8e80941Smrg const union pipe_color_union *color, 388b8e80941Smrg unsigned width, unsigned height, unsigned depth) 389b8e80941Smrg{ 390b8e80941Smrg union util_color uc; 391b8e80941Smrg 392b8e80941Smrg assert(dst_trans->stride > 0); 393b8e80941Smrg 394b8e80941Smrg if (util_format_is_pure_integer(format)) { 395b8e80941Smrg /* 396b8e80941Smrg * We expect int/uint clear values here, though some APIs 397b8e80941Smrg * might disagree (but in any case util_pack_color() 398b8e80941Smrg * couldn't handle it)... 399b8e80941Smrg */ 400b8e80941Smrg if (util_format_is_pure_sint(format)) { 401b8e80941Smrg util_format_write_4i(format, color->i, 0, &uc, 0, 0, 0, 1, 1); 402b8e80941Smrg } else { 403b8e80941Smrg assert(util_format_is_pure_uint(format)); 404b8e80941Smrg util_format_write_4ui(format, color->ui, 0, &uc, 0, 0, 0, 1, 1); 405b8e80941Smrg } 406b8e80941Smrg } else { 407b8e80941Smrg util_pack_color(color->f, format, &uc); 408b8e80941Smrg } 409b8e80941Smrg 410b8e80941Smrg util_fill_box(dst_map, format, 411b8e80941Smrg dst_trans->stride, dst_trans->layer_stride, 412b8e80941Smrg 0, 0, 0, width, height, depth, &uc); 413b8e80941Smrg} 414b8e80941Smrg 415b8e80941Smrgstatic void 416b8e80941Smrgutil_clear_color_texture(struct pipe_context *pipe, 417b8e80941Smrg struct pipe_resource *texture, 418b8e80941Smrg enum pipe_format format, 419b8e80941Smrg const union pipe_color_union *color, 420b8e80941Smrg unsigned level, 421b8e80941Smrg unsigned dstx, unsigned dsty, unsigned dstz, 422b8e80941Smrg unsigned width, unsigned height, unsigned depth) 423b8e80941Smrg{ 424b8e80941Smrg struct pipe_transfer *dst_trans; 425b8e80941Smrg ubyte *dst_map; 426b8e80941Smrg 427b8e80941Smrg dst_map = pipe_transfer_map_3d(pipe, 428b8e80941Smrg texture, 429b8e80941Smrg level, 430b8e80941Smrg PIPE_TRANSFER_WRITE, 431b8e80941Smrg dstx, dsty, dstz, 432b8e80941Smrg width, height, depth, 433b8e80941Smrg &dst_trans); 434b8e80941Smrg if (!dst_map) 435b8e80941Smrg return; 436b8e80941Smrg 437b8e80941Smrg if (dst_trans->stride > 0) { 438b8e80941Smrg util_clear_color_texture_helper(dst_trans, dst_map, format, color, 439b8e80941Smrg width, height, depth); 440b8e80941Smrg } 441b8e80941Smrg pipe->transfer_unmap(pipe, dst_trans); 442b8e80941Smrg} 443848b8605Smrg 444848b8605Smrg 445848b8605Smrg#define UBYTE_TO_USHORT(B) ((B) | ((B) << 8)) 446848b8605Smrg 447848b8605Smrg 448848b8605Smrg/** 449848b8605Smrg * Fallback for pipe->clear_render_target() function. 450848b8605Smrg * XXX this looks too hackish to be really useful. 451848b8605Smrg * cpp > 4 looks like a gross hack at best... 452848b8605Smrg * Plus can't use these transfer fallbacks when clearing 453848b8605Smrg * multisampled surfaces for instance. 454848b8605Smrg * Clears all bound layers. 455848b8605Smrg */ 456848b8605Smrgvoid 457848b8605Smrgutil_clear_render_target(struct pipe_context *pipe, 458848b8605Smrg struct pipe_surface *dst, 459848b8605Smrg const union pipe_color_union *color, 460848b8605Smrg unsigned dstx, unsigned dsty, 461848b8605Smrg unsigned width, unsigned height) 462848b8605Smrg{ 463848b8605Smrg struct pipe_transfer *dst_trans; 464848b8605Smrg ubyte *dst_map; 465848b8605Smrg 466848b8605Smrg assert(dst->texture); 467848b8605Smrg if (!dst->texture) 468848b8605Smrg return; 469848b8605Smrg 470848b8605Smrg if (dst->texture->target == PIPE_BUFFER) { 471848b8605Smrg /* 472848b8605Smrg * The fill naturally works on the surface format, however 473848b8605Smrg * the transfer uses resource format which is just bytes for buffers. 474848b8605Smrg */ 475848b8605Smrg unsigned dx, w; 476848b8605Smrg unsigned pixstride = util_format_get_blocksize(dst->format); 477848b8605Smrg dx = (dst->u.buf.first_element + dstx) * pixstride; 478848b8605Smrg w = width * pixstride; 479848b8605Smrg dst_map = pipe_transfer_map(pipe, 480848b8605Smrg dst->texture, 481848b8605Smrg 0, 0, 482848b8605Smrg PIPE_TRANSFER_WRITE, 483848b8605Smrg dx, 0, w, 1, 484848b8605Smrg &dst_trans); 485b8e80941Smrg if (dst_map) { 486b8e80941Smrg util_clear_color_texture_helper(dst_trans, dst_map, dst->format, 487b8e80941Smrg color, width, height, 1); 488b8e80941Smrg pipe->transfer_unmap(pipe, dst_trans); 489b8e80941Smrg } 490848b8605Smrg } 491848b8605Smrg else { 492b8e80941Smrg unsigned depth = dst->u.tex.last_layer - dst->u.tex.first_layer + 1; 493b8e80941Smrg util_clear_color_texture(pipe, dst->texture, dst->format, color, 494b8e80941Smrg dst->u.tex.level, dstx, dsty, 495b8e80941Smrg dst->u.tex.first_layer, width, height, depth); 496848b8605Smrg } 497b8e80941Smrg} 498b8e80941Smrg 499b8e80941Smrgstatic void 500b8e80941Smrgutil_clear_depth_stencil_texture(struct pipe_context *pipe, 501b8e80941Smrg struct pipe_resource *texture, 502b8e80941Smrg enum pipe_format format, 503b8e80941Smrg unsigned clear_flags, 504b8e80941Smrg uint64_t zstencil, unsigned level, 505b8e80941Smrg unsigned dstx, unsigned dsty, unsigned dstz, 506b8e80941Smrg unsigned width, unsigned height, unsigned depth) 507b8e80941Smrg{ 508b8e80941Smrg struct pipe_transfer *dst_trans; 509b8e80941Smrg ubyte *dst_map; 510b8e80941Smrg boolean need_rmw = FALSE; 511b8e80941Smrg unsigned dst_stride; 512b8e80941Smrg ubyte *dst_layer; 513b8e80941Smrg unsigned i, j, layer; 514848b8605Smrg 515b8e80941Smrg if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) && 516b8e80941Smrg ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) && 517b8e80941Smrg util_format_is_depth_and_stencil(format)) 518b8e80941Smrg need_rmw = TRUE; 519b8e80941Smrg 520b8e80941Smrg dst_map = pipe_transfer_map_3d(pipe, 521b8e80941Smrg texture, 522b8e80941Smrg level, 523b8e80941Smrg (need_rmw ? PIPE_TRANSFER_READ_WRITE : 524b8e80941Smrg PIPE_TRANSFER_WRITE), 525b8e80941Smrg dstx, dsty, dstz, 526b8e80941Smrg width, height, depth, &dst_trans); 527848b8605Smrg assert(dst_map); 528b8e80941Smrg if (!dst_map) 529b8e80941Smrg return; 530848b8605Smrg 531b8e80941Smrg dst_stride = dst_trans->stride; 532b8e80941Smrg dst_layer = dst_map; 533b8e80941Smrg assert(dst_trans->stride > 0); 534b8e80941Smrg 535b8e80941Smrg for (layer = 0; layer < depth; layer++) { 536b8e80941Smrg dst_map = dst_layer; 537b8e80941Smrg 538b8e80941Smrg switch (util_format_get_blocksize(format)) { 539b8e80941Smrg case 1: 540b8e80941Smrg assert(format == PIPE_FORMAT_S8_UINT); 541b8e80941Smrg if(dst_stride == width) 542b8e80941Smrg memset(dst_map, (uint8_t) zstencil, height * width); 543b8e80941Smrg else { 544b8e80941Smrg for (i = 0; i < height; i++) { 545b8e80941Smrg memset(dst_map, (uint8_t) zstencil, width); 546b8e80941Smrg dst_map += dst_stride; 547b8e80941Smrg } 548b8e80941Smrg } 549b8e80941Smrg break; 550b8e80941Smrg case 2: 551b8e80941Smrg assert(format == PIPE_FORMAT_Z16_UNORM); 552b8e80941Smrg for (i = 0; i < height; i++) { 553b8e80941Smrg uint16_t *row = (uint16_t *)dst_map; 554b8e80941Smrg for (j = 0; j < width; j++) 555b8e80941Smrg *row++ = (uint16_t) zstencil; 556b8e80941Smrg dst_map += dst_stride; 557b8e80941Smrg } 558b8e80941Smrg break; 559b8e80941Smrg case 4: 560b8e80941Smrg if (!need_rmw) { 561b8e80941Smrg for (i = 0; i < height; i++) { 562b8e80941Smrg uint32_t *row = (uint32_t *)dst_map; 563b8e80941Smrg for (j = 0; j < width; j++) 564b8e80941Smrg *row++ = (uint32_t) zstencil; 565b8e80941Smrg dst_map += dst_stride; 566b8e80941Smrg } 567b8e80941Smrg } 568b8e80941Smrg else { 569b8e80941Smrg uint32_t dst_mask; 570b8e80941Smrg if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT) 571b8e80941Smrg dst_mask = 0x00ffffff; 572b8e80941Smrg else { 573b8e80941Smrg assert(format == PIPE_FORMAT_S8_UINT_Z24_UNORM); 574b8e80941Smrg dst_mask = 0xffffff00; 575b8e80941Smrg } 576b8e80941Smrg if (clear_flags & PIPE_CLEAR_DEPTH) 577b8e80941Smrg dst_mask = ~dst_mask; 578b8e80941Smrg for (i = 0; i < height; i++) { 579b8e80941Smrg uint32_t *row = (uint32_t *)dst_map; 580b8e80941Smrg for (j = 0; j < width; j++) { 581b8e80941Smrg uint32_t tmp = *row & dst_mask; 582b8e80941Smrg *row++ = tmp | ((uint32_t) zstencil & ~dst_mask); 583b8e80941Smrg } 584b8e80941Smrg dst_map += dst_stride; 585b8e80941Smrg } 586b8e80941Smrg } 587b8e80941Smrg break; 588b8e80941Smrg case 8: 589b8e80941Smrg if (!need_rmw) { 590b8e80941Smrg for (i = 0; i < height; i++) { 591b8e80941Smrg uint64_t *row = (uint64_t *)dst_map; 592b8e80941Smrg for (j = 0; j < width; j++) 593b8e80941Smrg *row++ = zstencil; 594b8e80941Smrg dst_map += dst_stride; 595b8e80941Smrg } 596848b8605Smrg } 597848b8605Smrg else { 598b8e80941Smrg uint64_t src_mask; 599b8e80941Smrg 600b8e80941Smrg if (clear_flags & PIPE_CLEAR_DEPTH) 601b8e80941Smrg src_mask = 0x00000000ffffffffull; 602b8e80941Smrg else 603b8e80941Smrg src_mask = 0x000000ff00000000ull; 604b8e80941Smrg 605b8e80941Smrg for (i = 0; i < height; i++) { 606b8e80941Smrg uint64_t *row = (uint64_t *)dst_map; 607b8e80941Smrg for (j = 0; j < width; j++) { 608b8e80941Smrg uint64_t tmp = *row & ~src_mask; 609b8e80941Smrg *row++ = tmp | (zstencil & src_mask); 610b8e80941Smrg } 611b8e80941Smrg dst_map += dst_stride; 612b8e80941Smrg } 613848b8605Smrg } 614b8e80941Smrg break; 615b8e80941Smrg default: 616b8e80941Smrg assert(0); 617b8e80941Smrg break; 618848b8605Smrg } 619b8e80941Smrg dst_layer += dst_trans->layer_stride; 620b8e80941Smrg } 621b8e80941Smrg 622b8e80941Smrg pipe->transfer_unmap(pipe, dst_trans); 623b8e80941Smrg} 624b8e80941Smrg 625b8e80941Smrg 626b8e80941Smrgvoid 627b8e80941Smrgutil_clear_texture(struct pipe_context *pipe, 628b8e80941Smrg struct pipe_resource *tex, 629b8e80941Smrg unsigned level, 630b8e80941Smrg const struct pipe_box *box, 631b8e80941Smrg const void *data) 632b8e80941Smrg{ 633b8e80941Smrg const struct util_format_description *desc = 634b8e80941Smrg util_format_description(tex->format); 635b8e80941Smrg 636b8e80941Smrg if (level > tex->last_level) 637b8e80941Smrg return; 638b8e80941Smrg 639b8e80941Smrg if (util_format_is_depth_or_stencil(tex->format)) { 640b8e80941Smrg unsigned clear = 0; 641b8e80941Smrg float depth = 0.0f; 642b8e80941Smrg uint8_t stencil = 0; 643b8e80941Smrg uint64_t zstencil; 644b8e80941Smrg 645b8e80941Smrg if (util_format_has_depth(desc)) { 646b8e80941Smrg clear |= PIPE_CLEAR_DEPTH; 647b8e80941Smrg desc->unpack_z_float(&depth, 0, data, 0, 1, 1); 648848b8605Smrg } 649848b8605Smrg 650b8e80941Smrg if (util_format_has_stencil(desc)) { 651b8e80941Smrg clear |= PIPE_CLEAR_STENCIL; 652b8e80941Smrg desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1); 653b8e80941Smrg } 654b8e80941Smrg 655b8e80941Smrg zstencil = util_pack64_z_stencil(tex->format, depth, stencil); 656848b8605Smrg 657b8e80941Smrg util_clear_depth_stencil_texture(pipe, tex, tex->format, clear, zstencil, 658b8e80941Smrg level, box->x, box->y, box->z, 659b8e80941Smrg box->width, box->height, box->depth); 660b8e80941Smrg } else { 661b8e80941Smrg union pipe_color_union color; 662b8e80941Smrg if (util_format_is_pure_uint(tex->format)) 663b8e80941Smrg desc->unpack_rgba_uint(color.ui, 0, data, 0, 1, 1); 664b8e80941Smrg else if (util_format_is_pure_sint(tex->format)) 665b8e80941Smrg desc->unpack_rgba_sint(color.i, 0, data, 0, 1, 1); 666b8e80941Smrg else 667b8e80941Smrg desc->unpack_rgba_float(color.f, 0, data, 0, 1, 1); 668b8e80941Smrg 669b8e80941Smrg util_clear_color_texture(pipe, tex, tex->format, &color, level, 670b8e80941Smrg box->x, box->y, box->z, 671b8e80941Smrg box->width, box->height, box->depth); 672848b8605Smrg } 673848b8605Smrg} 674848b8605Smrg 675b8e80941Smrg 676848b8605Smrg/** 677848b8605Smrg * Fallback for pipe->clear_stencil() function. 678848b8605Smrg * sw fallback doesn't look terribly useful here. 679848b8605Smrg * Plus can't use these transfer fallbacks when clearing 680848b8605Smrg * multisampled surfaces for instance. 681848b8605Smrg * Clears all bound layers. 682848b8605Smrg */ 683848b8605Smrgvoid 684848b8605Smrgutil_clear_depth_stencil(struct pipe_context *pipe, 685848b8605Smrg struct pipe_surface *dst, 686848b8605Smrg unsigned clear_flags, 687848b8605Smrg double depth, 688848b8605Smrg unsigned stencil, 689848b8605Smrg unsigned dstx, unsigned dsty, 690848b8605Smrg unsigned width, unsigned height) 691848b8605Smrg{ 692b8e80941Smrg uint64_t zstencil; 693b8e80941Smrg unsigned max_layer; 694848b8605Smrg 695848b8605Smrg assert(dst->texture); 696848b8605Smrg if (!dst->texture) 697848b8605Smrg return; 698848b8605Smrg 699b8e80941Smrg zstencil = util_pack64_z_stencil(dst->format, depth, stencil); 700848b8605Smrg max_layer = dst->u.tex.last_layer - dst->u.tex.first_layer; 701b8e80941Smrg util_clear_depth_stencil_texture(pipe, dst->texture, dst->format, 702b8e80941Smrg clear_flags, zstencil, dst->u.tex.level, 703b8e80941Smrg dstx, dsty, dst->u.tex.first_layer, 704b8e80941Smrg width, height, max_layer + 1); 705848b8605Smrg} 706848b8605Smrg 707848b8605Smrg 708848b8605Smrg/* Return if the box is totally inside the resource. 709848b8605Smrg */ 710848b8605Smrgstatic boolean 711848b8605Smrgis_box_inside_resource(const struct pipe_resource *res, 712848b8605Smrg const struct pipe_box *box, 713848b8605Smrg unsigned level) 714848b8605Smrg{ 715848b8605Smrg unsigned width = 1, height = 1, depth = 1; 716848b8605Smrg 717848b8605Smrg switch (res->target) { 718848b8605Smrg case PIPE_BUFFER: 719848b8605Smrg width = res->width0; 720848b8605Smrg height = 1; 721848b8605Smrg depth = 1; 722848b8605Smrg break; 723848b8605Smrg case PIPE_TEXTURE_1D: 724848b8605Smrg width = u_minify(res->width0, level); 725848b8605Smrg height = 1; 726848b8605Smrg depth = 1; 727848b8605Smrg break; 728848b8605Smrg case PIPE_TEXTURE_2D: 729848b8605Smrg case PIPE_TEXTURE_RECT: 730848b8605Smrg width = u_minify(res->width0, level); 731848b8605Smrg height = u_minify(res->height0, level); 732848b8605Smrg depth = 1; 733848b8605Smrg break; 734848b8605Smrg case PIPE_TEXTURE_3D: 735848b8605Smrg width = u_minify(res->width0, level); 736848b8605Smrg height = u_minify(res->height0, level); 737848b8605Smrg depth = u_minify(res->depth0, level); 738848b8605Smrg break; 739848b8605Smrg case PIPE_TEXTURE_CUBE: 740848b8605Smrg width = u_minify(res->width0, level); 741848b8605Smrg height = u_minify(res->height0, level); 742848b8605Smrg depth = 6; 743848b8605Smrg break; 744848b8605Smrg case PIPE_TEXTURE_1D_ARRAY: 745848b8605Smrg width = u_minify(res->width0, level); 746848b8605Smrg height = 1; 747848b8605Smrg depth = res->array_size; 748848b8605Smrg break; 749848b8605Smrg case PIPE_TEXTURE_2D_ARRAY: 750848b8605Smrg width = u_minify(res->width0, level); 751848b8605Smrg height = u_minify(res->height0, level); 752848b8605Smrg depth = res->array_size; 753848b8605Smrg break; 754848b8605Smrg case PIPE_TEXTURE_CUBE_ARRAY: 755848b8605Smrg width = u_minify(res->width0, level); 756848b8605Smrg height = u_minify(res->height0, level); 757848b8605Smrg depth = res->array_size; 758848b8605Smrg assert(res->array_size % 6 == 0); 759848b8605Smrg break; 760b8e80941Smrg case PIPE_MAX_TEXTURE_TYPES: 761b8e80941Smrg break; 762848b8605Smrg } 763848b8605Smrg 764848b8605Smrg return box->x >= 0 && 765848b8605Smrg box->x + box->width <= (int) width && 766848b8605Smrg box->y >= 0 && 767848b8605Smrg box->y + box->height <= (int) height && 768848b8605Smrg box->z >= 0 && 769848b8605Smrg box->z + box->depth <= (int) depth; 770848b8605Smrg} 771848b8605Smrg 772848b8605Smrgstatic unsigned 773848b8605Smrgget_sample_count(const struct pipe_resource *res) 774848b8605Smrg{ 775848b8605Smrg return res->nr_samples ? res->nr_samples : 1; 776848b8605Smrg} 777848b8605Smrg 778b8e80941Smrg 779848b8605Smrg/** 780b8e80941Smrg * Check if a blit() command can be implemented with a resource_copy_region(). 781b8e80941Smrg * If tight_format_check is true, only allow the resource_copy_region() if 782b8e80941Smrg * the blit src/dst formats are identical, ignoring the resource formats. 783b8e80941Smrg * Otherwise, check for format casting and compatibility. 784848b8605Smrg */ 785848b8605Smrgboolean 786b8e80941Smrgutil_can_blit_via_copy_region(const struct pipe_blit_info *blit, 787b8e80941Smrg boolean tight_format_check) 788848b8605Smrg{ 789b8e80941Smrg const struct util_format_description *src_desc, *dst_desc; 790848b8605Smrg 791b8e80941Smrg src_desc = util_format_description(blit->src.resource->format); 792b8e80941Smrg dst_desc = util_format_description(blit->dst.resource->format); 793b8e80941Smrg 794b8e80941Smrg if (tight_format_check) { 795b8e80941Smrg /* no format conversions allowed */ 796b8e80941Smrg if (blit->src.format != blit->dst.format) { 797b8e80941Smrg return FALSE; 798b8e80941Smrg } 799b8e80941Smrg } 800b8e80941Smrg else { 801b8e80941Smrg /* do loose format compatibility checking */ 802b8e80941Smrg if (blit->src.resource->format != blit->src.format || 803b8e80941Smrg blit->dst.resource->format != blit->dst.format || 804b8e80941Smrg !util_is_format_compatible(src_desc, dst_desc)) { 805b8e80941Smrg return FALSE; 806b8e80941Smrg } 807848b8605Smrg } 808848b8605Smrg 809b8e80941Smrg unsigned mask = util_format_get_mask(blit->dst.format); 810b8e80941Smrg 811b8e80941Smrg /* No masks, no filtering, no scissor, no blending */ 812848b8605Smrg if ((blit->mask & mask) != mask || 813848b8605Smrg blit->filter != PIPE_TEX_FILTER_NEAREST || 814b8e80941Smrg blit->scissor_enable || 815b8e80941Smrg blit->num_window_rectangles > 0 || 816b8e80941Smrg blit->alpha_blend) { 817848b8605Smrg return FALSE; 818848b8605Smrg } 819848b8605Smrg 820b8e80941Smrg /* Only the src box can have negative dims for flipping */ 821b8e80941Smrg assert(blit->dst.box.width >= 1); 822b8e80941Smrg assert(blit->dst.box.height >= 1); 823b8e80941Smrg assert(blit->dst.box.depth >= 1); 824848b8605Smrg 825b8e80941Smrg /* No scaling or flipping */ 826848b8605Smrg if (blit->src.box.width != blit->dst.box.width || 827848b8605Smrg blit->src.box.height != blit->dst.box.height || 828848b8605Smrg blit->src.box.depth != blit->dst.box.depth) { 829848b8605Smrg return FALSE; 830848b8605Smrg } 831848b8605Smrg 832848b8605Smrg /* No out-of-bounds access. */ 833848b8605Smrg if (!is_box_inside_resource(blit->src.resource, &blit->src.box, 834848b8605Smrg blit->src.level) || 835848b8605Smrg !is_box_inside_resource(blit->dst.resource, &blit->dst.box, 836848b8605Smrg blit->dst.level)) { 837848b8605Smrg return FALSE; 838848b8605Smrg } 839848b8605Smrg 840848b8605Smrg /* Sample counts must match. */ 841848b8605Smrg if (get_sample_count(blit->src.resource) != 842848b8605Smrg get_sample_count(blit->dst.resource)) { 843848b8605Smrg return FALSE; 844848b8605Smrg } 845848b8605Smrg 846848b8605Smrg return TRUE; 847848b8605Smrg} 848b8e80941Smrg 849b8e80941Smrg 850b8e80941Smrg/** 851b8e80941Smrg * Try to do a blit using resource_copy_region. The function calls 852b8e80941Smrg * resource_copy_region if the blit description is compatible with it. 853b8e80941Smrg * 854b8e80941Smrg * It returns TRUE if the blit was done using resource_copy_region. 855b8e80941Smrg * 856b8e80941Smrg * It returns FALSE otherwise and the caller must fall back to a more generic 857b8e80941Smrg * codepath for the blit operation. (e.g. by using u_blitter) 858b8e80941Smrg */ 859b8e80941Smrgboolean 860b8e80941Smrgutil_try_blit_via_copy_region(struct pipe_context *ctx, 861b8e80941Smrg const struct pipe_blit_info *blit) 862b8e80941Smrg{ 863b8e80941Smrg if (util_can_blit_via_copy_region(blit, FALSE)) { 864b8e80941Smrg ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level, 865b8e80941Smrg blit->dst.box.x, blit->dst.box.y, 866b8e80941Smrg blit->dst.box.z, 867b8e80941Smrg blit->src.resource, blit->src.level, 868b8e80941Smrg &blit->src.box); 869b8e80941Smrg return TRUE; 870b8e80941Smrg } 871b8e80941Smrg else { 872b8e80941Smrg return FALSE; 873b8e80941Smrg } 874b8e80941Smrg} 875