Commit e2898c5f authored by Nicolai Haehnle's avatar Nicolai Haehnle Committed by Dave Airlie

drm/radeon: r300_cmdbuf: Always emit INDX_BUFFER immediately after DRAW_INDEX

DRAW_INDEX writes a vertex count to VAP_VF_CNTL. Docs say that behaviour
is undefined (i.e. lockups happen) when this write is not followed by the
right number of vertex indices.

Thus we used to do the wrong thing when drawing across many cliprects was
necessary, because we emitted a sequence
DRAW_INDEX, DRAW_INDEX, INDX_BUFFER, INDX_BUFFER
instead of
DRAW_INDEX, INDX_BUFFER, DRAW_INDEX, INDX_BUFFER
The latter is what we're doing now and which ought to be correct.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 54f961a6
...@@ -577,32 +577,77 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, ...@@ -577,32 +577,77 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
return 0; return 0;
} }
static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf) drm_radeon_kcmd_buffer_t *cmdbuf)
{ {
u32 *cmd = (u32 *) cmdbuf->buf; u32 *cmd;
int count, ret; int count;
int expected_count;
RING_LOCALS; RING_LOCALS;
count=(cmd[0]>>16) & 0x3fff; cmd = (u32 *) cmdbuf->buf;
count = (cmd[0]>>16) & 0x3fff;
expected_count = cmd[1] >> 16;
if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
expected_count = (expected_count+1)/2;
if (count && count != expected_count) {
DRM_ERROR("3D_DRAW_INDX_2: packet size %i, expected %i\n",
count, expected_count);
return -EINVAL;
}
BEGIN_RING(count+2);
OUT_RING(cmd[0]);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
ADVANCE_RING();
cmdbuf->buf += (count+2)*4;
cmdbuf->bufsz -= (count+2)*4;
if (!count) {
drm_r300_cmd_header_t header;
if (cmdbuf->bufsz < 4*4 + sizeof(header)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n");
return -EINVAL;
}
header.u = *(unsigned int *)cmdbuf->buf;
cmdbuf->buf += sizeof(header);
cmdbuf->bufsz -= sizeof(header);
cmd = (u32 *) cmdbuf->buf;
if (header.header.cmd_type != R300_CMD_PACKET3 ||
header.packet3.packet != R300_CMD_PACKET3_RAW ||
cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n");
return -EINVAL;
}
if ((cmd[1] & 0x8000ffff) != 0x80000810) { if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return -EINVAL; return -EINVAL;
} }
ret = !radeon_check_offset(dev_priv, cmd[2]); if (!radeon_check_offset(dev_priv, cmd[2])) {
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return -EINVAL; return -EINVAL;
} }
if (cmd[3] != expected_count) {
DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n",
cmd[3], expected_count);
return -EINVAL;
}
BEGIN_RING(count+2); BEGIN_RING(4);
OUT_RING(cmd[0]); OUT_RING(cmd[0]);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1); OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += (count+2)*4; cmdbuf->buf += 4*4;
cmdbuf->bufsz -= (count+2)*4; cmdbuf->bufsz -= 4*4;
}
return 0; return 0;
} }
...@@ -648,18 +693,21 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, ...@@ -648,18 +693,21 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
return r300_emit_bitblt_multi(dev_priv, cmdbuf); return r300_emit_bitblt_multi(dev_priv, cmdbuf);
case RADEON_CP_INDX_BUFFER: case RADEON_CP_INDX_BUFFER:
/* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ DRM_ERROR("packet3 INDX_BUFFER without preceding 3D_DRAW_INDX_2 is illegal.\n");
return r300_emit_indx_buffer(dev_priv, cmdbuf); return -EINVAL;
case RADEON_CP_3D_DRAW_IMMD_2: case RADEON_CP_3D_DRAW_IMMD_2:
/* triggers drawing using in-packet vertex data */ /* triggers drawing using in-packet vertex data */
case RADEON_CP_3D_DRAW_VBUF_2: case RADEON_CP_3D_DRAW_VBUF_2:
/* triggers drawing of vertex buffers setup elsewhere */ /* triggers drawing of vertex buffers setup elsewhere */
dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
RADEON_PURGE_EMITED);
break;
case RADEON_CP_3D_DRAW_INDX_2: case RADEON_CP_3D_DRAW_INDX_2:
/* triggers drawing using indices to vertex buffer */ /* triggers drawing using indices to vertex buffer */
/* whenever we send vertex we clear flush & purge */ /* whenever we send vertex we clear flush & purge */
dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
RADEON_PURGE_EMITED); RADEON_PURGE_EMITED);
break; return r300_emit_draw_indx_2(dev_priv, cmdbuf);
case RADEON_WAIT_FOR_IDLE: case RADEON_WAIT_FOR_IDLE:
case RADEON_CP_NOP: case RADEON_CP_NOP:
/* these packets are safe */ /* these packets are safe */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment