Requires Evergreen/Cayman and updated radeon kernel module Signed-off-by: Glenn Kennard <glenn.kenn...@gmail.com> --- Changes since V1: * Fixed 8 bit index case, only triggerable using GLES 3.1 which isn't supported yet * Don't read info struct values that have no meaning for indirect case * Don't update start_instance/instance_count for indirect cases * Use bool expression directly in get_param
Benjamin, the #defines are essentially used, but due to a header conflict its not possible to include them in this file. Would have broken the indirect cases into evergreen_state.c, but this is a performance-sensitive section of code and inlining is critical, so did the next best thing and typed out the define names as comments. Thanks Marek/Benjamin for V1 review docs/GL3.txt | 4 +- docs/relnotes/10.5.0.html | 1 + src/gallium/drivers/r600/evergreend.h | 6 +- src/gallium/drivers/r600/r600_pipe.c | 4 +- src/gallium/drivers/r600/r600_state_common.c | 116 ++++++++++++++++++++++----- 5 files changed, 105 insertions(+), 26 deletions(-) diff --git a/docs/GL3.txt b/docs/GL3.txt index 648f5ac..435054a 100644 --- a/docs/GL3.txt +++ b/docs/GL3.txt @@ -95,7 +95,7 @@ GL 3.3, GLSL 3.30 --- all DONE: i965, nv50, nvc0, r600, radeonsi, llvmpipe, soft GL 4.0, GLSL 4.00: GL_ARB_draw_buffers_blend DONE (i965, nv50, nvc0, r600, radeonsi, llvmpipe, softpipe) - GL_ARB_draw_indirect DONE (i965, nvc0, radeonsi, llvmpipe, softpipe) + GL_ARB_draw_indirect DONE (i965, nvc0, r600, radeonsi, llvmpipe, softpipe) GL_ARB_gpu_shader5 DONE (i965, nvc0) - 'precise' qualifier DONE - Dynamically uniform sampler array indices DONE (r600) @@ -159,7 +159,7 @@ GL 4.3, GLSL 4.30: GL_ARB_framebuffer_no_attachments not started GL_ARB_internalformat_query2 not started GL_ARB_invalidate_subdata DONE (all drivers) - GL_ARB_multi_draw_indirect DONE (i965, nvc0, radeonsi, llvmpipe, softpipe) + GL_ARB_multi_draw_indirect DONE (i965, nvc0, r600, radeonsi, llvmpipe, softpipe) GL_ARB_program_interface_query not started GL_ARB_robust_buffer_access_behavior not started GL_ARB_shader_image_size not started diff --git a/docs/relnotes/10.5.0.html b/docs/relnotes/10.5.0.html index 2987d53..72bb791 100644 --- a/docs/relnotes/10.5.0.html +++ b/docs/relnotes/10.5.0.html @@ -49,6 +49,7 @@ Note: some of the new features are only available with certain drivers. <li>GL_EXT_packed_float on freedreno</li> <li>GL_EXT_texture_shared_exponent on freedreno</li> <li>GL_EXT_texture_snorm on freedreno</li> +<li>GL_ARB_draw_indirect, GL_ARB_multi_draw_indirect on r600</li> </ul> diff --git a/src/gallium/drivers/r600/evergreend.h b/src/gallium/drivers/r600/evergreend.h index 4989996..0725f0d 100644 --- a/src/gallium/drivers/r600/evergreend.h +++ b/src/gallium/drivers/r600/evergreend.h @@ -64,6 +64,8 @@ #define R600_TEXEL_PITCH_ALIGNMENT_MASK 0x7 #define PKT3_NOP 0x10 +#define PKT3_SET_BASE 0x11 +#define PKT3_INDEX_BUFFER_SIZE 0x13 #define PKT3_DEALLOC_STATE 0x14 #define PKT3_DISPATCH_DIRECT 0x15 #define PKT3_DISPATCH_INDIRECT 0x16 @@ -72,7 +74,9 @@ #define PKT3_REG_RMW 0x21 #define PKT3_COND_EXEC 0x22 #define PKT3_PRED_EXEC 0x23 -#define PKT3_START_3D_CMDBUF 0x24 +#define PKT3_DRAW_INDIRECT 0x24 +#define PKT3_DRAW_INDEX_INDIRECT 0x25 +#define PKT3_INDEX_BASE 0x26 #define PKT3_DRAW_INDEX_2 0x27 #define PKT3_CONTEXT_CONTROL 0x28 #define PKT3_DRAW_INDEX_IMMD_BE 0x29 diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 0b571e4..0d8bac2 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -313,6 +313,9 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param) return family >= CHIP_CEDAR ? 1 : 0; case PIPE_CAP_MAX_TEXTURE_GATHER_COMPONENTS: return family >= CHIP_CEDAR ? 4 : 0; + case PIPE_CAP_DRAW_INDIRECT: + /* kernel command checker support is also required */ + return family >= CHIP_CEDAR && rscreen->b.info.drm_minor >= 41; /* Unsupported features. */ case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: @@ -322,7 +325,6 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param) case PIPE_CAP_VERTEX_COLOR_CLAMPED: case PIPE_CAP_USER_VERTEX_BUFFERS: case PIPE_CAP_TEXTURE_GATHER_OFFSETS: - case PIPE_CAP_DRAW_INDIRECT: case PIPE_CAP_CONDITIONAL_RENDER_INVERTED: case PIPE_CAP_SAMPLER_VIEW_TARGET: return 0; diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index 09d8952..57f87d1 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -1347,7 +1347,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info unsigned i; struct radeon_winsys_cs *cs = rctx->b.rings.gfx.cs; - if (!info.count && (info.indexed || !info.count_from_stream_output)) { + if (!info.indirect && !info.count && (info.indexed || !info.count_from_stream_output)) { return; } @@ -1373,19 +1373,44 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info pipe_resource_reference(&ib.buffer, rctx->index_buffer.buffer); ib.user_buffer = rctx->index_buffer.user_buffer; ib.index_size = rctx->index_buffer.index_size; - ib.offset = rctx->index_buffer.offset + info.start * ib.index_size; + ib.offset = rctx->index_buffer.offset; + if (!info.indirect) { + ib.offset += info.start * ib.index_size; + } /* Translate 8-bit indices to 16-bit. */ - if (ib.index_size == 1) { + if (unlikely(ib.index_size == 1)) { struct pipe_resource *out_buffer = NULL; unsigned out_offset; void *ptr; + unsigned start, count; + + if (likely(!info.indirect)) { + start = 0; + count = info.count; + } + else { + /* Have to get start/count from indirect buffer, slow path ahead... */ + struct r600_resource *indirect_resource = (struct r600_resource *)info.indirect; + unsigned *data = r600_buffer_map_sync_with_rings(&rctx->b, indirect_resource, + PIPE_TRANSFER_READ); + if (data) { + data += info.indirect_offset / sizeof(unsigned); + start = data[2] * ib.index_size; + count = data[0]; + rctx->b.ws->buffer_unmap(indirect_resource->cs_buf); + } + else { + start = 0; + count = 0; + } + } - u_upload_alloc(rctx->b.uploader, 0, info.count * 2, + u_upload_alloc(rctx->b.uploader, start, count * 2, &out_offset, &out_buffer, &ptr); util_shorten_ubyte_elts_to_userptr( - &rctx->b.b, &ib, 0, ib.offset, info.count, ptr); + &rctx->b.b, &ib, 0, ib.offset + start, count, ptr); pipe_resource_reference(&ib.buffer, NULL); ib.user_buffer = NULL; @@ -1397,9 +1422,11 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info /* Upload the index buffer. * The upload is skipped for small index counts on little-endian machines * and the indices are emitted via PKT3_DRAW_INDEX_IMMD. + * Indirect draws never use immediate indices. * Note: Instanced rendering in combination with immediate indices hangs. */ - if (ib.user_buffer && (R600_BIG_ENDIAN || info.instance_count > 1 || - info.count*ib.index_size > 20)) { + if (ib.user_buffer && (R600_BIG_ENDIAN || info.indirect || + info.instance_count > 1 || + info.count*ib.index_size > 20)) { u_upload_data(rctx->b.uploader, 0, info.count * ib.index_size, ib.user_buffer, &ib.offset, &ib.buffer); ib.user_buffer = NULL; @@ -1479,7 +1506,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info } /* Update start instance. */ - if (rctx->last_start_instance != info.start_instance) { + if (!info.indirect && rctx->last_start_instance != info.start_instance) { r600_write_ctl_const(cs, R_03CFF4_SQ_VTX_START_INST_LOC, info.start_instance); rctx->last_start_instance = info.start_instance; } @@ -1504,8 +1531,25 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info } /* Draw packets. */ - cs->buf[cs->cdw++] = PKT3(PKT3_NUM_INSTANCES, 0, rctx->b.predicate_drawing); - cs->buf[cs->cdw++] = info.instance_count; + if (!info.indirect) { + cs->buf[cs->cdw++] = PKT3(PKT3_NUM_INSTANCES, 0, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = info.instance_count; + } + + if (unlikely(info.indirect)) { + uint64_t va = r600_resource(info.indirect)->gpu_address; + assert(rctx->b.chip_class >= EVERGREEN); + cs->buf[cs->cdw++] = PKT3(0x11 /* PKT3_SET_BASE */, 2, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = 1; // 1 means DX11 Draw_Index_Indirect Patch Table Base + cs->buf[cs->cdw++] = va; + cs->buf[cs->cdw++] = (va >> 32UL) & 0xFF; + + cs->buf[cs->cdw++] = PKT3(PKT3_NOP, 0, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = r600_context_bo_reloc(&rctx->b, &rctx->b.rings.gfx, + (struct r600_resource*)info.indirect, + RADEON_USAGE_READ, RADEON_PRIO_MIN); + } + if (info.indexed) { cs->buf[cs->cdw++] = PKT3(PKT3_INDEX_TYPE, 0, rctx->b.predicate_drawing); cs->buf[cs->cdw++] = ib.index_size == 4 ? @@ -1522,18 +1566,40 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info cs->cdw += size_dw; } else { uint64_t va = r600_resource(ib.buffer)->gpu_address + ib.offset; - cs->buf[cs->cdw++] = PKT3(PKT3_DRAW_INDEX, 3, rctx->b.predicate_drawing); - cs->buf[cs->cdw++] = va; - cs->buf[cs->cdw++] = (va >> 32UL) & 0xFF; - cs->buf[cs->cdw++] = info.count; - cs->buf[cs->cdw++] = V_0287F0_DI_SRC_SEL_DMA; - cs->buf[cs->cdw++] = PKT3(PKT3_NOP, 0, rctx->b.predicate_drawing); - cs->buf[cs->cdw++] = r600_context_bo_reloc(&rctx->b, &rctx->b.rings.gfx, - (struct r600_resource*)ib.buffer, - RADEON_USAGE_READ, RADEON_PRIO_MIN); + + if (likely(!info.indirect)) { + cs->buf[cs->cdw++] = PKT3(PKT3_DRAW_INDEX, 3, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = va; + cs->buf[cs->cdw++] = (va >> 32UL) & 0xFF; + cs->buf[cs->cdw++] = info.count; + cs->buf[cs->cdw++] = V_0287F0_DI_SRC_SEL_DMA; + cs->buf[cs->cdw++] = PKT3(PKT3_NOP, 0, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = r600_context_bo_reloc(&rctx->b, &rctx->b.rings.gfx, + (struct r600_resource*)ib.buffer, + RADEON_USAGE_READ, RADEON_PRIO_MIN); + } + else { + uint32_t max_size = (ib.buffer->width0 - ib.offset) / ib.index_size; + + cs->buf[cs->cdw++] = PKT3(0x26 /* PKT3_INDEX_BASE */, 1, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = va; + cs->buf[cs->cdw++] = (va >> 32UL) & 0xFF; + + cs->buf[cs->cdw++] = PKT3(PKT3_NOP, 0, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = r600_context_bo_reloc(&rctx->b, &rctx->b.rings.gfx, + (struct r600_resource*)ib.buffer, + RADEON_USAGE_READ, RADEON_PRIO_MIN); + + cs->buf[cs->cdw++] = PKT3(0x13 /* PKT3_INDEX_BUFFER_SIZE */, 0, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = max_size; + + cs->buf[cs->cdw++] = PKT3(0x25 /* PKT3_DRAW_INDEX_INDIRECT */, 1, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = info.indirect_offset; + cs->buf[cs->cdw++] = V_0287F0_DI_SRC_SEL_DMA; + } } } else { - if (info.count_from_stream_output) { + if (unlikely(info.count_from_stream_output)) { struct r600_so_target *t = (struct r600_so_target*)info.count_from_stream_output; uint64_t va = t->buf_filled_size->gpu_address + t->buf_filled_size_offset; @@ -1552,8 +1618,14 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info RADEON_PRIO_MIN); } - cs->buf[cs->cdw++] = PKT3(PKT3_DRAW_INDEX_AUTO, 1, rctx->b.predicate_drawing); - cs->buf[cs->cdw++] = info.count; + if (likely(!info.indirect)) { + cs->buf[cs->cdw++] = PKT3(PKT3_DRAW_INDEX_AUTO, 1, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = info.count; + } + else { + cs->buf[cs->cdw++] = PKT3(0x24 /* PKT3_DRAW_INDIRECT */, 1, rctx->b.predicate_drawing); + cs->buf[cs->cdw++] = info.indirect_offset; + } cs->buf[cs->cdw++] = V_0287F0_DI_SRC_SEL_AUTO_INDEX | (info.count_from_stream_output ? S_0287F0_USE_OPAQUE(1) : 0); } -- 1.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev