[PATCH v2] drm/radeon: evergreen/cayman indirect draw support

Glenn Kennard glenn.kennard at gmail.com
Fri Dec 12 18:32:37 PST 2014


Add the necessary set of commands to support OpenGL
indirect draw calls on evergreen/cayman devices that
do not have VM.

Signed-off-by: Glenn Kennard <glenn.kennard at gmail.com>
---
Changes since patch V1:
* Removed multi draw indirect, not used by current userspace which instead
  decomposes multi into separate draw indirect calls
* Added validation to reject cs if indirect draw buffer is too small for address+offset
* Removed useless calls to evergreen_cs_track_check
* Reject attempt to call PACKET3_SET_BASE with other value than indirect draw buffer base for chips using VM.

I've left the index buffer logic unchanged, outside of scope for this feature,
additional checking of that would be part of support for GL_ARB/KHR_robust_buffer_access_behavior.

 drivers/gpu/drm/radeon/evergreen_cs.c | 76 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_drv.c   |  3 +-
 2 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 924b1b7..5152c1f 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -83,6 +83,7 @@ struct evergreen_cs_track {
 	u32			htile_offset;
 	u32			htile_surface;
 	struct radeon_bo	*htile_bo;
+	unsigned long		indirect_draw_buffer_size;
 };
 
 static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@@ -1896,6 +1897,14 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
 		}
 		break;
 	}
+	case PACKET3_INDEX_BUFFER_SIZE:
+	{
+		if (pkt->count != 0) {
+			DRM_ERROR("bad INDEX_BUFFER_SIZE\n");
+			return -EINVAL;
+		}
+		break;
+	}
 	case PACKET3_DRAW_INDEX:
 	{
 		uint64_t offset;
@@ -2006,6 +2015,67 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
 			return r;
 		}
 		break;
+	case PACKET3_SET_BASE:
+	{
+		/*
+		DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the Header will correspond to the shader type of the Load, see Type-3 Packet.
+		   2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies which base address is specified in the last two DWs.
+		     0001: DX11 Draw_Index_Indirect Patch Table Base: Base address for Draw_Index_Indirect data.
+		   3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned Address. Bits [2:0] - Reserved
+		   4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits of Address [47:32]
+		*/
+		if (pkt->count != 2) {
+			DRM_ERROR("bad SET_BASE\n");
+			return -EINVAL;
+		}
+
+		/* currently only supporting setting indirect draw buffer base address */
+		if (idx_value != 1) {
+			DRM_ERROR("bad SET_BASE\n");
+			return -EINVAL;
+		}
+
+		r = radeon_cs_packet_next_reloc(p, &reloc, 0);
+		if (r) {
+			DRM_ERROR("bad SET_BASE\n");
+			return -EINVAL;
+		}
+
+		track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj);
+
+		ib[idx+1] = reloc->gpu_offset;
+		ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff;
+
+		break;
+	}
+	case PACKET3_DRAW_INDIRECT:
+	case PACKET3_DRAW_INDEX_INDIRECT:
+	{
+		u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20;
+
+		/*
+		DW 1 HEADER
+		   2 DATA_OFFSET Bits [31:0] + byte aligned offset where the required data structure starts. Bits 1:0 are zero
+		   3 DRAW_INITIATOR Draw Initiator Register. Written to the VGT_DRAW_INITIATOR register for the assigned context
+		*/
+		if (pkt->count != 1) {
+			DRM_ERROR("bad DRAW_INDIRECT\n");
+			return -EINVAL;
+		}
+
+		if (idx_value + size > track->indirect_draw_buffer_size) {
+			dev_warn(p->dev, "DRAW_INDIRECT buffer too small %llu + %llu > %lu\n",
+				idx_value, size, track->indirect_draw_buffer_size);
+			return -EINVAL;
+		}
+
+		r = evergreen_cs_track_check(p);
+		if (r) {
+			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+			return r;
+		}
+		break;
+	}
 	case PACKET3_DISPATCH_DIRECT:
 		if (pkt->count != 3) {
 			DRM_ERROR("bad DISPATCH_DIRECT\n");
@@ -3243,7 +3313,13 @@ static int evergreen_vm_packet3_check(struct radeon_device *rdev,
 
 	switch (pkt->opcode) {
 	case PACKET3_NOP:
+		break;
 	case PACKET3_SET_BASE:
+		if (idx_value != 1) {
+			DRM_ERROR("bad SET_BASE");
+			return -EINVAL;
+		}
+		break;
 	case PACKET3_CLEAR_STATE:
 	case PACKET3_INDEX_BUFFER_SIZE:
 	case PACKET3_DISPATCH_DIRECT:
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 4f50fb0..5d684be 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -88,9 +88,10 @@
  *   2.39.0 - Add INFO query for number of active CUs
  *   2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting
  *            CS to GPU on >= r600
+ *   2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support
  */
 #define KMS_DRIVER_MAJOR	2
-#define KMS_DRIVER_MINOR	40
+#define KMS_DRIVER_MINOR	41
 #define KMS_DRIVER_PATCHLEVEL	0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
-- 
1.9.1



More information about the dri-devel mailing list