+static void
+blitter_draw_tex(struct blitter_context_priv *ctx,
+ int dst_x1, int dst_y1, int dst_x2, int dst_y2,
+ struct pipe_sampler_view *src,
+ unsigned src_width0, unsigned src_height0,
+ int src_x1, int src_y1, int src_x2, int src_y2,
+ float layer, unsigned sample,
+ bool uses_txf, enum blitter_attrib_type type)
+{
+ union blitter_attrib coord;
+ blitter_get_vs_func get_vs = get_vs_passthrough_pos_generic;
+
+ get_texcoords(src, src_width0, src_height0,
+ src_x1, src_y1, src_x2, src_y2, layer, sample,
+ uses_txf, &coord);
+
+ if (src->target == PIPE_TEXTURE_CUBE ||
+ src->target == PIPE_TEXTURE_CUBE_ARRAY) {
+ float face_coord[4][2];
+
+ set_texcoords_in_vertices(&coord, &face_coord[0][0], 2);
+ util_map_texcoords2d_onto_cubemap((unsigned)layer % 6,
+ /* pointer, stride in floats */
+ &face_coord[0][0], 2,
+ &ctx->vertices[0][1][0], 8,
+ false);
+ for (unsigned i = 0; i < 4; i++)
+ ctx->vertices[i][1][3] = coord.texcoord.w;
+
+ /* Cubemaps don't use draw_rectangle. */
+ blitter_draw(ctx, ctx->velem_state, get_vs,
+ dst_x1, dst_y1, dst_x2, dst_y2, 0, 1);
+ } else {
+ ctx->base.draw_rectangle(&ctx->base, ctx->velem_state, get_vs,
+ dst_x1, dst_y1, dst_x2, dst_y2,
+ 0, 1, type, &coord);
+ }
+}
+
+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,
+ bool uses_txf)
+{
+ 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->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) {
+ /* 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);
+ blitter_draw_tex(ctx, dstbox->x, dstbox->y,
+ dstbox->x + dstbox->width,
+ dstbox->y + dstbox->height,
+ src, src_width0, src_height0, srcbox->x, srcbox->y,
+ srcbox->x + srcbox->width, srcbox->y + srcbox->height,
+ 0, 0, uses_txf, UTIL_BLITTER_ATTRIB_TEXCOORD_XY);
+ } 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_draw_tex(ctx, dstbox->x, dstbox->y,
+ dstbox->x + dstbox->width,
+ dstbox->y + dstbox->height,
+ src, src_width0, src_height0,
+ srcbox->x, srcbox->y,
+ srcbox->x + srcbox->width,
+ srcbox->y + srcbox->height,
+ srcbox->z + src_z, i, uses_txf,
+ UTIL_BLITTER_ATTRIB_TEXCOORD_XYZW);
+ }
+ } else {
+ /* Normal copy, MSAA upsampling, or MSAA resolve. */
+ pipe->set_sample_mask(pipe, ~0);
+ blitter_draw_tex(ctx, dstbox->x, dstbox->y,
+ dstbox->x + dstbox->width,
+ dstbox->y + dstbox->height,
+ src, src_width0, src_height0,
+ srcbox->x, srcbox->y,
+ srcbox->x + srcbox->width,
+ srcbox->y + srcbox->height,
+ srcbox->z + src_z, 0, uses_txf,
+ UTIL_BLITTER_ATTRIB_TEXCOORD_XYZW);
+ }
+
+ /* 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 = util_blitter_get_next_surface_layer(ctx->base.pipe, dst);
+ }
+ if (dst_z) {
+ pipe_surface_reference(&old, NULL);
+ }
+ }
+ }
+}
+