summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChia-I Wu <olvaffe@gmail.com>2013-05-09 14:07:58 +0800
committerChia-I Wu <olvaffe@gmail.com>2013-05-09 16:05:47 +0800
commitbaa44db06586f8f844046a6397ea609f55cd3b97 (patch)
tree26ac762d8045788c6e815d088e6e2378cedab4ab
parent7cca1aac9dba97cc7a97d3fd7690bc4af4bda0a6 (diff)
ilo: allow for different mapping methods
We want to or need to use a different mapping method when when the resource is busy, the bo format differs from the requested format, and etc.
-rw-r--r--src/gallium/drivers/ilo/ilo_resource.c302
1 files changed, 187 insertions, 115 deletions
diff --git a/src/gallium/drivers/ilo/ilo_resource.c b/src/gallium/drivers/ilo/ilo_resource.c
index d2b3dd14656..984a47a22ad 100644
--- a/src/gallium/drivers/ilo/ilo_resource.c
+++ b/src/gallium/drivers/ilo/ilo_resource.c
@@ -35,6 +35,23 @@
/* use PIPE_BIND_CUSTOM to indicate MCS */
#define ILO_BIND_MCS PIPE_BIND_CUSTOM
+enum ilo_transfer_map_method {
+ ILO_TRANSFER_MAP_DIRECT,
+};
+
+struct ilo_transfer {
+ struct pipe_transfer base;
+
+ enum ilo_transfer_map_method method;
+ void *ptr;
+};
+
+static inline struct ilo_transfer *
+ilo_transfer(struct pipe_transfer *transfer)
+{
+ return (struct ilo_transfer *) transfer;
+}
+
static struct intel_bo *
alloc_buf_bo(const struct ilo_resource *res)
{
@@ -245,96 +262,166 @@ ilo_transfer_inline_write(struct pipe_context *pipe,
}
static void
-ilo_transfer_unmap(struct pipe_context *pipe,
- struct pipe_transfer *transfer)
+transfer_unmap_direct(struct ilo_context *ilo,
+ struct ilo_resource *res,
+ struct ilo_transfer *xfer)
{
- struct ilo_resource *res = ilo_resource(transfer->resource);
-
res->bo->unmap(res->bo);
-
- pipe_resource_reference(&transfer->resource, NULL);
- FREE(transfer);
-}
-
-static void
-ilo_transfer_flush_region(struct pipe_context *pipe,
- struct pipe_transfer *transfer,
- const struct pipe_box *box)
-{
}
static bool
-map_resource(struct ilo_context *ilo, struct ilo_resource *res,
- unsigned usage)
+transfer_map_direct(struct ilo_context *ilo,
+ struct ilo_resource *res,
+ struct ilo_transfer *xfer)
{
- struct ilo_screen *is = ilo_screen(res->base.screen);
- bool will_be_busy;
- int err;
+ int x, y, err;
- /* simply map unsynchronized */
- if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
+ if (xfer->base.usage & PIPE_TRANSFER_UNSYNCHRONIZED)
err = res->bo->map_unsynchronized(res->bo);
- return !err;
- }
+ /* prefer map() when there is the last-level cache */
+ else if (res->tiling == INTEL_TILING_NONE &&
+ (ilo->dev->has_llc || (xfer->base.usage & PIPE_TRANSFER_READ)))
+ err = res->bo->map(res->bo, (xfer->base.usage & PIPE_TRANSFER_WRITE));
+ else
+ err = res->bo->map_gtt(res->bo);
+
+ if (err)
+ return false;
+
+ /* note that stride is for a block row, not a texel row */
+ xfer->base.stride = res->bo_stride;
/*
- * XXX With hardware context support, the bo may be needed by GPU without
- * being referenced by ilo->cp->bo. We have to flush unconditionally, and
- * that is bad.
+ * we can walk through layers when the resource is a texture array or
+ * when this is the first level of a 3D texture being mapped
*/
- if (ilo->cp->hw_ctx)
- ilo_cp_flush(ilo->cp);
+ if (res->base.array_size > 1 ||
+ (res->base.target == PIPE_TEXTURE_3D && xfer->base.level == 0)) {
+ const unsigned qpitch = res->slice_offsets[xfer->base.level][1].y -
+ res->slice_offsets[xfer->base.level][0].y;
+
+ assert(qpitch % res->block_height == 0);
+ xfer->base.layer_stride = (qpitch / res->block_height) * xfer->base.stride;
+ }
+ else {
+ xfer->base.layer_stride = 0;
+ }
+
+ x = res->slice_offsets[xfer->base.level][xfer->base.box.z].x;
+ y = res->slice_offsets[xfer->base.level][xfer->base.box.z].y;
+
+ x += xfer->base.box.x;
+ y += xfer->base.box.y;
+
+ /* in blocks */
+ assert(x % res->block_width == 0 && y % res->block_height == 0);
+ x /= res->block_width;
+ y /= res->block_height;
+
+ xfer->ptr = res->bo->get_virtual(res->bo);
+ xfer->ptr += y * res->bo_stride + x * res->bo_cpp;
+
+ return true;
+}
+
+/**
+ * Choose the best mapping method, depending on the transfer usage and whether
+ * the bo is busy.
+ */
+static bool
+transfer_map_choose_method(struct ilo_context *ilo,
+ struct ilo_resource *res,
+ struct ilo_transfer *xfer)
+{
+ bool will_be_busy, will_stall;
+
+ xfer->method = ILO_TRANSFER_MAP_DIRECT;
+
+ /* unsynchronized map does not stall */
+ if (xfer->base.usage & PIPE_TRANSFER_UNSYNCHRONIZED)
+ return true;
will_be_busy = ilo->cp->bo->references(ilo->cp->bo, res->bo);
+ if (!will_be_busy) {
+ /*
+ * XXX With hardware context support, the bo may be needed by GPU
+ * without being referenced by ilo->cp->bo. We have to flush
+ * unconditionally, and that is bad.
+ */
+ if (ilo->cp->hw_ctx)
+ ilo_cp_flush(ilo->cp);
- /* see if we can avoid stalling */
- if (will_be_busy || intel_bo_is_busy(res->bo)) {
- bool will_stall = true;
+ if (!intel_bo_is_busy(res->bo))
+ return true;
+ }
- if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
- /* discard old bo and allocate a new one for mapping */
- if (realloc_bo(res))
- will_stall = false;
- }
- else if (usage & PIPE_TRANSFER_MAP_DIRECTLY) {
- /* nothing we can do */
- }
- else if (usage & PIPE_TRANSFER_FLUSH_EXPLICIT) {
- /*
- * We could allocate and return a system buffer here. When a region
- * of the buffer is explicitly flushed, we pwrite() the region to a
- * temporary bo and emit pipelined copy blit.
- *
- * For now, do nothing.
- */
- }
- else if (usage & PIPE_TRANSFER_DISCARD_RANGE) {
- /*
- * We could allocate a temporary bo for mapping, and emit pipelined
- * copy blit upon unmapping.
- *
- * For now, do nothing.
- */
- }
+ /* bo is busy and mapping it will stall */
+ will_stall = true;
+
+ if (xfer->base.usage & PIPE_TRANSFER_MAP_DIRECTLY) {
+ /* nothing we can do */
+ }
+ else if (xfer->base.usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
+ /* discard old bo and allocate a new one for mapping */
+ if (realloc_bo(res))
+ will_stall = false;
+ }
+ else if (xfer->base.usage & PIPE_TRANSFER_FLUSH_EXPLICIT) {
+ /*
+ * We could allocate and return a system buffer here. When a region of
+ * the buffer is explicitly flushed, we pwrite() the region to a
+ * temporary bo and emit pipelined copy blit.
+ *
+ * For now, do nothing.
+ */
+ }
+ else if (xfer->base.usage & PIPE_TRANSFER_DISCARD_RANGE) {
+ /*
+ * We could allocate a temporary bo for mapping, and emit pipelined copy
+ * blit upon unmapping.
+ *
+ * For now, do nothing.
+ */
+ }
- if (will_stall) {
- if (usage & PIPE_TRANSFER_DONTBLOCK)
- return false;
+ if (will_stall) {
+ if (xfer->base.usage & PIPE_TRANSFER_DONTBLOCK)
+ return false;
- /* flush to make bo busy (so that map() stalls as it should be) */
- if (will_be_busy)
- ilo_cp_flush(ilo->cp);
- }
+ /* flush to make bo busy (so that map() stalls as it should be) */
+ if (will_be_busy)
+ ilo_cp_flush(ilo->cp);
}
- /* prefer map() when there is the last-level cache */
- if (res->tiling == INTEL_TILING_NONE &&
- (is->dev.has_llc || (usage & PIPE_TRANSFER_READ)))
- err = res->bo->map(res->bo, (usage & PIPE_TRANSFER_WRITE));
- else
- err = res->bo->map_gtt(res->bo);
+ return true;
+}
- return !err;
+static void
+ilo_transfer_flush_region(struct pipe_context *pipe,
+ struct pipe_transfer *transfer,
+ const struct pipe_box *box)
+{
+}
+
+static void
+ilo_transfer_unmap(struct pipe_context *pipe,
+ struct pipe_transfer *transfer)
+{
+ struct ilo_context *ilo = ilo_context(pipe);
+ struct ilo_resource *res = ilo_resource(transfer->resource);
+ struct ilo_transfer *xfer = ilo_transfer(transfer);
+
+ switch (xfer->method) {
+ case ILO_TRANSFER_MAP_DIRECT:
+ transfer_unmap_direct(ilo, res, xfer);
+ break;
+ default:
+ assert(!"unknown mapping method");
+ break;
+ }
+
+ pipe_resource_reference(&xfer->base.resource, NULL);
+ FREE(xfer);
}
static void *
@@ -347,61 +434,46 @@ ilo_transfer_map(struct pipe_context *pipe,
{
struct ilo_context *ilo = ilo_context(pipe);
struct ilo_resource *res = ilo_resource(r);
- struct pipe_transfer *xfer;
- void *ptr;
- int x, y;
+ struct ilo_transfer *xfer;
+ int ok;
- xfer = MALLOC_STRUCT(pipe_transfer);
- if (!xfer)
- return NULL;
-
- if (!map_resource(ilo, res, usage)) {
- FREE(xfer);
+ xfer = MALLOC_STRUCT(ilo_transfer);
+ if (!xfer) {
+ *transfer = NULL;
return NULL;
}
- /* init transfer */
- xfer->resource = NULL;
- pipe_resource_reference(&xfer->resource, &res->base);
- xfer->level = level;
- xfer->usage = usage;
- xfer->box = *box;
- /* stride for a block row, not a texel row */
- xfer->stride = res->bo_stride;
-
- /*
- * we can walk through layers when the resource is a texture array or
- * when this is the first level of a 3D texture being mapped
- */
- if (res->base.array_size > 1 ||
- (res->base.target == PIPE_TEXTURE_3D && level == 0)) {
- const unsigned qpitch =
- res->slice_offsets[level][1].y - res->slice_offsets[level][0].y;
-
- assert(qpitch % res->block_height == 0);
- xfer->layer_stride = (qpitch / res->block_height) * xfer->stride;
- }
- else {
- xfer->layer_stride = 0;
+ xfer->base.resource = NULL;
+ pipe_resource_reference(&xfer->base.resource, &res->base);
+ xfer->base.level = level;
+ xfer->base.usage = usage;
+ xfer->base.box = *box;
+
+ ok = transfer_map_choose_method(ilo, res, xfer);
+ if (ok) {
+ switch (xfer->method) {
+ case ILO_TRANSFER_MAP_DIRECT:
+ ok = transfer_map_direct(ilo, res, xfer);
+ break;
+ default:
+ assert(!"unknown mapping method");
+ ok = false;
+ break;
+ }
}
- x = res->slice_offsets[level][box->z].x;
- y = res->slice_offsets[level][box->z].y;
+ if (!ok) {
+ pipe_resource_reference(&xfer->base.resource, NULL);
+ FREE(xfer);
- x += box->x;
- y += box->y;
+ *transfer = NULL;
- /* in blocks */
- assert(x % res->block_width == 0 && y % res->block_height == 0);
- x /= res->block_width;
- y /= res->block_height;
-
- ptr = res->bo->get_virtual(res->bo);
- ptr += y * res->bo_stride + x * res->bo_cpp;
+ return NULL;
+ }
- *transfer = xfer;
+ *transfer = &xfer->base;
- return ptr;
+ return xfer->ptr;
}
static bool