* IN THE SOFTWARE.
*/
-#include <stdio.h>
-
#include "util/u_memory.h"
#include "util/u_format.h"
#include "util/u_inlines.h"
#include "vc4_screen.h"
#include "vc4_context.h"
#include "vc4_resource.h"
+#include "vc4_tiling.h"
+
+static bool miptree_debug = false;
+
+static void
+vc4_resource_bo_alloc(struct vc4_resource *rsc)
+{
+ struct pipe_resource *prsc = &rsc->base.b;
+ struct pipe_screen *pscreen = prsc->screen;
+
+ if (miptree_debug) {
+ fprintf(stderr, "alloc %p: size %d + offset %d -> %d\n",
+ rsc,
+ rsc->slices[0].size,
+ rsc->slices[0].offset,
+ rsc->slices[0].offset +
+ rsc->slices[0].size +
+ rsc->cube_map_stride * (prsc->array_size - 1));
+ }
+
+ vc4_bo_unreference(&rsc->bo);
+ rsc->bo = vc4_bo_alloc(vc4_screen(pscreen),
+ rsc->slices[0].offset +
+ rsc->slices[0].size +
+ rsc->cube_map_stride * (prsc->array_size - 1),
+ "resource");
+}
static void
vc4_resource_transfer_unmap(struct pipe_context *pctx,
struct pipe_transfer *ptrans)
{
struct vc4_context *vc4 = vc4_context(pctx);
+ struct vc4_transfer *trans = vc4_transfer(ptrans);
+ struct pipe_resource *prsc = ptrans->resource;
+ struct vc4_resource *rsc = vc4_resource(prsc);
+ struct vc4_resource_slice *slice = &rsc->slices[ptrans->level];
+
+ if (trans->map) {
+ if (ptrans->usage & PIPE_TRANSFER_WRITE) {
+ vc4_store_tiled_image(rsc->bo->map + slice->offset +
+ ptrans->box.z * rsc->cube_map_stride,
+ slice->stride,
+ trans->map, ptrans->stride,
+ slice->tiling, rsc->cpp,
+ &ptrans->box);
+ }
+ free(trans->map);
+ }
pipe_resource_reference(&ptrans->resource, NULL);
util_slab_free(&vc4->transfer_pool, ptrans);
{
struct vc4_context *vc4 = vc4_context(pctx);
struct vc4_resource *rsc = vc4_resource(prsc);
+ struct vc4_resource_slice *slice = &rsc->slices[level];
+ struct vc4_transfer *trans;
struct pipe_transfer *ptrans;
enum pipe_format format = prsc->format;
char *buf;
- vc4_flush_for_bo(pctx, rsc->bo);
+ if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
+ vc4_resource_bo_alloc(rsc);
+ } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
+ if (vc4_cl_references_bo(pctx, rsc->bo)) {
+ if ((usage & PIPE_TRANSFER_DISCARD_RANGE) &&
+ prsc->last_level == 0 &&
+ prsc->width0 == box->width &&
+ prsc->height0 == box->height &&
+ prsc->depth0 == box->depth) {
+ vc4_resource_bo_alloc(rsc);
+ } else {
+ vc4_flush(pctx);
+ }
+ }
+ }
+
+ if (usage & PIPE_TRANSFER_WRITE)
+ rsc->writes++;
- ptrans = util_slab_alloc(&vc4->transfer_pool);
- if (!ptrans)
+ trans = util_slab_alloc(&vc4->transfer_pool);
+ if (!trans)
return NULL;
+ /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */
+
/* util_slab_alloc() doesn't zero: */
- memset(ptrans, 0, sizeof(*ptrans));
+ memset(trans, 0, sizeof(*trans));
+ ptrans = &trans->base;
pipe_resource_reference(&ptrans->resource, prsc);
ptrans->level = level;
ptrans->usage = usage;
ptrans->box = *box;
- ptrans->stride = rsc->slices[level].stride;
- ptrans->layer_stride = ptrans->stride;
/* Note that the current kernel implementation is synchronous, so no
* need to do syncing stuff here yet.
*/
- buf = vc4_bo_map(rsc->bo);
+ if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
+ buf = vc4_bo_map_unsynchronized(rsc->bo);
+ else
+ buf = vc4_bo_map(rsc->bo);
if (!buf) {
fprintf(stderr, "Failed to map bo\n");
goto fail;
*pptrans = ptrans;
- return buf + rsc->slices[level].offset +
- box->y / util_format_get_blockheight(format) * ptrans->stride +
- box->x / util_format_get_blockwidth(format) * rsc->cpp +
- box->z * rsc->slices[level].size0;
+ if (rsc->tiled) {
+ uint32_t utile_w = vc4_utile_width(rsc->cpp);
+ uint32_t utile_h = vc4_utile_height(rsc->cpp);
+
+ /* No direct mappings of tiled, since we need to manually
+ * tile/untile.
+ */
+ if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
+ return NULL;
+
+ /* We need to align the box to utile boundaries, since that's
+ * what load/store operate on.
+ */
+ uint32_t box_start_x = ptrans->box.x & (utile_w - 1);
+ uint32_t box_start_y = ptrans->box.y & (utile_h - 1);
+ ptrans->box.width += box_start_x;
+ ptrans->box.x -= box_start_x;
+ ptrans->box.height += box_start_y;
+ ptrans->box.y -= box_start_y;
+ ptrans->box.width = align(ptrans->box.width, utile_w);
+ ptrans->box.height = align(ptrans->box.height, utile_h);
+
+ ptrans->stride = ptrans->box.width * rsc->cpp;
+ ptrans->layer_stride = ptrans->stride;
+
+ trans->map = malloc(ptrans->stride * ptrans->box.height);
+ if (usage & PIPE_TRANSFER_READ) {
+ vc4_load_tiled_image(trans->map, ptrans->stride,
+ buf + slice->offset +
+ box->z * rsc->cube_map_stride,
+ slice->stride,
+ slice->tiling, rsc->cpp,
+ &ptrans->box);
+ }
+ return (trans->map +
+ box_start_x * rsc->cpp +
+ box_start_y * ptrans->stride);
+ } else {
+ ptrans->stride = slice->stride;
+ ptrans->layer_stride = ptrans->stride;
+
+ return buf + slice->offset +
+ box->y / util_format_get_blockheight(format) * ptrans->stride +
+ box->x / util_format_get_blockwidth(format) * rsc->cpp +
+ box->z * rsc->cube_map_stride;
+ }
+
fail:
vc4_resource_transfer_unmap(pctx, ptrans);
struct pipe_resource *prsc)
{
struct vc4_resource *rsc = vc4_resource(prsc);
+ pipe_resource_reference(&rsc->shadow_parent, NULL);
vc4_bo_unreference(&rsc->bo);
free(rsc);
}
struct pipe_resource *prsc = &rsc->base.b;
uint32_t width = prsc->width0;
uint32_t height = prsc->height0;
- uint32_t depth = prsc->depth0;
+ uint32_t pot_width = util_next_power_of_two(width);
+ uint32_t pot_height = util_next_power_of_two(height);
uint32_t offset = 0;
+ uint32_t utile_w = vc4_utile_width(rsc->cpp);
+ uint32_t utile_h = vc4_utile_height(rsc->cpp);
for (int i = prsc->last_level; i >= 0; i--) {
struct vc4_resource_slice *slice = &rsc->slices[i];
- uint32_t level_width = u_minify(width, i);
- uint32_t level_height = u_minify(height, i);
- slice->offset = offset;
- slice->stride = align(level_width * rsc->cpp, 16);
- slice->size0 = level_height * slice->stride;
+ uint32_t level_width, level_height;
+ if (i == 0) {
+ level_width = width;
+ level_height = height;
+ } else {
+ level_width = u_minify(pot_width, i);
+ level_height = u_minify(pot_height, i);
+ }
+
+ if (!rsc->tiled) {
+ slice->tiling = VC4_TILING_FORMAT_LINEAR;
+ level_width = align(level_width, 16);
+ } else {
+ if (vc4_size_is_lt(level_width, level_height,
+ rsc->cpp)) {
+ slice->tiling = VC4_TILING_FORMAT_LT;
+ level_width = align(level_width, utile_w);
+ level_height = align(level_height, utile_h);
+ } else {
+ slice->tiling = VC4_TILING_FORMAT_T;
+ level_width = align(level_width,
+ 4 * 2 * utile_w);
+ level_height = align(level_height,
+ 4 * 2 * utile_h);
+ }
+ }
- /* Note, since we have cubes but no 3D, depth is invariant
- * with miplevel.
- */
- offset += slice->size0 * depth;
+ slice->offset = offset;
+ slice->stride = level_width * rsc->cpp;
+ slice->size = level_height * slice->stride;
+
+ offset += slice->size;
+
+ if (miptree_debug) {
+ static const char tiling_chars[] = {
+ [VC4_TILING_FORMAT_LINEAR] = 'R',
+ [VC4_TILING_FORMAT_LT] = 'L',
+ [VC4_TILING_FORMAT_T] = 'T'
+ };
+ fprintf(stderr,
+ "rsc setup %p (format %d), %dx%d: "
+ "level %d (%c) -> %dx%d, stride %d@0x%08x\n",
+ rsc, rsc->vc4_format,
+ prsc->width0, prsc->height0,
+ i, tiling_chars[slice->tiling],
+ level_width, level_height,
+ slice->stride, slice->offset);
+ }
}
/* The texture base pointer that has to point to level 0 doesn't have
for (int i = 0; i <= prsc->last_level; i++)
rsc->slices[i].offset += page_align_offset;
}
+
+ /* Cube map faces appear as whole miptrees at a page-aligned offset
+ * from the first face's miptree.
+ */
+ if (prsc->target == PIPE_TEXTURE_CUBE) {
+ rsc->cube_map_stride = align(rsc->slices[0].offset +
+ rsc->slices[0].size, 4096);
+ }
}
static struct vc4_resource *
return rsc;
}
-static struct pipe_resource *
+static enum vc4_texture_data_type
+get_resource_texture_format(struct pipe_resource *prsc)
+{
+ struct vc4_resource *rsc = vc4_resource(prsc);
+ uint8_t format = vc4_get_tex_format(prsc->format);
+
+ if (!rsc->tiled) {
+ assert(format == VC4_TEXTURE_TYPE_RGBA8888);
+ return VC4_TEXTURE_TYPE_RGBA32R;
+ }
+
+ return format;
+}
+
+struct pipe_resource *
vc4_resource_create(struct pipe_screen *pscreen,
const struct pipe_resource *tmpl)
{
struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
struct pipe_resource *prsc = &rsc->base.b;
- vc4_setup_slices(rsc);
+ /* We have to make shared be untiled, since we don't have any way to
+ * communicate metadata about tiling currently.
+ */
+ if (tmpl->target == PIPE_BUFFER ||
+ (tmpl->bind & (PIPE_BIND_SCANOUT |
+ PIPE_BIND_LINEAR |
+ PIPE_BIND_SHARED |
+ PIPE_BIND_CURSOR))) {
+ rsc->tiled = false;
+ } else {
+ rsc->tiled = true;
+ }
- rsc->tiling = VC4_TILING_FORMAT_LINEAR;
- rsc->bo = vc4_bo_alloc(vc4_screen(pscreen),
- rsc->slices[0].offset +
- rsc->slices[0].size0 * prsc->depth0,
- "resource");
+ if (tmpl->target != PIPE_BUFFER)
+ rsc->vc4_format = get_resource_texture_format(prsc);
+
+ vc4_setup_slices(rsc);
+ vc4_resource_bo_alloc(rsc);
if (!rsc->bo)
goto fail;
if (!rsc)
return NULL;
- rsc->tiling = VC4_TILING_FORMAT_LINEAR;
- rsc->bo = vc4_screen_bo_from_handle(pscreen, handle, &slice->stride);
+ rsc->tiled = false;
+ rsc->bo = vc4_screen_bo_from_handle(pscreen, handle);
if (!rsc->bo)
goto fail;
-#ifdef USE_VC4_SIMULATOR
- slice->stride = align(prsc->width0 * rsc->cpp, 16);
-#endif
+ if (!using_vc4_simulator)
+ slice->stride = handle->stride;
+ else
+ slice->stride = align(prsc->width0 * rsc->cpp, 16);
+
+ slice->tiling = VC4_TILING_FORMAT_LINEAR;
+
+ rsc->vc4_format = get_resource_texture_format(prsc);
+
+ if (miptree_debug) {
+ fprintf(stderr,
+ "rsc import %p (format %d), %dx%d: "
+ "level 0 (R) -> stride %d@0x%08x\n",
+ rsc, rsc->vc4_format,
+ prsc->width0, prsc->height0,
+ slice->stride, slice->offset);
+ }
return prsc;
psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
surface->offset = rsc->slices[level].offset;
+ surface->tiling = rsc->slices[level].tiling;
return &surface->base;
}
static void
vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
{
- struct vc4_context *vc4 = vc4_context(pctx);
-
- /* XXX: Skip this if we don't have any queued drawing to it. */
- vc4->base.flush(pctx, NULL, 0);
+ /* All calls to flush_resource are followed by a flush of the context,
+ * so there's nothing to do.
+ */
}
+
static bool
render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
{
util_blitter_save_vertex_buffer_slot(vc4->blitter, vc4->vertexbuf.vb);
util_blitter_save_vertex_elements(vc4->blitter, vc4->vtx);
- util_blitter_save_vertex_shader(vc4->blitter, vc4->prog.vs);
+ util_blitter_save_vertex_shader(vc4->blitter, vc4->prog.bind_vs);
util_blitter_save_rasterizer(vc4->blitter, vc4->rasterizer);
util_blitter_save_viewport(vc4->blitter, &vc4->viewport);
util_blitter_save_scissor(vc4->blitter, &vc4->scissor);
- util_blitter_save_fragment_shader(vc4->blitter, vc4->prog.fs);
+ util_blitter_save_fragment_shader(vc4->blitter, vc4->prog.bind_fs);
util_blitter_save_blend(vc4->blitter, vc4->blend);
util_blitter_save_depth_stencil_alpha(vc4->blitter, vc4->zsa);
util_blitter_save_stencil_ref(vc4->blitter, &vc4->stencil_ref);
render_blit(pctx, &info);
}
+void
+vc4_update_shadow_baselevel_texture(struct pipe_context *pctx,
+ struct pipe_sampler_view *view)
+{
+ struct vc4_resource *shadow = vc4_resource(view->texture);
+ struct vc4_resource *orig = vc4_resource(shadow->shadow_parent);
+ assert(orig);
+
+ if (shadow->writes == orig->writes)
+ return;
+
+ for (int i = 0; i <= shadow->base.b.last_level; i++) {
+ struct pipe_box box = {
+ .x = 0,
+ .y = 0,
+ .z = 0,
+ .width = u_minify(shadow->base.b.width0, i),
+ .height = u_minify(shadow->base.b.height0, i),
+ .depth = 1,
+ };
+
+ util_resource_copy_region(pctx,
+ &shadow->base.b, i, 0, 0, 0,
+ &orig->base.b,
+ view->u.tex.first_level + i,
+ &box);
+ }
+
+ 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)
{