101e04c3fSmrg/* 201e04c3fSmrg * Copyright (c) 2017 Etnaviv Project 301e04c3fSmrg * Copyright (C) 2017 Zodiac Inflight Innovations 401e04c3fSmrg * 501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 601e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 701e04c3fSmrg * to deal in the Software without restriction, including without limitation 801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sub license, 901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1101e04c3fSmrg * 1201e04c3fSmrg * The above copyright notice and this permission notice (including the 1301e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions 1401e04c3fSmrg * of the Software. 1501e04c3fSmrg * 1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2201e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2301e04c3fSmrg * 2401e04c3fSmrg * Authors: 2501e04c3fSmrg * Wladimir J. van der Laan <laanwj@gmail.com> 2601e04c3fSmrg */ 2701e04c3fSmrg#include "etnaviv_blt.h" 2801e04c3fSmrg 2901e04c3fSmrg#include "etnaviv_emit.h" 3001e04c3fSmrg#include "etnaviv_clear_blit.h" 3101e04c3fSmrg#include "etnaviv_context.h" 3201e04c3fSmrg#include "etnaviv_emit.h" 3301e04c3fSmrg#include "etnaviv_format.h" 3401e04c3fSmrg#include "etnaviv_resource.h" 3501e04c3fSmrg#include "etnaviv_surface.h" 3601e04c3fSmrg#include "etnaviv_translate.h" 3701e04c3fSmrg 3801e04c3fSmrg#include "util/u_math.h" 3901e04c3fSmrg#include "pipe/p_defines.h" 4001e04c3fSmrg#include "pipe/p_state.h" 4101e04c3fSmrg#include "util/u_blitter.h" 4201e04c3fSmrg#include "util/u_inlines.h" 4301e04c3fSmrg#include "util/u_memory.h" 4401e04c3fSmrg#include "util/u_surface.h" 4501e04c3fSmrg 4601e04c3fSmrg#include "hw/common_3d.xml.h" 4701e04c3fSmrg#include "hw/state_blt.xml.h" 4801e04c3fSmrg#include "hw/common.xml.h" 4901e04c3fSmrg 5001e04c3fSmrg#include <assert.h> 5101e04c3fSmrg 527ec681f3Smrgstatic uint32_t 537ec681f3Smrgetna_compatible_blt_format(enum pipe_format fmt) 547ec681f3Smrg{ 557ec681f3Smrg /* YUYV and UYVY are blocksize 4, but 2 bytes per pixel */ 567ec681f3Smrg if (fmt == PIPE_FORMAT_YUYV || fmt == PIPE_FORMAT_UYVY) 577ec681f3Smrg return BLT_FORMAT_R8G8; 587ec681f3Smrg 597ec681f3Smrg switch (util_format_get_blocksize(fmt)) { 607ec681f3Smrg case 1: return BLT_FORMAT_R8; 617ec681f3Smrg case 2: return BLT_FORMAT_R8G8; 627ec681f3Smrg case 4: return BLT_FORMAT_A8R8G8B8; 637ec681f3Smrg case 8: return BLT_FORMAT_A16R16G16B16; 647ec681f3Smrg default: return ETNA_NO_MATCH; 657ec681f3Smrg } 667ec681f3Smrg} 6701e04c3fSmrg 6801e04c3fSmrgstatic inline uint32_t 6901e04c3fSmrgblt_compute_stride_bits(const struct blt_imginfo *img) 7001e04c3fSmrg{ 7101e04c3fSmrg return VIVS_BLT_DEST_STRIDE_TILING(img->tiling == ETNA_LAYOUT_LINEAR ? 0 : 3) | /* 1/3? */ 7201e04c3fSmrg VIVS_BLT_DEST_STRIDE_FORMAT(img->format) | 7301e04c3fSmrg VIVS_BLT_DEST_STRIDE_STRIDE(img->stride); 7401e04c3fSmrg} 7501e04c3fSmrg 7601e04c3fSmrgstatic inline uint32_t 7701e04c3fSmrgblt_compute_img_config_bits(const struct blt_imginfo *img, bool for_dest) 7801e04c3fSmrg{ 7901e04c3fSmrg uint32_t tiling_bits = 0; 8001e04c3fSmrg if (img->tiling == ETNA_LAYOUT_SUPER_TILED) { 8101e04c3fSmrg tiling_bits |= for_dest ? BLT_IMAGE_CONFIG_TO_SUPER_TILED : BLT_IMAGE_CONFIG_FROM_SUPER_TILED; 8201e04c3fSmrg } 8301e04c3fSmrg 847ec681f3Smrg return BLT_IMAGE_CONFIG_TS_MODE(img->ts_mode) | 8501e04c3fSmrg COND(img->use_ts, BLT_IMAGE_CONFIG_TS) | 867ec681f3Smrg COND(img->use_ts && img->ts_compress_fmt >= 0, BLT_IMAGE_CONFIG_COMPRESSION) | 877ec681f3Smrg BLT_IMAGE_CONFIG_COMPRESSION_FORMAT(img->ts_compress_fmt) | 8801e04c3fSmrg COND(for_dest, BLT_IMAGE_CONFIG_UNK22) | 8901e04c3fSmrg BLT_IMAGE_CONFIG_SWIZ_R(0) | /* not used? */ 9001e04c3fSmrg BLT_IMAGE_CONFIG_SWIZ_G(1) | 9101e04c3fSmrg BLT_IMAGE_CONFIG_SWIZ_B(2) | 9201e04c3fSmrg BLT_IMAGE_CONFIG_SWIZ_A(3) | 9301e04c3fSmrg tiling_bits; 9401e04c3fSmrg} 9501e04c3fSmrg 9601e04c3fSmrgstatic inline uint32_t 9701e04c3fSmrgblt_compute_swizzle_bits(const struct blt_imginfo *img, bool for_dest) 9801e04c3fSmrg{ 9901e04c3fSmrg uint32_t swiz = VIVS_BLT_SWIZZLE_SRC_R(img->swizzle[0]) | 10001e04c3fSmrg VIVS_BLT_SWIZZLE_SRC_G(img->swizzle[1]) | 10101e04c3fSmrg VIVS_BLT_SWIZZLE_SRC_B(img->swizzle[2]) | 10201e04c3fSmrg VIVS_BLT_SWIZZLE_SRC_A(img->swizzle[3]); 10301e04c3fSmrg return for_dest ? (swiz << 12) : swiz; 10401e04c3fSmrg} 10501e04c3fSmrg 10601e04c3fSmrg/* Clear (part of) an image */ 10701e04c3fSmrgstatic void 10801e04c3fSmrgemit_blt_clearimage(struct etna_cmd_stream *stream, const struct blt_clear_op *op) 10901e04c3fSmrg{ 11001e04c3fSmrg etna_cmd_stream_reserve(stream, 64*2); /* Make sure BLT op doesn't get broken up */ 11101e04c3fSmrg 11201e04c3fSmrg etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001); 11301e04c3fSmrg assert(op->dest.bpp); 11401e04c3fSmrg etna_set_state(stream, VIVS_BLT_CONFIG, VIVS_BLT_CONFIG_CLEAR_BPP(op->dest.bpp-1)); 11501e04c3fSmrg /* NB: blob sets format to 1 in dest/src config for clear, and the swizzle to RRRR. 11601e04c3fSmrg * does this matter? It seems to just be ignored. But if we run into issues with BLT 11701e04c3fSmrg * behaving stragely, it's something to look at. 11801e04c3fSmrg */ 11901e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_STRIDE, blt_compute_stride_bits(&op->dest)); 12001e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_CONFIG, blt_compute_img_config_bits(&op->dest, true)); 12101e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_DEST_ADDR, &op->dest.addr); 12201e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_STRIDE, blt_compute_stride_bits(&op->dest)); 12301e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_CONFIG, blt_compute_img_config_bits(&op->dest, false)); 12401e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_SRC_ADDR, &op->dest.addr); 12501e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_POS, VIVS_BLT_DEST_POS_X(op->rect_x) | VIVS_BLT_DEST_POS_Y(op->rect_y)); 12601e04c3fSmrg etna_set_state(stream, VIVS_BLT_IMAGE_SIZE, VIVS_BLT_IMAGE_SIZE_WIDTH(op->rect_w) | VIVS_BLT_IMAGE_SIZE_HEIGHT(op->rect_h)); 12701e04c3fSmrg etna_set_state(stream, VIVS_BLT_CLEAR_COLOR0, op->clear_value[0]); 12801e04c3fSmrg etna_set_state(stream, VIVS_BLT_CLEAR_COLOR1, op->clear_value[1]); 12901e04c3fSmrg etna_set_state(stream, VIVS_BLT_CLEAR_BITS0, op->clear_bits[0]); 13001e04c3fSmrg etna_set_state(stream, VIVS_BLT_CLEAR_BITS1, op->clear_bits[1]); 13101e04c3fSmrg if (op->dest.use_ts) { 13201e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_DEST_TS, &op->dest.ts_addr); 13301e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_SRC_TS, &op->dest.ts_addr); 13401e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE0, op->dest.ts_clear_value[0]); 13501e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE1, op->dest.ts_clear_value[1]); 13601e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE0, op->dest.ts_clear_value[0]); 13701e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE1, op->dest.ts_clear_value[1]); 13801e04c3fSmrg } 13901e04c3fSmrg etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); 14001e04c3fSmrg etna_set_state(stream, VIVS_BLT_COMMAND, VIVS_BLT_COMMAND_COMMAND_CLEAR_IMAGE); 14101e04c3fSmrg etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); 14201e04c3fSmrg etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000); 14301e04c3fSmrg} 14401e04c3fSmrg 14501e04c3fSmrg/* Copy (a subset of) an image to another image. */ 14601e04c3fSmrgstatic void 14701e04c3fSmrgemit_blt_copyimage(struct etna_cmd_stream *stream, const struct blt_imgcopy_op *op) 14801e04c3fSmrg{ 14901e04c3fSmrg etna_cmd_stream_reserve(stream, 64*2); /* Never allow BLT sequences to be broken up */ 15001e04c3fSmrg 15101e04c3fSmrg etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001); 15201e04c3fSmrg etna_set_state(stream, VIVS_BLT_CONFIG, 15301e04c3fSmrg VIVS_BLT_CONFIG_SRC_ENDIAN(op->src.endian_mode) | 15401e04c3fSmrg VIVS_BLT_CONFIG_DEST_ENDIAN(op->dest.endian_mode)); 15501e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_STRIDE, blt_compute_stride_bits(&op->src)); 15601e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_CONFIG, blt_compute_img_config_bits(&op->src, false)); 15701e04c3fSmrg etna_set_state(stream, VIVS_BLT_SWIZZLE, 15801e04c3fSmrg blt_compute_swizzle_bits(&op->src, false) | 15901e04c3fSmrg blt_compute_swizzle_bits(&op->dest, true)); 16001e04c3fSmrg etna_set_state(stream, VIVS_BLT_UNK140A0, 0x00040004); 16101e04c3fSmrg etna_set_state(stream, VIVS_BLT_UNK1409C, 0x00400040); 16201e04c3fSmrg if (op->src.use_ts) { 16301e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_SRC_TS, &op->src.ts_addr); 16401e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE0, op->src.ts_clear_value[0]); 16501e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE1, op->src.ts_clear_value[1]); 16601e04c3fSmrg } 16701e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_SRC_ADDR, &op->src.addr); 16801e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_STRIDE, blt_compute_stride_bits(&op->dest)); 16901e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_CONFIG, 17001e04c3fSmrg blt_compute_img_config_bits(&op->dest, true) | 17101e04c3fSmrg COND(op->flip_y, BLT_IMAGE_CONFIG_FLIP_Y)); 17201e04c3fSmrg assert(!op->dest.use_ts); /* Dest TS path doesn't work for copies? */ 17301e04c3fSmrg if (op->dest.use_ts) { 17401e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_DEST_TS, &op->dest.ts_addr); 17501e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE0, op->dest.ts_clear_value[0]); 17601e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE1, op->dest.ts_clear_value[1]); 17701e04c3fSmrg } 17801e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_DEST_ADDR, &op->dest.addr); 17901e04c3fSmrg etna_set_state(stream, VIVS_BLT_SRC_POS, VIVS_BLT_DEST_POS_X(op->src_x) | VIVS_BLT_DEST_POS_Y(op->src_y)); 18001e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_POS, VIVS_BLT_DEST_POS_X(op->dest_x) | VIVS_BLT_DEST_POS_Y(op->dest_y)); 18101e04c3fSmrg etna_set_state(stream, VIVS_BLT_IMAGE_SIZE, VIVS_BLT_IMAGE_SIZE_WIDTH(op->rect_w) | VIVS_BLT_IMAGE_SIZE_HEIGHT(op->rect_h)); 18201e04c3fSmrg etna_set_state(stream, VIVS_BLT_UNK14058, 0xffffffff); 18301e04c3fSmrg etna_set_state(stream, VIVS_BLT_UNK1405C, 0xffffffff); 18401e04c3fSmrg etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); 18501e04c3fSmrg etna_set_state(stream, VIVS_BLT_COMMAND, VIVS_BLT_COMMAND_COMMAND_COPY_IMAGE); 18601e04c3fSmrg etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); 18701e04c3fSmrg etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000); 18801e04c3fSmrg} 18901e04c3fSmrg 19001e04c3fSmrg/* Emit in-place resolve using BLT. */ 19101e04c3fSmrgstatic void 19201e04c3fSmrgemit_blt_inplace(struct etna_cmd_stream *stream, const struct blt_inplace_op *op) 19301e04c3fSmrg{ 19401e04c3fSmrg assert(op->bpp > 0 && util_is_power_of_two_nonzero(op->bpp)); 19501e04c3fSmrg etna_cmd_stream_reserve(stream, 64*2); /* Never allow BLT sequences to be broken up */ 19601e04c3fSmrg etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001); 19701e04c3fSmrg etna_set_state(stream, VIVS_BLT_CONFIG, 1987ec681f3Smrg VIVS_BLT_CONFIG_INPLACE_TS_MODE(op->ts_mode) | 19901e04c3fSmrg VIVS_BLT_CONFIG_INPLACE_BOTH | 20001e04c3fSmrg (util_logbase2(op->bpp) << VIVS_BLT_CONFIG_INPLACE_BPP__SHIFT)); 20101e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE0, op->ts_clear_value[0]); 20201e04c3fSmrg etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE1, op->ts_clear_value[1]); 20301e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_DEST_ADDR, &op->addr); 20401e04c3fSmrg etna_set_state_reloc(stream, VIVS_BLT_DEST_TS, &op->ts_addr); 20501e04c3fSmrg etna_set_state(stream, 0x14068, op->num_tiles); 20601e04c3fSmrg etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); 20701e04c3fSmrg etna_set_state(stream, VIVS_BLT_COMMAND, 0x00000004); 20801e04c3fSmrg etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003); 20901e04c3fSmrg etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000); 21001e04c3fSmrg} 21101e04c3fSmrg 21201e04c3fSmrgstatic void 21301e04c3fSmrgetna_blit_clear_color_blt(struct pipe_context *pctx, struct pipe_surface *dst, 21401e04c3fSmrg const union pipe_color_union *color) 21501e04c3fSmrg{ 21601e04c3fSmrg struct etna_context *ctx = etna_context(pctx); 21701e04c3fSmrg struct etna_surface *surf = etna_surface(dst); 2187ec681f3Smrg uint64_t new_clear_value = etna_clear_blit_pack_rgba(surf->base.format, color); 21901e04c3fSmrg 22001e04c3fSmrg struct etna_resource *res = etna_resource(surf->base.texture); 22101e04c3fSmrg struct blt_clear_op clr = {}; 22201e04c3fSmrg clr.dest.addr.bo = res->bo; 22301e04c3fSmrg clr.dest.addr.offset = surf->surf.offset; 22401e04c3fSmrg clr.dest.addr.flags = ETNA_RELOC_WRITE; 22501e04c3fSmrg clr.dest.bpp = util_format_get_blocksize(surf->base.format); 22601e04c3fSmrg clr.dest.stride = surf->surf.stride; 22701e04c3fSmrg clr.dest.tiling = res->layout; 22801e04c3fSmrg 22901e04c3fSmrg if (surf->surf.ts_size) { 23001e04c3fSmrg clr.dest.use_ts = 1; 23101e04c3fSmrg clr.dest.ts_addr.bo = res->ts_bo; 2327ec681f3Smrg clr.dest.ts_addr.offset = surf->level->ts_offset; 23301e04c3fSmrg clr.dest.ts_addr.flags = ETNA_RELOC_WRITE; 23401e04c3fSmrg clr.dest.ts_clear_value[0] = new_clear_value; 2357ec681f3Smrg clr.dest.ts_clear_value[1] = new_clear_value >> 32; 2367ec681f3Smrg clr.dest.ts_mode = surf->level->ts_mode; 2377ec681f3Smrg clr.dest.ts_compress_fmt = surf->level->ts_compress_fmt; 23801e04c3fSmrg } 23901e04c3fSmrg 24001e04c3fSmrg clr.clear_value[0] = new_clear_value; 2417ec681f3Smrg clr.clear_value[1] = new_clear_value >> 32; 24201e04c3fSmrg clr.clear_bits[0] = 0xffffffff; /* TODO: Might want to clear only specific channels? */ 24301e04c3fSmrg clr.clear_bits[1] = 0xffffffff; 24401e04c3fSmrg clr.rect_x = 0; /* What about scissors? */ 24501e04c3fSmrg clr.rect_y = 0; 24601e04c3fSmrg clr.rect_w = surf->surf.width; 24701e04c3fSmrg clr.rect_h = surf->surf.height; 24801e04c3fSmrg 24901e04c3fSmrg emit_blt_clearimage(ctx->stream, &clr); 25001e04c3fSmrg 25101e04c3fSmrg /* This made the TS valid */ 25201e04c3fSmrg if (surf->surf.ts_size) { 25301e04c3fSmrg ctx->framebuffer.TS_COLOR_CLEAR_VALUE = new_clear_value; 2547ec681f3Smrg ctx->framebuffer.TS_COLOR_CLEAR_VALUE_EXT = new_clear_value >> 32; 25501e04c3fSmrg surf->level->ts_valid = true; 2567ec681f3Smrg ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS; 25701e04c3fSmrg } 25801e04c3fSmrg 25901e04c3fSmrg surf->level->clear_value = new_clear_value; 26001e04c3fSmrg resource_written(ctx, surf->base.texture); 26101e04c3fSmrg etna_resource(surf->base.texture)->seqno++; 26201e04c3fSmrg} 26301e04c3fSmrg 26401e04c3fSmrgstatic void 26501e04c3fSmrgetna_blit_clear_zs_blt(struct pipe_context *pctx, struct pipe_surface *dst, 26601e04c3fSmrg unsigned buffers, double depth, unsigned stencil) 26701e04c3fSmrg{ 26801e04c3fSmrg struct etna_context *ctx = etna_context(pctx); 26901e04c3fSmrg struct etna_surface *surf = etna_surface(dst); 27001e04c3fSmrg uint32_t new_clear_value = translate_clear_depth_stencil(surf->base.format, depth, stencil); 27101e04c3fSmrg uint32_t new_clear_bits = 0, clear_bits_depth, clear_bits_stencil; 27201e04c3fSmrg 27301e04c3fSmrg /* Get the channels to clear */ 27401e04c3fSmrg switch (surf->base.format) { 27501e04c3fSmrg case PIPE_FORMAT_Z16_UNORM: 2767ec681f3Smrg case PIPE_FORMAT_X8Z24_UNORM: 27701e04c3fSmrg clear_bits_depth = 0xffffffff; 27801e04c3fSmrg clear_bits_stencil = 0x00000000; 27901e04c3fSmrg break; 28001e04c3fSmrg case PIPE_FORMAT_S8_UINT_Z24_UNORM: 28101e04c3fSmrg clear_bits_depth = 0xffffff00; 28201e04c3fSmrg clear_bits_stencil = 0x000000ff; 28301e04c3fSmrg break; 28401e04c3fSmrg default: 28501e04c3fSmrg clear_bits_depth = clear_bits_stencil = 0xffffffff; 28601e04c3fSmrg break; 28701e04c3fSmrg } 28801e04c3fSmrg 28901e04c3fSmrg if (buffers & PIPE_CLEAR_DEPTH) 29001e04c3fSmrg new_clear_bits |= clear_bits_depth; 29101e04c3fSmrg if (buffers & PIPE_CLEAR_STENCIL) 29201e04c3fSmrg new_clear_bits |= clear_bits_stencil; 29301e04c3fSmrg 2947ec681f3Smrg /* if all bits are cleared, update TS clear value */ 2957ec681f3Smrg if (new_clear_bits == 0xffffffff) 2967ec681f3Smrg surf->level->clear_value = new_clear_value; 2977ec681f3Smrg 29801e04c3fSmrg /* TODO unduplicate this */ 29901e04c3fSmrg struct etna_resource *res = etna_resource(surf->base.texture); 30001e04c3fSmrg struct blt_clear_op clr = {}; 30101e04c3fSmrg clr.dest.addr.bo = res->bo; 30201e04c3fSmrg clr.dest.addr.offset = surf->surf.offset; 30301e04c3fSmrg clr.dest.addr.flags = ETNA_RELOC_WRITE; 30401e04c3fSmrg clr.dest.bpp = util_format_get_blocksize(surf->base.format); 30501e04c3fSmrg clr.dest.stride = surf->surf.stride; 30601e04c3fSmrg clr.dest.tiling = res->layout; 30701e04c3fSmrg 30801e04c3fSmrg if (surf->surf.ts_size) { 30901e04c3fSmrg clr.dest.use_ts = 1; 31001e04c3fSmrg clr.dest.ts_addr.bo = res->ts_bo; 3117ec681f3Smrg clr.dest.ts_addr.offset = surf->level->ts_offset; 31201e04c3fSmrg clr.dest.ts_addr.flags = ETNA_RELOC_WRITE; 3137ec681f3Smrg clr.dest.ts_clear_value[0] = surf->level->clear_value; 3147ec681f3Smrg clr.dest.ts_clear_value[1] = surf->level->clear_value; 3157ec681f3Smrg clr.dest.ts_mode = surf->level->ts_mode; 3167ec681f3Smrg clr.dest.ts_compress_fmt = surf->level->ts_compress_fmt; 31701e04c3fSmrg } 31801e04c3fSmrg 31901e04c3fSmrg clr.clear_value[0] = new_clear_value; 32001e04c3fSmrg clr.clear_value[1] = new_clear_value; 32101e04c3fSmrg clr.clear_bits[0] = new_clear_bits; 32201e04c3fSmrg clr.clear_bits[1] = new_clear_bits; 32301e04c3fSmrg clr.rect_x = 0; /* What about scissors? */ 32401e04c3fSmrg clr.rect_y = 0; 32501e04c3fSmrg clr.rect_w = surf->surf.width; 32601e04c3fSmrg clr.rect_h = surf->surf.height; 32701e04c3fSmrg 32801e04c3fSmrg emit_blt_clearimage(ctx->stream, &clr); 32901e04c3fSmrg 33001e04c3fSmrg /* This made the TS valid */ 33101e04c3fSmrg if (surf->surf.ts_size) { 3327ec681f3Smrg ctx->framebuffer.TS_DEPTH_CLEAR_VALUE = surf->level->clear_value; 33301e04c3fSmrg surf->level->ts_valid = true; 3347ec681f3Smrg ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS; 33501e04c3fSmrg } 33601e04c3fSmrg 33701e04c3fSmrg resource_written(ctx, surf->base.texture); 33801e04c3fSmrg etna_resource(surf->base.texture)->seqno++; 33901e04c3fSmrg} 34001e04c3fSmrg 34101e04c3fSmrgstatic void 3427ec681f3Smrgetna_clear_blt(struct pipe_context *pctx, unsigned buffers, const struct pipe_scissor_state *scissor_state, 34301e04c3fSmrg const union pipe_color_union *color, double depth, unsigned stencil) 34401e04c3fSmrg{ 34501e04c3fSmrg struct etna_context *ctx = etna_context(pctx); 3467ec681f3Smrg mtx_lock(&ctx->lock); 34701e04c3fSmrg 34801e04c3fSmrg etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23); 34901e04c3fSmrg etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH); 35001e04c3fSmrg 35101e04c3fSmrg if (buffers & PIPE_CLEAR_COLOR) { 35201e04c3fSmrg for (int idx = 0; idx < ctx->framebuffer_s.nr_cbufs; ++idx) { 35301e04c3fSmrg etna_blit_clear_color_blt(pctx, ctx->framebuffer_s.cbufs[idx], 35401e04c3fSmrg &color[idx]); 35501e04c3fSmrg } 35601e04c3fSmrg } 35701e04c3fSmrg 35801e04c3fSmrg if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && ctx->framebuffer_s.zsbuf != NULL) 35901e04c3fSmrg etna_blit_clear_zs_blt(pctx, ctx->framebuffer_s.zsbuf, buffers, depth, stencil); 36001e04c3fSmrg 36101e04c3fSmrg etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_BLT); 36201e04c3fSmrg 36301e04c3fSmrg if ((buffers & PIPE_CLEAR_COLOR) && (buffers & PIPE_CLEAR_DEPTH)) 36401e04c3fSmrg etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23); 36501e04c3fSmrg else 36601e04c3fSmrg etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000002); 3677ec681f3Smrg mtx_unlock(&ctx->lock); 36801e04c3fSmrg} 36901e04c3fSmrg 37001e04c3fSmrgstatic bool 37101e04c3fSmrgetna_try_blt_blit(struct pipe_context *pctx, 37201e04c3fSmrg const struct pipe_blit_info *blit_info) 37301e04c3fSmrg{ 37401e04c3fSmrg struct etna_context *ctx = etna_context(pctx); 37501e04c3fSmrg struct etna_resource *src = etna_resource(blit_info->src.resource); 37601e04c3fSmrg struct etna_resource *dst = etna_resource(blit_info->dst.resource); 37701e04c3fSmrg int msaa_xscale = 1, msaa_yscale = 1; 37801e04c3fSmrg 37901e04c3fSmrg /* Ensure that the level is valid */ 38001e04c3fSmrg assert(blit_info->src.level <= src->base.last_level); 38101e04c3fSmrg assert(blit_info->dst.level <= dst->base.last_level); 38201e04c3fSmrg 3837ec681f3Smrg if (!translate_samples_to_xyscale(src->base.nr_samples, &msaa_xscale, &msaa_yscale)) 3847ec681f3Smrg return false; 38501e04c3fSmrg 38601e04c3fSmrg /* The width/height are in pixels; they do not change as a result of 38701e04c3fSmrg * multi-sampling. So, when blitting from a 4x multisampled surface 38801e04c3fSmrg * to a non-multisampled surface, the width and height will be 38901e04c3fSmrg * identical. As we do not support scaling, reject different sizes. 39001e04c3fSmrg * TODO: could handle 2x downsample here with emit_blt_genmipmaps */ 39101e04c3fSmrg if (blit_info->dst.box.width != blit_info->src.box.width || 39201e04c3fSmrg blit_info->dst.box.height != abs(blit_info->src.box.height)) { /* allow y flip for glTexImage2D */ 39301e04c3fSmrg DBG("scaling requested: source %dx%d destination %dx%d", 39401e04c3fSmrg blit_info->src.box.width, blit_info->src.box.height, 39501e04c3fSmrg blit_info->dst.box.width, blit_info->dst.box.height); 3967ec681f3Smrg return false; 39701e04c3fSmrg } 39801e04c3fSmrg 39901e04c3fSmrg /* No masks - not sure if BLT can copy individual channels */ 40001e04c3fSmrg unsigned mask = util_format_get_mask(blit_info->dst.format); 40101e04c3fSmrg if ((blit_info->mask & mask) != mask) { 40201e04c3fSmrg DBG("sub-mask requested: 0x%02x vs format mask 0x%02x", blit_info->mask, mask); 4037ec681f3Smrg return false; 40401e04c3fSmrg } 40501e04c3fSmrg 4067ec681f3Smrg /* Only support same format (used tiling/detiling) blits for now. 4077ec681f3Smrg * TODO: figure out which different-format blits are possible and test them 4087ec681f3Smrg * - need to use correct swizzle 4097ec681f3Smrg * - set sRGB bits correctly 4107ec681f3Smrg * - avoid trying to convert between float/int formats? 41101e04c3fSmrg */ 4127ec681f3Smrg if (blit_info->src.format != blit_info->dst.format) 4137ec681f3Smrg return false; 4147ec681f3Smrg 4157ec681f3Smrg uint32_t format = etna_compatible_blt_format(blit_info->dst.format); 4167ec681f3Smrg if (format == ETNA_NO_MATCH) 4177ec681f3Smrg return false; 4187ec681f3Smrg 4197ec681f3Smrg if (blit_info->scissor_enable || 42001e04c3fSmrg blit_info->dst.box.depth != blit_info->src.box.depth || 42101e04c3fSmrg blit_info->dst.box.depth != 1) { 4227ec681f3Smrg return false; 42301e04c3fSmrg } 42401e04c3fSmrg 42501e04c3fSmrg struct etna_resource_level *src_lev = &src->levels[blit_info->src.level]; 42601e04c3fSmrg struct etna_resource_level *dst_lev = &dst->levels[blit_info->dst.level]; 42701e04c3fSmrg 4287ec681f3Smrg /* if we asked for in-place resolve, return immediately if ts isn't valid 4297ec681f3Smrg * do this check separately because it applies when compression is used, but 4307ec681f3Smrg * we can't use inplace resolve path with compression 4317ec681f3Smrg */ 43201e04c3fSmrg if (src == dst) { 43301e04c3fSmrg assert(!memcmp(&blit_info->src, &blit_info->dst, sizeof(blit_info->src))); 43401e04c3fSmrg if (!src_lev->ts_size || !src_lev->ts_valid) /* No TS, no worries */ 4357ec681f3Smrg return true; 4367ec681f3Smrg } 4377ec681f3Smrg 4387ec681f3Smrg mtx_lock(&ctx->lock); 4397ec681f3Smrg /* Kick off BLT here */ 4407ec681f3Smrg if (src == dst && src_lev->ts_compress_fmt < 0) { 4417ec681f3Smrg /* Resolve-in-place */ 44201e04c3fSmrg struct blt_inplace_op op = {}; 44301e04c3fSmrg 44401e04c3fSmrg op.addr.bo = src->bo; 44501e04c3fSmrg op.addr.offset = src_lev->offset + blit_info->src.box.z * src_lev->layer_stride; 44601e04c3fSmrg op.addr.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE; 44701e04c3fSmrg op.ts_addr.bo = src->ts_bo; 44801e04c3fSmrg op.ts_addr.offset = src_lev->ts_offset + blit_info->src.box.z * src_lev->ts_layer_stride; 44901e04c3fSmrg op.ts_addr.flags = ETNA_RELOC_READ; 45001e04c3fSmrg op.ts_clear_value[0] = src_lev->clear_value; 45101e04c3fSmrg op.ts_clear_value[1] = src_lev->clear_value; 4527ec681f3Smrg op.ts_mode = src_lev->ts_mode; 4537ec681f3Smrg op.num_tiles = DIV_ROUND_UP(src_lev->size, src_lev->ts_mode ? 256 : 128); 45401e04c3fSmrg op.bpp = util_format_get_blocksize(src->base.format); 45501e04c3fSmrg 45601e04c3fSmrg etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23); 45701e04c3fSmrg etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, 0x00000001); 45801e04c3fSmrg emit_blt_inplace(ctx->stream, &op); 45901e04c3fSmrg } else { 46001e04c3fSmrg /* Copy op */ 46101e04c3fSmrg struct blt_imgcopy_op op = {}; 46201e04c3fSmrg 46301e04c3fSmrg op.src.addr.bo = src->bo; 46401e04c3fSmrg op.src.addr.offset = src_lev->offset + blit_info->src.box.z * src_lev->layer_stride; 46501e04c3fSmrg op.src.addr.flags = ETNA_RELOC_READ; 4667ec681f3Smrg op.src.format = format; 46701e04c3fSmrg op.src.stride = src_lev->stride; 46801e04c3fSmrg op.src.tiling = src->layout; 46901e04c3fSmrg for (unsigned x=0; x<4; ++x) 4707ec681f3Smrg op.src.swizzle[x] = x; 47101e04c3fSmrg 47201e04c3fSmrg if (src_lev->ts_size && src_lev->ts_valid) { 47301e04c3fSmrg op.src.use_ts = 1; 47401e04c3fSmrg op.src.ts_addr.bo = src->ts_bo; 47501e04c3fSmrg op.src.ts_addr.offset = src_lev->ts_offset + blit_info->src.box.z * src_lev->ts_layer_stride; 47601e04c3fSmrg op.src.ts_addr.flags = ETNA_RELOC_READ; 47701e04c3fSmrg op.src.ts_clear_value[0] = src_lev->clear_value; 47801e04c3fSmrg op.src.ts_clear_value[1] = src_lev->clear_value; 4797ec681f3Smrg op.src.ts_mode = src_lev->ts_mode; 4807ec681f3Smrg op.src.ts_compress_fmt = src_lev->ts_compress_fmt; 48101e04c3fSmrg } 48201e04c3fSmrg 48301e04c3fSmrg op.dest.addr.bo = dst->bo; 48401e04c3fSmrg op.dest.addr.offset = dst_lev->offset + blit_info->dst.box.z * dst_lev->layer_stride; 48501e04c3fSmrg op.dest.addr.flags = ETNA_RELOC_WRITE; 4867ec681f3Smrg op.dest.format = format; 48701e04c3fSmrg op.dest.stride = dst_lev->stride; 48801e04c3fSmrg op.dest.tiling = dst->layout; 48901e04c3fSmrg for (unsigned x=0; x<4; ++x) 4907ec681f3Smrg op.dest.swizzle[x] = x; 49101e04c3fSmrg 49201e04c3fSmrg op.dest_x = blit_info->dst.box.x; 49301e04c3fSmrg op.dest_y = blit_info->dst.box.y; 49401e04c3fSmrg op.src_x = blit_info->src.box.x; 49501e04c3fSmrg op.src_y = blit_info->src.box.y; 49601e04c3fSmrg op.rect_w = blit_info->dst.box.width; 49701e04c3fSmrg op.rect_h = blit_info->dst.box.height; 49801e04c3fSmrg 49901e04c3fSmrg if (blit_info->src.box.height < 0) { /* flipped? fix up base y */ 50001e04c3fSmrg op.flip_y = 1; 50101e04c3fSmrg op.src_y += blit_info->src.box.height; 50201e04c3fSmrg } 50301e04c3fSmrg 50401e04c3fSmrg assert(op.src_x < src_lev->padded_width); 50501e04c3fSmrg assert(op.src_y < src_lev->padded_height); 50601e04c3fSmrg assert((op.src_x + op.rect_w) <= src_lev->padded_width); 50701e04c3fSmrg assert((op.src_y + op.rect_h) <= src_lev->padded_height); 50801e04c3fSmrg assert(op.dest_x < dst_lev->padded_width); 50901e04c3fSmrg assert(op.dest_y < dst_lev->padded_height); 51001e04c3fSmrg assert((op.dest_x + op.rect_w) <= dst_lev->padded_width); 51101e04c3fSmrg assert((op.dest_y + op.rect_h) <= dst_lev->padded_height); 51201e04c3fSmrg 51301e04c3fSmrg etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23); 51401e04c3fSmrg etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, 0x00000001); 51501e04c3fSmrg emit_blt_copyimage(ctx->stream, &op); 51601e04c3fSmrg } 51701e04c3fSmrg 51801e04c3fSmrg /* Make FE wait for BLT, in case we want to do something with the image next. 51901e04c3fSmrg * This probably shouldn't be here, and depend on what is done with the resource. 52001e04c3fSmrg */ 52101e04c3fSmrg etna_stall(ctx->stream, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT); 52201e04c3fSmrg etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23); 52301e04c3fSmrg 524361fc4cbSmaya resource_read(ctx, &src->base); 52501e04c3fSmrg resource_written(ctx, &dst->base); 526361fc4cbSmaya 52701e04c3fSmrg dst->seqno++; 52801e04c3fSmrg dst_lev->ts_valid = false; 5297ec681f3Smrg mtx_unlock(&ctx->lock); 53001e04c3fSmrg 5317ec681f3Smrg return true; 53201e04c3fSmrg} 53301e04c3fSmrg 5347ec681f3Smrgstatic bool 53501e04c3fSmrgetna_blit_blt(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) 53601e04c3fSmrg{ 5377ec681f3Smrg if (blit_info->src.resource->nr_samples > 1 && 5387ec681f3Smrg blit_info->dst.resource->nr_samples <= 1 && 5397ec681f3Smrg !util_format_is_depth_or_stencil(blit_info->src.resource->format) && 5407ec681f3Smrg !util_format_is_pure_integer(blit_info->src.resource->format)) { 54101e04c3fSmrg DBG("color resolve unimplemented"); 5427ec681f3Smrg return false; 54301e04c3fSmrg } 54401e04c3fSmrg 5457ec681f3Smrg return etna_try_blt_blit(pctx, blit_info); 54601e04c3fSmrg} 54701e04c3fSmrg 54801e04c3fSmrgvoid 54901e04c3fSmrgetna_clear_blit_blt_init(struct pipe_context *pctx) 55001e04c3fSmrg{ 5517ec681f3Smrg struct etna_context *ctx = etna_context(pctx); 5527ec681f3Smrg 55301e04c3fSmrg DBG("etnaviv: Using BLT blit engine"); 55401e04c3fSmrg pctx->clear = etna_clear_blt; 5557ec681f3Smrg ctx->blit = etna_blit_blt; 55601e04c3fSmrg} 557