+}
+
+
+void
+util_clear_texture(struct pipe_context *pipe,
+ struct pipe_resource *tex,
+ unsigned level,
+ const struct pipe_box *box,
+ const void *data)
+{
+ const struct util_format_description *desc =
+ util_format_description(tex->format);
+
+ if (level > tex->last_level)
+ return;
+
+ if (util_format_is_depth_or_stencil(tex->format)) {
+ unsigned clear = 0;
+ float depth = 0.0f;
+ uint8_t stencil = 0;
+ uint64_t zstencil;
+
+ if (util_format_has_depth(desc)) {
+ clear |= PIPE_CLEAR_DEPTH;
+ desc->unpack_z_float(&depth, 0, data, 0, 1, 1);
+ }
+
+ if (util_format_has_stencil(desc)) {
+ clear |= PIPE_CLEAR_STENCIL;
+ desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1);
+ }
+
+ zstencil = util_pack64_z_stencil(tex->format, depth, stencil);
+
+ util_clear_depth_stencil_texture(pipe, tex, tex->format, clear, zstencil,
+ level, box->x, box->y, box->z,
+ box->width, box->height, box->depth);
+ } else {
+ union pipe_color_union color;
+ if (util_format_is_pure_uint(tex->format))
+ desc->unpack_rgba_uint(color.ui, 0, data, 0, 1, 1);
+ else if (util_format_is_pure_sint(tex->format))
+ desc->unpack_rgba_sint(color.i, 0, data, 0, 1, 1);
+ else
+ desc->unpack_rgba_float(color.f, 0, data, 0, 1, 1);
+
+ util_clear_color_texture(pipe, tex, tex->format, &color, level,
+ box->x, box->y, box->z,
+ box->width, box->height, box->depth);
+ }
+}
+
+
+/**
+ * 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)
+{
+ uint64_t zstencil;
+ unsigned max_layer;
+
+ assert(dst->texture);
+ if (!dst->texture)
+ return;
+
+ zstencil = util_pack64_z_stencil(dst->format, depth, stencil);
+ max_layer = dst->u.tex.last_layer - dst->u.tex.first_layer;
+ util_clear_depth_stencil_texture(pipe, dst->texture, dst->format,
+ clear_flags, zstencil, dst->u.tex.level,
+ dstx, dsty, dst->u.tex.first_layer,
+ width, height, max_layer + 1);
+}
+
+
+/* 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:
+ break;
+ }
+
+ 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;
+}
+
+
+/**
+ * Check if a blit() command can be implemented with a resource_copy_region().
+ * If tight_format_check is true, only allow the resource_copy_region() if
+ * the blit src/dst formats are identical, ignoring the resource formats.
+ * Otherwise, check for format casting and compatibility.
+ */
+boolean
+util_can_blit_via_copy_region(const struct pipe_blit_info *blit,
+ boolean tight_format_check)
+{
+ const struct util_format_description *src_desc, *dst_desc;
+
+ src_desc = util_format_description(blit->src.resource->format);
+ dst_desc = util_format_description(blit->dst.resource->format);
+
+ if (tight_format_check) {
+ /* no format conversions allowed */
+ if (blit->src.format != blit->dst.format) {
+ return FALSE;
+ }
+ }
+ else {
+ /* do loose format compatibility checking */
+ if (blit->src.resource->format != blit->src.format ||
+ blit->dst.resource->format != blit->dst.format ||
+ !util_is_format_compatible(src_desc, dst_desc)) {
+ return FALSE;
+ }
+ }
+
+ unsigned mask = util_format_get_mask(blit->dst.format);
+
+ /* No masks, no filtering, no scissor, no blending */
+ if ((blit->mask & mask) != mask ||
+ blit->filter != PIPE_TEX_FILTER_NEAREST ||
+ blit->scissor_enable ||
+ blit->num_window_rectangles > 0 ||
+ blit->alpha_blend) {
+ return FALSE;
+ }
+
+ /* Only the src box can have negative dims for flipping */
+ assert(blit->dst.box.width >= 1);
+ assert(blit->dst.box.height >= 1);
+ assert(blit->dst.box.depth >= 1);
+
+ /* No scaling or flipping */
+ 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;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * 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)
+{
+ if (util_can_blit_via_copy_region(blit, 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;
+ }
+ else {
+ return FALSE;
+ }