+/**
+ * Fallback for pipe->clear_stencil() function.
+ * sw fallback doesn't look terribly useful here.
+ * Plus can't use these transfer fallbacks when clearing
+ * multisampled surfaces for instance.
+ * Clears all bound layers.
+ */
+void
+util_clear_depth_stencil(struct pipe_context *pipe,
+ struct pipe_surface *dst,
+ unsigned clear_flags,
+ double depth,
+ unsigned stencil,
+ unsigned dstx, unsigned dsty,
+ unsigned width, unsigned height)
+{
+ enum pipe_format format = dst->format;
+ struct pipe_transfer *dst_trans;
+ ubyte *dst_map;
+ boolean need_rmw = FALSE;
+ unsigned max_layer, layer;
+
+ if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) &&
+ ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) &&
+ util_format_is_depth_and_stencil(format))
+ need_rmw = TRUE;
+
+ assert(dst->texture);
+ if (!dst->texture)
+ return;
+
+ max_layer = dst->u.tex.last_layer - dst->u.tex.first_layer;
+ dst_map = pipe_transfer_map_3d(pipe,
+ dst->texture,
+ dst->u.tex.level,
+ (need_rmw ? PIPE_TRANSFER_READ_WRITE :
+ PIPE_TRANSFER_WRITE),
+ dstx, dsty, dst->u.tex.first_layer,
+ width, height, max_layer + 1, &dst_trans);
+ assert(dst_map);
+
+ if (dst_map) {
+ unsigned dst_stride = dst_trans->stride;
+ uint64_t zstencil = util_pack64_z_stencil(format, depth, stencil);
+ ubyte *dst_layer = dst_map;
+ unsigned i, j;
+ assert(dst_trans->stride > 0);
+
+ for (layer = 0; layer <= max_layer; layer++) {
+ dst_map = dst_layer;
+
+ switch (util_format_get_blocksize(format)) {
+ case 1:
+ assert(format == PIPE_FORMAT_S8_UINT);
+ if(dst_stride == width)
+ memset(dst_map, (uint8_t) zstencil, height * width);
+ else {
+ for (i = 0; i < height; i++) {
+ memset(dst_map, (uint8_t) zstencil, width);
+ dst_map += dst_stride;
+ }
+ }
+ break;
+ case 2:
+ assert(format == PIPE_FORMAT_Z16_UNORM);
+ for (i = 0; i < height; i++) {
+ uint16_t *row = (uint16_t *)dst_map;
+ for (j = 0; j < width; j++)
+ *row++ = (uint16_t) zstencil;
+ dst_map += dst_stride;
+ }
+ break;
+ case 4:
+ if (!need_rmw) {
+ for (i = 0; i < height; i++) {
+ uint32_t *row = (uint32_t *)dst_map;
+ for (j = 0; j < width; j++)
+ *row++ = (uint32_t) zstencil;
+ dst_map += dst_stride;
+ }
+ }
+ else {
+ uint32_t dst_mask;
+ if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT)
+ dst_mask = 0x00ffffff;
+ else {
+ assert(format == PIPE_FORMAT_S8_UINT_Z24_UNORM);
+ dst_mask = 0xffffff00;
+ }
+ if (clear_flags & PIPE_CLEAR_DEPTH)
+ dst_mask = ~dst_mask;
+ for (i = 0; i < height; i++) {
+ uint32_t *row = (uint32_t *)dst_map;
+ for (j = 0; j < width; j++) {
+ uint32_t tmp = *row & dst_mask;
+ *row++ = tmp | ((uint32_t) zstencil & ~dst_mask);
+ }
+ dst_map += dst_stride;
+ }
+ }
+ break;
+ case 8:
+ if (!need_rmw) {
+ for (i = 0; i < height; i++) {
+ uint64_t *row = (uint64_t *)dst_map;
+ for (j = 0; j < width; j++)
+ *row++ = zstencil;
+ dst_map += dst_stride;
+ }
+ }
+ else {
+ uint64_t src_mask;
+
+ if (clear_flags & PIPE_CLEAR_DEPTH)
+ src_mask = 0x00000000ffffffffull;
+ else
+ src_mask = 0x000000ff00000000ull;
+
+ for (i = 0; i < height; i++) {
+ uint64_t *row = (uint64_t *)dst_map;
+ for (j = 0; j < width; j++) {
+ uint64_t tmp = *row & ~src_mask;
+ *row++ = tmp | (zstencil & src_mask);
+ }
+ dst_map += dst_stride;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ dst_layer += dst_trans->layer_stride;
+ }
+
+ pipe->transfer_unmap(pipe, dst_trans);
+ }
+}
+
+
+/* Return if the box is totally inside the resource.
+ */
+static boolean
+is_box_inside_resource(const struct pipe_resource *res,
+ const struct pipe_box *box,
+ unsigned level)
+{
+ unsigned width = 1, height = 1, depth = 1;
+
+ switch (res->target) {
+ case PIPE_BUFFER:
+ width = res->width0;
+ height = 1;
+ depth = 1;
+ break;
+ case PIPE_TEXTURE_1D:
+ width = u_minify(res->width0, level);
+ height = 1;
+ depth = 1;
+ break;
+ case PIPE_TEXTURE_2D:
+ case PIPE_TEXTURE_RECT:
+ width = u_minify(res->width0, level);
+ height = u_minify(res->height0, level);
+ depth = 1;
+ break;
+ case PIPE_TEXTURE_3D:
+ width = u_minify(res->width0, level);
+ height = u_minify(res->height0, level);
+ depth = u_minify(res->depth0, level);
+ break;
+ case PIPE_TEXTURE_CUBE:
+ width = u_minify(res->width0, level);
+ height = u_minify(res->height0, level);
+ depth = 6;
+ break;
+ case PIPE_TEXTURE_1D_ARRAY:
+ width = u_minify(res->width0, level);
+ height = 1;
+ depth = res->array_size;
+ break;
+ case PIPE_TEXTURE_2D_ARRAY:
+ width = u_minify(res->width0, level);
+ height = u_minify(res->height0, level);
+ depth = res->array_size;
+ break;
+ case PIPE_TEXTURE_CUBE_ARRAY:
+ width = u_minify(res->width0, level);
+ height = u_minify(res->height0, level);
+ depth = res->array_size;
+ assert(res->array_size % 6 == 0);
+ break;
+ case PIPE_MAX_TEXTURE_TYPES:;
+ }
+
+ return box->x >= 0 &&
+ box->x + box->width <= (int) width &&
+ box->y >= 0 &&
+ box->y + box->height <= (int) height &&
+ box->z >= 0 &&
+ box->z + box->depth <= (int) depth;
+}
+
+static unsigned
+get_sample_count(const struct pipe_resource *res)
+{
+ return res->nr_samples ? res->nr_samples : 1;
+}
+
+/**
+ * Try to do a blit using resource_copy_region. The function calls
+ * resource_copy_region if the blit description is compatible with it.
+ *
+ * It returns TRUE if the blit was done using resource_copy_region.
+ *
+ * It returns FALSE otherwise and the caller must fall back to a more generic
+ * codepath for the blit operation. (e.g. by using u_blitter)
+ */
+boolean
+util_try_blit_via_copy_region(struct pipe_context *ctx,
+ const struct pipe_blit_info *blit)
+{
+ unsigned mask = util_format_get_mask(blit->dst.format);
+
+ /* No format conversions. */
+ if (blit->src.resource->format != blit->src.format ||
+ blit->dst.resource->format != blit->dst.format ||
+ !util_is_format_compatible(
+ util_format_description(blit->src.resource->format),
+ util_format_description(blit->dst.resource->format))) {
+ return FALSE;
+ }
+
+ /* No masks, no filtering, no scissor. */
+ if ((blit->mask & mask) != mask ||
+ blit->filter != PIPE_TEX_FILTER_NEAREST ||
+ blit->scissor_enable) {
+ return FALSE;
+ }
+
+ /* No flipping. */
+ if (blit->src.box.width < 0 ||
+ blit->src.box.height < 0 ||
+ blit->src.box.depth < 0) {
+ return FALSE;
+ }
+
+ /* No scaling. */
+ if (blit->src.box.width != blit->dst.box.width ||
+ blit->src.box.height != blit->dst.box.height ||
+ blit->src.box.depth != blit->dst.box.depth) {
+ return FALSE;
+ }
+
+ /* No out-of-bounds access. */
+ if (!is_box_inside_resource(blit->src.resource, &blit->src.box,
+ blit->src.level) ||
+ !is_box_inside_resource(blit->dst.resource, &blit->dst.box,
+ blit->dst.level)) {
+ return FALSE;
+ }
+
+ /* Sample counts must match. */
+ if (get_sample_count(blit->src.resource) !=
+ get_sample_count(blit->dst.resource)) {
+ return FALSE;
+ }
+
+ ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level,
+ blit->dst.box.x, blit->dst.box.y, blit->dst.box.z,
+ blit->src.resource, blit->src.level,
+ &blit->src.box);
+ return TRUE;