aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorNicolai Haehnle <nhaehnle@gmail.com>2008-08-12 19:49:15 -0400
committerDave Airlie <airlied@linux.ie>2008-08-24 16:35:05 -0400
commite2898c5fdd91f54c9c84fbf7d32edb8e4dfda574 (patch)
treec9939a528d7e352dbf0360aec5c19a7b041bc658 /drivers/gpu
parent54f961a628b737f66710eca0b0d95346645dd33e (diff)
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: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/radeon/r300_cmdbuf.c80
1 files changed, 64 insertions, 16 deletions
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c
index 4b3bd6303daf..b1fdfc61f27d 100644
--- a/drivers/gpu/drm/radeon/r300_cmdbuf.c
+++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c
@@ -577,22 +577,23 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
577 return 0; 577 return 0;
578} 578}
579 579
580static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, 580static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
581 drm_radeon_kcmd_buffer_t *cmdbuf) 581 drm_radeon_kcmd_buffer_t *cmdbuf)
582{ 582{
583 u32 *cmd = (u32 *) cmdbuf->buf; 583 u32 *cmd;
584 int count, ret; 584 int count;
585 int expected_count;
585 RING_LOCALS; 586 RING_LOCALS;
586 587
587 count=(cmd[0]>>16) & 0x3fff; 588 cmd = (u32 *) cmdbuf->buf;
589 count = (cmd[0]>>16) & 0x3fff;
590 expected_count = cmd[1] >> 16;
591 if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
592 expected_count = (expected_count+1)/2;
588 593
589 if ((cmd[1] & 0x8000ffff) != 0x80000810) { 594 if (count && count != expected_count) {
590 DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); 595 DRM_ERROR("3D_DRAW_INDX_2: packet size %i, expected %i\n",
591 return -EINVAL; 596 count, expected_count);
592 }
593 ret = !radeon_check_offset(dev_priv, cmd[2]);
594 if (ret) {
595 DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
596 return -EINVAL; 597 return -EINVAL;
597 } 598 }
598 599
@@ -604,6 +605,50 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
604 cmdbuf->buf += (count+2)*4; 605 cmdbuf->buf += (count+2)*4;
605 cmdbuf->bufsz -= (count+2)*4; 606 cmdbuf->bufsz -= (count+2)*4;
606 607
608 if (!count) {
609 drm_r300_cmd_header_t header;
610
611 if (cmdbuf->bufsz < 4*4 + sizeof(header)) {
612 DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n");
613 return -EINVAL;
614 }
615
616 header.u = *(unsigned int *)cmdbuf->buf;
617
618 cmdbuf->buf += sizeof(header);
619 cmdbuf->bufsz -= sizeof(header);
620 cmd = (u32 *) cmdbuf->buf;
621
622 if (header.header.cmd_type != R300_CMD_PACKET3 ||
623 header.packet3.packet != R300_CMD_PACKET3_RAW ||
624 cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
625 DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n");
626 return -EINVAL;
627 }
628
629 if ((cmd[1] & 0x8000ffff) != 0x80000810) {
630 DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
631 return -EINVAL;
632 }
633 if (!radeon_check_offset(dev_priv, cmd[2])) {
634 DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
635 return -EINVAL;
636 }
637 if (cmd[3] != expected_count) {
638 DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n",
639 cmd[3], expected_count);
640 return -EINVAL;
641 }
642
643 BEGIN_RING(4);
644 OUT_RING(cmd[0]);
645 OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3);
646 ADVANCE_RING();
647
648 cmdbuf->buf += 4*4;
649 cmdbuf->bufsz -= 4*4;
650 }
651
607 return 0; 652 return 0;
608} 653}
609 654
@@ -648,18 +693,21 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
648 return r300_emit_bitblt_multi(dev_priv, cmdbuf); 693 return r300_emit_bitblt_multi(dev_priv, cmdbuf);
649 694
650 case RADEON_CP_INDX_BUFFER: 695 case RADEON_CP_INDX_BUFFER:
651 /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ 696 DRM_ERROR("packet3 INDX_BUFFER without preceding 3D_DRAW_INDX_2 is illegal.\n");
652 return r300_emit_indx_buffer(dev_priv, cmdbuf); 697 return -EINVAL;
653 case RADEON_CP_3D_DRAW_IMMD_2: 698 case RADEON_CP_3D_DRAW_IMMD_2:
654 /* triggers drawing using in-packet vertex data */ 699 /* triggers drawing using in-packet vertex data */
655 case RADEON_CP_3D_DRAW_VBUF_2: 700 case RADEON_CP_3D_DRAW_VBUF_2:
656 /* triggers drawing of vertex buffers setup elsewhere */ 701 /* triggers drawing of vertex buffers setup elsewhere */
702 dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
703 RADEON_PURGE_EMITED);
704 break;
657 case RADEON_CP_3D_DRAW_INDX_2: 705 case RADEON_CP_3D_DRAW_INDX_2:
658 /* triggers drawing using indices to vertex buffer */ 706 /* triggers drawing using indices to vertex buffer */
659 /* whenever we send vertex we clear flush & purge */ 707 /* whenever we send vertex we clear flush & purge */
660 dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | 708 dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
661 RADEON_PURGE_EMITED); 709 RADEON_PURGE_EMITED);
662 break; 710 return r300_emit_draw_indx_2(dev_priv, cmdbuf);
663 case RADEON_WAIT_FOR_IDLE: 711 case RADEON_WAIT_FOR_IDLE:
664 case RADEON_CP_NOP: 712 case RADEON_CP_NOP:
665 /* these packets are safe */ 713 /* these packets are safe */
@@ -757,7 +805,7 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
757{ 805{
758 uint32_t cache_z, cache_3d, cache_2d; 806 uint32_t cache_z, cache_3d, cache_2d;
759 RING_LOCALS; 807 RING_LOCALS;
760 808
761 cache_z = R300_ZC_FLUSH; 809 cache_z = R300_ZC_FLUSH;
762 cache_2d = R300_RB2D_DC_FLUSH; 810 cache_2d = R300_RB2D_DC_FLUSH;
763 cache_3d = R300_RB3D_DC_FLUSH; 811 cache_3d = R300_RB3D_DC_FLUSH;