From 6212d2402df4ad0658cbb98ce889e35ef5f32fa3 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 18 Oct 2014 12:50:05 +0100 Subject: [PATCH] vc4: Translate 4-byte index buffers to 2 bytes. Fixes assertion failures in 14 piglit tests (half of which now pass). --- src/gallium/drivers/vc4/vc4_draw.c | 14 +++++--- src/gallium/drivers/vc4/vc4_resource.c | 46 ++++++++++++++++++++++++++ src/gallium/drivers/vc4/vc4_resource.h | 17 +++++++++- src/gallium/drivers/vc4/vc4_state.c | 25 +++++++++++--- 4 files changed, 92 insertions(+), 10 deletions(-) diff --git a/src/gallium/drivers/vc4/vc4_draw.c b/src/gallium/drivers/vc4/vc4_draw.c index f53caf79cfb..e70506b6245 100644 --- a/src/gallium/drivers/vc4/vc4_draw.c +++ b/src/gallium/drivers/vc4/vc4_draw.c @@ -209,19 +209,23 @@ vc4_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) */ if (info->indexed) { struct vc4_resource *rsc = vc4_resource(vc4->indexbuf.buffer); - - assert(vc4->indexbuf.index_size == 1 || - vc4->indexbuf.index_size == 2); + uint32_t offset = vc4->indexbuf.offset; + uint32_t index_size = vc4->indexbuf.index_size; + if (rsc->shadow_parent) { + vc4_update_shadow_index_buffer(pctx, &vc4->indexbuf); + offset = 0; + index_size = 2; + } cl_start_reloc(&vc4->bcl, 1); cl_u8(&vc4->bcl, VC4_PACKET_GL_INDEXED_PRIMITIVE); cl_u8(&vc4->bcl, info->mode | - (vc4->indexbuf.index_size == 2 ? + (index_size == 2 ? VC4_INDEX_BUFFER_U16: VC4_INDEX_BUFFER_U8)); cl_u32(&vc4->bcl, info->count); - cl_reloc(vc4, &vc4->bcl, rsc->bo, vc4->indexbuf.offset); + cl_reloc(vc4, &vc4->bcl, rsc->bo, offset); cl_u32(&vc4->bcl, max_index); } else { cl_u8(&vc4->bcl, VC4_PACKET_GL_ARRAY_PRIMITIVE); diff --git a/src/gallium/drivers/vc4/vc4_resource.c b/src/gallium/drivers/vc4/vc4_resource.c index 803d3575f09..c198ab94f43 100644 --- a/src/gallium/drivers/vc4/vc4_resource.c +++ b/src/gallium/drivers/vc4/vc4_resource.c @@ -512,6 +512,52 @@ vc4_update_shadow_baselevel_texture(struct pipe_context *pctx, shadow->writes = orig->writes; } +/** + * Converts a 4-byte index buffer to 2 bytes. + * + * Since GLES2 only has support for 1 and 2-byte indices, the hardware doesn't + * include 4-byte index support, and we have to shrink it down. + * + * There's no fallback support for when indices end up being larger than 2^16, + * though it will at least assertion fail. Also, if the original index data + * was in user memory, it would be nice to not have uploaded it to a VBO + * before translating. + */ +void +vc4_update_shadow_index_buffer(struct pipe_context *pctx, + const struct pipe_index_buffer *ib) +{ + struct vc4_resource *shadow = vc4_resource(ib->buffer); + struct vc4_resource *orig = vc4_resource(shadow->shadow_parent); + uint32_t count = shadow->base.b.width0 / 2; + + if (shadow->writes == orig->writes) + return; + + struct pipe_transfer *src_transfer; + uint32_t *src = pipe_buffer_map_range(pctx, &orig->base.b, + ib->offset, + count * 4, + PIPE_TRANSFER_READ, &src_transfer); + + struct pipe_transfer *dst_transfer; + uint16_t *dst = pipe_buffer_map_range(pctx, &shadow->base.b, + 0, + count * 2, + PIPE_TRANSFER_WRITE, &dst_transfer); + + for (int i = 0; i < count; i++) { + uint32_t src_index = src[i]; + assert(src_index <= 0xffff); + dst[i] = src_index; + } + + pctx->transfer_unmap(pctx, dst_transfer); + pctx->transfer_unmap(pctx, src_transfer); + + shadow->writes = orig->writes; +} + void vc4_resource_screen_init(struct pipe_screen *pscreen) { diff --git a/src/gallium/drivers/vc4/vc4_resource.h b/src/gallium/drivers/vc4/vc4_resource.h index 7cc16a4540b..90b58e137df 100644 --- a/src/gallium/drivers/vc4/vc4_resource.h +++ b/src/gallium/drivers/vc4/vc4_resource.h @@ -67,9 +67,22 @@ struct vc4_resource { * * This is used to track when we need to update this shadow resource * from its parent in the case of GL_TEXTURE_BASE_LEVEL (which we - * can't support in hardware). + * can't support in hardware) or GL_UNSIGNED_INTEGER index buffers. */ uint64_t writes; + + /** + * Resource containing the non-GL_TEXTURE_BASE_LEVEL-rebased texture + * contents, or the 4-byte index buffer. + * + * If the parent is set for an texture, then this resource is actually + * the texture contents just starting from the sampler_view's + * first_level. + * + * If the parent is set for an index index buffer, then this resource + * is actually a shadow containing a 2-byte index buffer starting from + * the ib's offset. + */ struct pipe_resource *shadow_parent; }; @@ -97,5 +110,7 @@ struct pipe_resource *vc4_resource_create(struct pipe_screen *pscreen, const struct pipe_resource *tmpl); void vc4_update_shadow_baselevel_texture(struct pipe_context *pctx, struct pipe_sampler_view *view); +void vc4_update_shadow_index_buffer(struct pipe_context *pctx, + const struct pipe_index_buffer *ib); #endif /* VC4_RESOURCE_H */ diff --git a/src/gallium/drivers/vc4/vc4_state.c b/src/gallium/drivers/vc4/vc4_state.c index d3219b39d61..31f24242860 100644 --- a/src/gallium/drivers/vc4/vc4_state.c +++ b/src/gallium/drivers/vc4/vc4_state.c @@ -281,10 +281,27 @@ vc4_set_index_buffer(struct pipe_context *pctx, struct vc4_context *vc4 = vc4_context(pctx); if (ib) { - pipe_resource_reference(&vc4->indexbuf.buffer, ib->buffer); - vc4->indexbuf.index_size = ib->index_size; - vc4->indexbuf.offset = ib->offset; - vc4->indexbuf.user_buffer = ib->user_buffer; + assert(!ib->user_buffer); + + if (ib->index_size == 4) { + struct pipe_resource tmpl = *ib->buffer; + assert(tmpl.format == PIPE_FORMAT_R8_UNORM); + assert(tmpl.height0 == 1); + tmpl.width0 = (tmpl.width0 - ib->offset) / 2; + struct pipe_resource *pshadow = + vc4_resource_create(&vc4->screen->base, &tmpl); + struct vc4_resource *shadow = vc4_resource(pshadow); + pipe_resource_reference(&shadow->shadow_parent, ib->buffer); + + pipe_resource_reference(&vc4->indexbuf.buffer, NULL); + vc4->indexbuf.buffer = pshadow; + vc4->indexbuf.index_size = 2; + vc4->indexbuf.offset = 0; + } else { + pipe_resource_reference(&vc4->indexbuf.buffer, ib->buffer); + vc4->indexbuf.index_size = ib->index_size; + vc4->indexbuf.offset = ib->offset; + } } else { pipe_resource_reference(&vc4->indexbuf.buffer, NULL); } -- 2.30.2