vc4: Translate 4-byte index buffers to 2 bytes.
authorEric Anholt <eric@anholt.net>
Sat, 18 Oct 2014 11:50:05 +0000 (12:50 +0100)
committerEric Anholt <eric@anholt.net>
Sun, 19 Oct 2014 07:44:56 +0000 (08:44 +0100)
Fixes assertion failures in 14 piglit tests (half of which now pass).

src/gallium/drivers/vc4/vc4_draw.c
src/gallium/drivers/vc4/vc4_resource.c
src/gallium/drivers/vc4/vc4_resource.h
src/gallium/drivers/vc4/vc4_state.c

index f53caf79cfbde6df2afcdf53f5bb93ebc6c76768..e70506b6245adff62d6cc036292b914934842dea 100644 (file)
@@ -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);
index 803d3575f099eb8a8de3e3f89472852c5a0eed1a..c198ab94f43d605b0c59f63cb65309a861a4f4cb 100644 (file)
@@ -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)
 {
index 7cc16a4540bde5ba90369cd3a2b262201a547b49..90b58e137dffb3a727c7d8d4ef1225b42bd31413 100644 (file)
@@ -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 */
index d3219b39d616fccbf86ab7b536fac945389da546..31f24242860b75b73d7aeac9c83776f9620327df 100644 (file)
@@ -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);
         }