+static void do_blits(struct blitter_context_priv *ctx,
+ struct pipe_surface *dst,
+ const struct pipe_box *dstbox,
+ struct pipe_sampler_view *src,
+ unsigned src_width0,
+ unsigned src_height0,
+ const struct pipe_box *srcbox,
+ bool is_zsbuf)
+{
+ struct pipe_context *pipe = ctx->base.pipe;
+ unsigned src_samples = src->texture->nr_samples;
+ unsigned dst_samples = dst->texture->nr_samples;
+ enum pipe_texture_target src_target = src->texture->target;
+ struct pipe_framebuffer_state fb_state = {0};
+
+ /* Initialize framebuffer state. */
+ fb_state.width = dst->width;
+ fb_state.height = dst->height;
+ fb_state.nr_cbufs = is_zsbuf ? 0 : 1;
+
+ blitter_set_dst_dimensions(ctx, fb_state.width, fb_state.height);
+
+ if ((src_target == PIPE_TEXTURE_1D ||
+ src_target == PIPE_TEXTURE_2D ||
+ src_target == PIPE_TEXTURE_RECT) &&
+ src_samples <= 1) {
+ /* Draw the quad with the draw_rectangle callback. */
+
+ /* Set texture coordinates. - use a pipe color union
+ * for interface purposes.
+ * XXX pipe_color_union is a wrong name since we use that to set
+ * texture coordinates too.
+ */
+ union pipe_color_union coord;
+ get_texcoords(src, src_width0, src_height0, srcbox->x, srcbox->y,
+ srcbox->x+srcbox->width, srcbox->y+srcbox->height, coord.f);
+
+ /* Set framebuffer state. */
+ if (is_zsbuf) {
+ fb_state.zsbuf = dst;
+ } else {
+ fb_state.cbufs[0] = dst;
+ }
+ pipe->set_framebuffer_state(pipe, &fb_state);
+
+ /* Draw. */
+ pipe->set_sample_mask(pipe, ~0);
+ ctx->base.draw_rectangle(&ctx->base, dstbox->x, dstbox->y,
+ dstbox->x + dstbox->width,
+ dstbox->y + dstbox->height, 0,
+ UTIL_BLITTER_ATTRIB_TEXCOORD, &coord);
+ } else {
+ /* Draw the quad with the generic codepath. */
+ int dst_z;
+ for (dst_z = 0; dst_z < dstbox->depth; dst_z++) {
+ struct pipe_surface *old;
+ float dst2src_scale = srcbox->depth / (float)dstbox->depth;
+
+ /* Scale Z properly if the blit is scaled.
+ *
+ * When downscaling, we want the coordinates centered, so that
+ * mipmapping works for 3D textures. For example, when generating
+ * a 4x4x4 level, this wouldn't average the pixels:
+ *
+ * src Z: 0 1 2 3 4 5 6 7
+ * dst Z: 0 1 2 3
+ *
+ * Because the pixels are not centered below the pixels of the higher
+ * level. Therefore, we want this:
+ * src Z: 0 1 2 3 4 5 6 7
+ * dst Z: 0 1 2 3
+ *
+ * dst_offset defines the offset needed for centering the pixels and
+ * it works with any scaling (not just 2x).
+ */
+ float dst_offset = ((srcbox->depth - 1) -
+ (dstbox->depth - 1) * dst2src_scale) * 0.5;
+ float src_z = (dst_z + dst_offset) * dst2src_scale;
+
+ /* Set framebuffer state. */
+ if (is_zsbuf) {
+ fb_state.zsbuf = dst;
+ } else {
+ fb_state.cbufs[0] = dst;
+ }
+ pipe->set_framebuffer_state(pipe, &fb_state);
+
+ /* See if we need to blit a multisample or singlesample buffer. */
+ if (src_samples == dst_samples && dst_samples > 1) {
+ /* MSAA copy. */
+ unsigned i, max_sample = dst_samples - 1;
+
+ for (i = 0; i <= max_sample; i++) {
+ pipe->set_sample_mask(pipe, 1 << i);
+ blitter_set_texcoords(ctx, src, src_width0, src_height0,
+ srcbox->z + src_z,
+ i, srcbox->x, srcbox->y,
+ srcbox->x + srcbox->width,
+ srcbox->y + srcbox->height);
+ blitter_draw(ctx, dstbox->x, dstbox->y,
+ dstbox->x + dstbox->width,
+ dstbox->y + dstbox->height, 0, 1);
+ }
+ } else {
+ /* Normal copy, MSAA upsampling, or MSAA resolve. */
+ pipe->set_sample_mask(pipe, ~0);
+ blitter_set_texcoords(ctx, src, src_width0, src_height0,
+ srcbox->z + src_z, 0,
+ srcbox->x, srcbox->y,
+ srcbox->x + srcbox->width,
+ srcbox->y + srcbox->height);
+ blitter_draw(ctx, dstbox->x, dstbox->y,
+ dstbox->x + dstbox->width,
+ dstbox->y + dstbox->height, 0, 1);
+ }
+
+ /* Get the next surface or (if this is the last iteration)
+ * just unreference the last one. */
+ old = dst;
+ if (dst_z < dstbox->depth-1) {
+ dst = ctx->base.get_next_surface_layer(ctx->base.pipe, dst);
+ }
+ if (dst_z) {
+ pipe_surface_reference(&old, NULL);
+ }
+ }
+ }
+}
+