#include "util/u_surface.h"
#include "util/u_transfer.h"
+#include <drm_fourcc.h>
+
/* Compute offset into a 1D/2D/3D buffer of a certain box.
* This box must be aligned to the block width and height of the
* underlying format. */
if (rsc->texture && !etna_resource_newer(rsc, etna_resource(rsc->texture)))
rsc = etna_resource(rsc->texture); /* switch to using the texture resource */
+ /*
+ * Temporary resources are always pulled into the CPU domain, must push them
+ * back into GPU domain before the RS execs the blit to the base resource.
+ */
if (trans->rsc)
etna_bo_cpu_fini(etna_resource(trans->rsc)->bo);
struct etna_resource_level *res_level = &rsc->levels[ptrans->level];
void *mapped = etna_bo_map(rsc->bo) + res_level->offset;
- if (rsc->layout == ETNA_LAYOUT_LINEAR || rsc->layout == ETNA_LAYOUT_TILED) {
- if (rsc->layout == ETNA_LAYOUT_TILED && !util_format_is_compressed(rsc->base.format)) {
- etna_texture_tile(
- mapped + ptrans->box.z * res_level->layer_stride,
- trans->staging, ptrans->box.x, ptrans->box.y,
- res_level->stride, ptrans->box.width, ptrans->box.height,
- ptrans->stride, util_format_get_blocksize(rsc->base.format));
- } else { /* non-tiled or compressed format */
- util_copy_box(mapped, rsc->base.format, res_level->stride,
- res_level->layer_stride, ptrans->box.x,
- ptrans->box.y, ptrans->box.z, ptrans->box.width,
- ptrans->box.height, ptrans->box.depth,
- trans->staging, ptrans->stride,
- ptrans->layer_stride, 0, 0, 0 /* src x,y,z */);
- }
+ if (rsc->layout == ETNA_LAYOUT_TILED) {
+ etna_texture_tile(
+ mapped + ptrans->box.z * res_level->layer_stride,
+ trans->staging, ptrans->box.x, ptrans->box.y,
+ res_level->stride, ptrans->box.width, ptrans->box.height,
+ ptrans->stride, util_format_get_blocksize(rsc->base.format));
+ } else if (rsc->layout == ETNA_LAYOUT_LINEAR) {
+ util_copy_box(mapped, rsc->base.format, res_level->stride,
+ res_level->layer_stride, ptrans->box.x,
+ ptrans->box.y, ptrans->box.z, ptrans->box.width,
+ ptrans->box.height, ptrans->box.depth,
+ trans->staging, ptrans->stride,
+ ptrans->layer_stride, 0, 0, 0 /* src x,y,z */);
} else {
BUG("unsupported tiling %i", rsc->layout);
}
}
}
- if (!trans->rsc)
+ /*
+ * Transfers without a temporary are only pulled into the CPU domain if they
+ * are not mapped unsynchronized. If they are, must push them back into GPU
+ * domain after CPU access is finished.
+ */
+ if (!trans->rsc && !(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED))
etna_bo_cpu_fini(rsc->bo);
pipe_resource_reference(&trans->rsc, NULL);
assert(level <= prsc->last_level);
+ /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
+ * being mapped. If we add buffer reallocation to avoid CPU/GPU sync this
+ * check needs to be extended to coherent mappings and shared resources.
+ */
+ if ((usage & PIPE_TRANSFER_DISCARD_RANGE) &&
+ !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
+ prsc->last_level == 0 &&
+ prsc->width0 == box->width &&
+ prsc->height0 == box->height &&
+ prsc->depth0 == box->depth &&
+ prsc->array_size == 1) {
+ usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
+ }
+
if (rsc->texture && !etna_resource_newer(rsc, etna_resource(rsc->texture))) {
/* We have a texture resource which is the same age or newer than the
* render resource. Use the texture resource, which avoids bouncing
templ.nr_samples = 0;
templ.bind = PIPE_BIND_RENDER_TARGET;
- trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR, &templ);
+ trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR,
+ DRM_FORMAT_MOD_LINEAR, &templ);
if (!trans->rsc) {
slab_free(&ctx->transfer_pool, trans);
return NULL;
}
- etna_copy_resource(pctx, trans->rsc, prsc, level, trans->rsc->last_level);
+ if (!(usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE))
+ etna_copy_resource(pctx, trans->rsc, prsc, level,
+ trans->rsc->last_level);
/* Switch to using the temporary resource instead */
rsc = etna_resource(trans->rsc);
/* Always sync if we have the temporary resource. The PIPE_TRANSFER_READ
* case could be optimised if we knew whether the resource has outstanding
* rendering. */
- if (usage & PIPE_TRANSFER_READ || trans->rsc)
- etna_resource_wait(pctx, rsc);
+ if ((usage & PIPE_TRANSFER_READ || trans->rsc) &&
+ rsc->status & ETNA_PENDING_WRITE)
+ pctx->flush(pctx, NULL, 0);
/* XXX we don't handle PIPE_TRANSFER_FLUSH_EXPLICIT; this flag can be ignored
* when mapping in-place,
PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE is set.
*/
- /* No need to allocate a buffer for copying if the resource is not in use,
- * and no tiling is needed, can just return a direct pointer.
+ /*
+ * Pull resources into the CPU domain. Only skipped for unsynchronized
+ * transfers without a temporary resource.
*/
- bool in_place = rsc->layout == ETNA_LAYOUT_LINEAR ||
- (rsc->layout == ETNA_LAYOUT_TILED &&
- util_format_is_compressed(prsc->format));
-
- /* Ignore PIPE_TRANSFER_UNSYNCHRONIZED and PIPE_TRANSFER_DONTBLOCK here.
- * It appears that Gallium operates the index/vertex buffers in a
- * circular fashion, and the CPU can catch up with the GPU and starts
- * overwriting yet-to-be-processed entries, causing rendering corruption. */
- uint32_t prep_flags = 0;
+ if (trans->rsc || !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
+ uint32_t prep_flags = 0;
- if (usage & PIPE_TRANSFER_READ)
- prep_flags |= DRM_ETNA_PREP_READ;
- if (usage & PIPE_TRANSFER_WRITE)
- prep_flags |= DRM_ETNA_PREP_WRITE;
+ if (usage & PIPE_TRANSFER_READ)
+ prep_flags |= DRM_ETNA_PREP_READ;
+ if (usage & PIPE_TRANSFER_WRITE)
+ prep_flags |= DRM_ETNA_PREP_WRITE;
- if (etna_bo_cpu_prep(rsc->bo, prep_flags))
- goto fail_prep;
+ if (etna_bo_cpu_prep(rsc->bo, prep_flags))
+ goto fail_prep;
+ }
/* map buffer object */
void *mapped = etna_bo_map(rsc->bo);
*out_transfer = ptrans;
- if (in_place) {
+ if (rsc->layout == ETNA_LAYOUT_LINEAR) {
ptrans->stride = res_level->stride;
ptrans->layer_stride = res_level->layer_stride;
goto fail;
if (usage & PIPE_TRANSFER_READ) {
- /* untile or copy resource for reading */
- if (rsc->layout == ETNA_LAYOUT_LINEAR || rsc->layout == ETNA_LAYOUT_TILED) {
- if (rsc->layout == ETNA_LAYOUT_TILED && !util_format_is_compressed(rsc->base.format)) {
- etna_texture_untile(trans->staging,
- mapped + ptrans->box.z * res_level->layer_stride,
- ptrans->box.x, ptrans->box.y, res_level->stride,
- ptrans->box.width, ptrans->box.height, ptrans->stride,
- util_format_get_blocksize(rsc->base.format));
- } else { /* non-tiled or compressed format */
- util_copy_box(trans->staging, rsc->base.format, ptrans->stride,
- ptrans->layer_stride, 0, 0, 0, /* dst x,y,z */
- ptrans->box.width, ptrans->box.height,
- ptrans->box.depth, mapped, res_level->stride,
- res_level->layer_stride, ptrans->box.x,
- ptrans->box.y, ptrans->box.z);
- }
- } else /* TODO supertiling */
- {
+ if (rsc->layout == ETNA_LAYOUT_TILED) {
+ etna_texture_untile(trans->staging,
+ mapped + ptrans->box.z * res_level->layer_stride,
+ ptrans->box.x, ptrans->box.y, res_level->stride,
+ ptrans->box.width, ptrans->box.height, ptrans->stride,
+ util_format_get_blocksize(rsc->base.format));
+ } else if (rsc->layout == ETNA_LAYOUT_LINEAR) {
+ util_copy_box(trans->staging, rsc->base.format, ptrans->stride,
+ ptrans->layer_stride, 0, 0, 0, /* dst x,y,z */
+ ptrans->box.width, ptrans->box.height,
+ ptrans->box.depth, mapped, res_level->stride,
+ res_level->layer_stride, ptrans->box.x,
+ ptrans->box.y, ptrans->box.z);
+ } else {
+ /* TODO supertiling */
BUG("unsupported tiling %i for reading", rsc->layout);
}
}