aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/radeon/r600_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_cs.c')
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c196
1 files changed, 148 insertions, 48 deletions
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index ca87f7afaf2..f37676d7f21 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -47,18 +47,23 @@ struct r600_cs_track {
u32 npipes;
/* value we track */
u32 sq_config;
+ u32 log_nsamples;
u32 nsamples;
u32 cb_color_base_last[8];
struct radeon_bo *cb_color_bo[8];
u64 cb_color_bo_mc[8];
- u32 cb_color_bo_offset[8];
- struct radeon_bo *cb_color_frag_bo[8]; /* unused */
- struct radeon_bo *cb_color_tile_bo[8]; /* unused */
+ u64 cb_color_bo_offset[8];
+ struct radeon_bo *cb_color_frag_bo[8];
+ u64 cb_color_frag_offset[8];
+ struct radeon_bo *cb_color_tile_bo[8];
+ u64 cb_color_tile_offset[8];
+ u32 cb_color_mask[8];
u32 cb_color_info[8];
u32 cb_color_view[8];
u32 cb_color_size_idx[8]; /* unused */
u32 cb_target_mask;
u32 cb_shader_mask; /* unused */
+ bool is_resolve;
u32 cb_color_size[8];
u32 vgt_strmout_en;
u32 vgt_strmout_buffer_en;
@@ -311,7 +316,15 @@ static void r600_cs_track_init(struct r600_cs_track *track)
track->cb_color_bo[i] = NULL;
track->cb_color_bo_offset[i] = 0xFFFFFFFF;
track->cb_color_bo_mc[i] = 0xFFFFFFFF;
- }
+ track->cb_color_frag_bo[i] = NULL;
+ track->cb_color_frag_offset[i] = 0xFFFFFFFF;
+ track->cb_color_tile_bo[i] = NULL;
+ track->cb_color_tile_offset[i] = 0xFFFFFFFF;
+ track->cb_color_mask[i] = 0xFFFFFFFF;
+ }
+ track->is_resolve = false;
+ track->nsamples = 16;
+ track->log_nsamples = 4;
track->cb_target_mask = 0xFFFFFFFF;
track->cb_shader_mask = 0xFFFFFFFF;
track->cb_dirty = true;
@@ -348,11 +361,9 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
volatile u32 *ib = p->ib.ptr;
unsigned array_mode;
u32 format;
+ /* When resolve is used, the second colorbuffer has always 1 sample. */
+ unsigned nsamples = track->is_resolve && i == 1 ? 1 : track->nsamples;
- if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
- dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
- return -EINVAL;
- }
size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
format = G_0280A0_FORMAT(track->cb_color_info[i]);
if (!r600_fmt_is_valid_color(format)) {
@@ -375,7 +386,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
array_check.group_size = track->group_size;
array_check.nbanks = track->nbanks;
array_check.npipes = track->npipes;
- array_check.nsamples = track->nsamples;
+ array_check.nsamples = nsamples;
array_check.blocksize = r600_fmt_get_blocksize(format);
if (r600_get_array_mode_alignment(&array_check,
&pitch_align, &height_align, &depth_align, &base_align)) {
@@ -420,7 +431,8 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
}
/* check offset */
- tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * r600_fmt_get_blocksize(format);
+ tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) *
+ r600_fmt_get_blocksize(format) * nsamples;
switch (array_mode) {
default:
case V_0280A0_ARRAY_LINEAR_GENERAL:
@@ -441,7 +453,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
* broken userspace.
*/
} else {
- dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big (%d %d) (%d %d %d)\n",
+ dev_warn(p->dev, "%s offset[%d] %d %llu %d %lu too big (%d %d) (%d %d %d)\n",
__func__, i, array_mode,
track->cb_color_bo_offset[i], tmp,
radeon_bo_size(track->cb_color_bo[i]),
@@ -458,6 +470,51 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) |
S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
ib[track->cb_color_size_idx[i]] = tmp;
+
+ /* FMASK/CMASK */
+ switch (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
+ case V_0280A0_TILE_DISABLE:
+ break;
+ case V_0280A0_FRAG_ENABLE:
+ if (track->nsamples > 1) {
+ uint32_t tile_max = G_028100_FMASK_TILE_MAX(track->cb_color_mask[i]);
+ /* the tile size is 8x8, but the size is in units of bits.
+ * for bytes, do just * 8. */
+ uint32_t bytes = track->nsamples * track->log_nsamples * 8 * (tile_max + 1);
+
+ if (bytes + track->cb_color_frag_offset[i] >
+ radeon_bo_size(track->cb_color_frag_bo[i])) {
+ dev_warn(p->dev, "%s FMASK_TILE_MAX too large "
+ "(tile_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n",
+ __func__, tile_max, bytes,
+ track->cb_color_frag_offset[i],
+ radeon_bo_size(track->cb_color_frag_bo[i]));
+ return -EINVAL;
+ }
+ }
+ /* fall through */
+ case V_0280A0_CLEAR_ENABLE:
+ {
+ uint32_t block_max = G_028100_CMASK_BLOCK_MAX(track->cb_color_mask[i]);
+ /* One block = 128x128 pixels, one 8x8 tile has 4 bits..
+ * (128*128) / (8*8) / 2 = 128 bytes per block. */
+ uint32_t bytes = (block_max + 1) * 128;
+
+ if (bytes + track->cb_color_tile_offset[i] >
+ radeon_bo_size(track->cb_color_tile_bo[i])) {
+ dev_warn(p->dev, "%s CMASK_BLOCK_MAX too large "
+ "(block_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n",
+ __func__, block_max, bytes,
+ track->cb_color_tile_offset[i],
+ radeon_bo_size(track->cb_color_tile_bo[i]));
+ return -EINVAL;
+ }
+ break;
+ }
+ default:
+ dev_warn(p->dev, "%s invalid tile mode\n", __func__);
+ return -EINVAL;
+ }
return 0;
}
@@ -566,7 +623,7 @@ static int r600_cs_track_validate_db(struct radeon_cs_parser *p)
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
- tmp = ntiles * bpe * 64 * nviews;
+ tmp = ntiles * bpe * 64 * nviews * track->nsamples;
if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
array_mode,
@@ -746,6 +803,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
*/
if (track->cb_dirty) {
tmp = track->cb_target_mask;
+
+ /* We must check both colorbuffers for RESOLVE. */
+ if (track->is_resolve) {
+ tmp |= 0xff;
+ }
+
for (i = 0; i < 8; i++) {
if ((tmp >> (i * 4)) & 0xF) {
/* at least one component is enabled */
@@ -764,8 +827,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
}
/* Check depth buffer */
- if (track->db_dirty && (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
- G_028800_Z_ENABLE(track->db_depth_control))) {
+ if (track->db_dirty &&
+ G_028010_FORMAT(track->db_depth_info) != V_028010_DEPTH_INVALID &&
+ (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
+ G_028800_Z_ENABLE(track->db_depth_control))) {
r = r600_cs_track_validate_db(p);
if (r)
return r;
@@ -1229,9 +1294,15 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
break;
case R_028C04_PA_SC_AA_CONFIG:
tmp = G_028C04_MSAA_NUM_SAMPLES(radeon_get_ib_value(p, idx));
+ track->log_nsamples = tmp;
track->nsamples = 1 << tmp;
track->cb_dirty = true;
break;
+ case R_028808_CB_COLOR_CONTROL:
+ tmp = G_028808_SPECIAL_OP(radeon_get_ib_value(p, idx));
+ track->is_resolve = tmp == V_028808_SPECIAL_RESOLVE_BOX;
+ track->cb_dirty = true;
+ break;
case R_0280A0_CB_COLOR0_INFO:
case R_0280A4_CB_COLOR1_INFO:
case R_0280A8_CB_COLOR2_INFO:
@@ -1310,16 +1381,21 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
return -EINVAL;
}
- ib[idx] = track->cb_color_base_last[tmp];
track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp];
+ track->cb_color_frag_offset[tmp] = track->cb_color_bo_offset[tmp];
+ ib[idx] = track->cb_color_base_last[tmp];
} else {
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
return -EINVAL;
}
- ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color_frag_bo[tmp] = reloc->robj;
+ track->cb_color_frag_offset[tmp] = (u64)ib[idx] << 8;
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ }
+ if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
+ track->cb_dirty = true;
}
break;
case R_0280C0_CB_COLOR0_TILE:
@@ -1336,16 +1412,35 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
return -EINVAL;
}
- ib[idx] = track->cb_color_base_last[tmp];
track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp];
+ track->cb_color_tile_offset[tmp] = track->cb_color_bo_offset[tmp];
+ ib[idx] = track->cb_color_base_last[tmp];
} else {
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
return -EINVAL;
}
- ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color_tile_bo[tmp] = reloc->robj;
+ track->cb_color_tile_offset[tmp] = (u64)ib[idx] << 8;
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ }
+ if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
+ track->cb_dirty = true;
+ }
+ break;
+ case R_028100_CB_COLOR0_MASK:
+ case R_028104_CB_COLOR1_MASK:
+ case R_028108_CB_COLOR2_MASK:
+ case R_02810C_CB_COLOR3_MASK:
+ case R_028110_CB_COLOR4_MASK:
+ case R_028114_CB_COLOR5_MASK:
+ case R_028118_CB_COLOR6_MASK:
+ case R_02811C_CB_COLOR7_MASK:
+ tmp = (reg - R_028100_CB_COLOR0_MASK) / 4;
+ track->cb_color_mask[tmp] = radeon_get_ib_value(p, idx);
+ if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
+ track->cb_dirty = true;
}
break;
case CB_COLOR0_BASE:
@@ -1490,7 +1585,7 @@ unsigned r600_mip_minify(unsigned size, unsigned level)
}
static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel,
- unsigned w0, unsigned h0, unsigned d0, unsigned format,
+ unsigned w0, unsigned h0, unsigned d0, unsigned nsamples, unsigned format,
unsigned block_align, unsigned height_align, unsigned base_align,
unsigned *l0_size, unsigned *mipmap_size)
{
@@ -1518,7 +1613,7 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel,
depth = r600_mip_minify(d0, i);
- size = nbx * nby * blocksize;
+ size = nbx * nby * blocksize * nsamples;
if (nfaces)
size *= nfaces;
else
@@ -1557,13 +1652,14 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
u32 tiling_flags)
{
struct r600_cs_track *track = p->track;
- u32 nfaces, llevel, blevel, w0, h0, d0;
- u32 word0, word1, l0_size, mipmap_size, word2, word3;
+ u32 dim, nfaces, llevel, blevel, w0, h0, d0;
+ u32 word0, word1, l0_size, mipmap_size, word2, word3, word4, word5;
u32 height_align, pitch, pitch_align, depth_align;
- u32 array, barray, larray;
+ u32 barray, larray;
u64 base_align;
struct array_mode_checker array_check;
u32 format;
+ bool is_array;
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
@@ -1581,12 +1677,28 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
}
word1 = radeon_get_ib_value(p, idx + 1);
+ word2 = radeon_get_ib_value(p, idx + 2) << 8;
+ word3 = radeon_get_ib_value(p, idx + 3) << 8;
+ word4 = radeon_get_ib_value(p, idx + 4);
+ word5 = radeon_get_ib_value(p, idx + 5);
+ dim = G_038000_DIM(word0);
w0 = G_038000_TEX_WIDTH(word0) + 1;
+ pitch = (G_038000_PITCH(word0) + 1) * 8;
h0 = G_038004_TEX_HEIGHT(word1) + 1;
d0 = G_038004_TEX_DEPTH(word1);
+ format = G_038004_DATA_FORMAT(word1);
+ blevel = G_038010_BASE_LEVEL(word4);
+ llevel = G_038014_LAST_LEVEL(word5);
+ /* pitch in texels */
+ array_check.array_mode = G_038000_TILE_MODE(word0);
+ array_check.group_size = track->group_size;
+ array_check.nbanks = track->nbanks;
+ array_check.npipes = track->npipes;
+ array_check.nsamples = 1;
+ array_check.blocksize = r600_fmt_get_blocksize(format);
nfaces = 1;
- array = 0;
- switch (G_038000_DIM(word0)) {
+ is_array = false;
+ switch (dim) {
case V_038000_SQ_TEX_DIM_1D:
case V_038000_SQ_TEX_DIM_2D:
case V_038000_SQ_TEX_DIM_3D:
@@ -1599,29 +1711,25 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
break;
case V_038000_SQ_TEX_DIM_1D_ARRAY:
case V_038000_SQ_TEX_DIM_2D_ARRAY:
- array = 1;
+ is_array = true;
break;
- case V_038000_SQ_TEX_DIM_2D_MSAA:
case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA:
+ is_array = true;
+ /* fall through */
+ case V_038000_SQ_TEX_DIM_2D_MSAA:
+ array_check.nsamples = 1 << llevel;
+ llevel = 0;
+ break;
default:
dev_warn(p->dev, "this kernel doesn't support %d texture dim\n", G_038000_DIM(word0));
return -EINVAL;
}
- format = G_038004_DATA_FORMAT(word1);
if (!r600_fmt_is_valid_texture(format, p->family)) {
dev_warn(p->dev, "%s:%d texture invalid format %d\n",
__func__, __LINE__, format);
return -EINVAL;
}
- /* pitch in texels */
- pitch = (G_038000_PITCH(word0) + 1) * 8;
- array_check.array_mode = G_038000_TILE_MODE(word0);
- array_check.group_size = track->group_size;
- array_check.nbanks = track->nbanks;
- array_check.npipes = track->npipes;
- array_check.nsamples = 1;
- array_check.blocksize = r600_fmt_get_blocksize(format);
if (r600_get_array_mode_alignment(&array_check,
&pitch_align, &height_align, &depth_align, &base_align)) {
dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
@@ -1647,24 +1755,17 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
return -EINVAL;
}
- word2 = radeon_get_ib_value(p, idx + 2) << 8;
- word3 = radeon_get_ib_value(p, idx + 3) << 8;
-
- word0 = radeon_get_ib_value(p, idx + 4);
- word1 = radeon_get_ib_value(p, idx + 5);
- blevel = G_038010_BASE_LEVEL(word0);
- llevel = G_038014_LAST_LEVEL(word1);
if (blevel > llevel) {
dev_warn(p->dev, "texture blevel %d > llevel %d\n",
blevel, llevel);
}
- if (array == 1) {
- barray = G_038014_BASE_ARRAY(word1);
- larray = G_038014_LAST_ARRAY(word1);
+ if (is_array) {
+ barray = G_038014_BASE_ARRAY(word5);
+ larray = G_038014_LAST_ARRAY(word5);
nfaces = larray - barray + 1;
}
- r600_texture_size(nfaces, blevel, llevel, w0, h0, d0, format,
+ r600_texture_size(nfaces, blevel, llevel, w0, h0, d0, array_check.nsamples, format,
pitch_align, height_align, base_align,
&l0_size, &mipmap_size);
/* using get ib will give us the offset into the texture bo */
@@ -1677,7 +1778,6 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
return -EINVAL;
}
/* using get ib will give us the offset into the mipmap bo */
- word3 = radeon_get_ib_value(p, idx + 3) << 8;
if ((mipmap_size + word3) > radeon_bo_size(mipmap)) {
/*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
w0, h0, format, blevel, nlevels, word3, mipmap_size, radeon_bo_size(texture));*/