Exemple #1
0
static void *
fd_resource_transfer_map(struct pipe_context *pctx,
		struct pipe_resource *prsc,
		unsigned level, unsigned usage,
		const struct pipe_box *box,
		struct pipe_transfer **pptrans)
{
	struct fd_context *ctx = fd_context(pctx);
	struct fd_resource *rsc = fd_resource(prsc);
	struct pipe_transfer *ptrans = util_slab_alloc(&ctx->transfer_pool);
	enum pipe_format format = prsc->format;
	char *buf;

	if (!ptrans)
		return NULL;

	ptrans->resource = prsc;
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = rsc->pitch * rsc->cpp;
	ptrans->layer_stride = ptrans->stride;

	buf = fd_bo_map(rsc->bo);

	*pptrans = ptrans;

	return buf +
		box->y / util_format_get_blockheight(format) * ptrans->stride +
		box->x / util_format_get_blockwidth(format) * rsc->cpp;
}
Exemple #2
0
static struct pipe_transfer *r600_get_transfer(struct pipe_context *ctx,
					       struct pipe_resource *resource,
					       unsigned level,
					       unsigned usage,
					       const struct pipe_box *box)
{
	struct r600_context *rctx = (struct r600_context*)ctx;
	struct r600_transfer *transfer = util_slab_alloc(&rctx->pool_transfers);

	assert(box->x + box->width <= resource->width0);

	transfer->transfer.resource = resource;
	transfer->transfer.level = level;
	transfer->transfer.usage = usage;
	transfer->transfer.box = *box;
	transfer->transfer.stride = 0;
	transfer->transfer.layer_stride = 0;
	transfer->transfer.data = NULL;
	transfer->staging = NULL;
	transfer->offset = 0;

	/* Note strides are zero, this is ok for buffers, but not for
	 * textures 2d & higher at least.
	 */
	return &transfer->transfer;
}
Exemple #3
0
struct pipe_transfer * r600_compute_global_get_transfer(
	struct pipe_context *ctx_,
	struct pipe_resource *resource,
	unsigned level,
	unsigned usage,
	const struct pipe_box *box)
{
	struct r600_context *ctx = (struct r600_context *)ctx_;
	struct compute_memory_pool *pool = ctx->screen->global_pool;

	compute_memory_finalize_pending(pool, ctx_);

	assert(resource->target == PIPE_BUFFER);
	struct r600_context *rctx = (struct r600_context*)ctx_;
	struct pipe_transfer *transfer = util_slab_alloc(&rctx->pool_transfers);

	transfer->resource = resource;
	transfer->level = level;
	transfer->usage = usage;
	transfer->box = *box;
	transfer->stride = 0;
	transfer->layer_stride = 0;
	transfer->data = NULL;

	/* Note strides are zero, this is ok for buffers, but not for
	* textures 2d & higher at least.
	*/
	return transfer;
}
struct pipe_resource *r300_user_buffer_create(struct pipe_screen *screen,
					      void *ptr, unsigned size,
					      unsigned bind)
{
    struct r300_screen *r300screen = r300_screen(screen);
    struct r300_resource *rbuf;

    rbuf = util_slab_alloc(&r300screen->pool_buffers);

    pipe_reference_init(&rbuf->b.b.reference, 1);
    rbuf->b.b.screen = screen;
    rbuf->b.b.target = PIPE_BUFFER;
    rbuf->b.b.format = PIPE_FORMAT_R8_UNORM;
    rbuf->b.b.usage = PIPE_USAGE_IMMUTABLE;
    rbuf->b.b.bind = bind;
    rbuf->b.b.width0 = ~0;
    rbuf->b.b.height0 = 1;
    rbuf->b.b.depth0 = 1;
    rbuf->b.b.array_size = 1;
    rbuf->b.b.flags = 0;
    rbuf->b.b.user_ptr = ptr;
    rbuf->b.vtbl = &r300_buffer_vtbl;
    rbuf->domain = RADEON_DOMAIN_GTT;
    rbuf->buf = NULL;
    rbuf->constant_buffer = NULL;
    return &rbuf->b.b;
}
static struct pipe_transfer *
i915_get_transfer(struct pipe_context *pipe,
                  struct pipe_resource *resource,
                  unsigned level,
                  unsigned usage,
                  const struct pipe_box *box)
{
   struct i915_context *i915 = i915_context(pipe);
   struct pipe_transfer *transfer;

   if (usage & PIPE_TRANSFER_MAP_PERMANENTLY) {
      return NULL;
   }

   transfer = util_slab_alloc(&i915->transfer_pool);
   if (transfer == NULL)
      return NULL;

   transfer->resource = resource;
   transfer->level = level;
   transfer->usage = usage;
   transfer->box = *box;

   /* Note strides are zero, this is ok for buffers, but not for
    * textures 2d & higher at least. 
    */
   return transfer;
}
Exemple #6
0
static void *virgl_buffer_transfer_map(struct pipe_context *ctx,
                                       struct pipe_resource *resource,
                                       unsigned level,
                                       unsigned usage,
                                       const struct pipe_box *box,
                                       struct pipe_transfer **transfer)
{
   struct virgl_context *vctx = virgl_context(ctx);
   struct virgl_screen *vs = virgl_screen(ctx->screen);
   struct virgl_buffer *vbuf = virgl_buffer(resource);
   struct virgl_transfer *trans;
   void *ptr;
   bool readback;
   uint32_t offset;
   bool doflushwait = false;

   if ((usage & PIPE_TRANSFER_READ) && (vbuf->on_list == TRUE))
      doflushwait = true;
   else
      doflushwait = virgl_res_needs_flush_wait(vctx, &vbuf->base, usage);

   if (doflushwait)
      ctx->flush(ctx, NULL, 0);

   trans = util_slab_alloc(&vctx->texture_transfer_pool);
   if (!trans)
      return NULL;

   trans->base.resource = resource;
   trans->base.level = level;
   trans->base.usage = usage;
   trans->base.box = *box;
   trans->base.stride = 0;
   trans->base.layer_stride = 0;

   offset = box->x;

   readback = virgl_res_needs_readback(vctx, &vbuf->base, usage);
   if (readback)
      vs->vws->transfer_get(vs->vws, vbuf->base.hw_res, box, trans->base.stride, trans->base.layer_stride, offset, level);

   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED))
      doflushwait = true;

   if (doflushwait || readback)
      vs->vws->resource_wait(vs->vws, vbuf->base.hw_res);

   ptr = vs->vws->resource_map(vs->vws, vbuf->base.hw_res);
   if (!ptr) {
      return NULL;
   }

   trans->offset = offset;
   *transfer = &trans->base;

   return ptr + trans->offset;
}
Exemple #7
0
void *r600_compute_global_transfer_map(
	struct pipe_context *ctx_,
	struct pipe_resource *resource,
	unsigned level,
	unsigned usage,
	const struct pipe_box *box,
	struct pipe_transfer **ptransfer)
{
	struct r600_context *rctx = (struct r600_context*)ctx_;
	struct compute_memory_pool *pool = rctx->screen->global_pool;
	struct pipe_transfer *transfer = util_slab_alloc(&rctx->pool_transfers);
	struct r600_resource_global* buffer =
		(struct r600_resource_global*)resource;
	uint32_t* map;

	compute_memory_finalize_pending(pool, ctx_);

	assert(resource->target == PIPE_BUFFER);

	COMPUTE_DBG(rctx->screen, "* r600_compute_global_get_transfer()\n"
			"level = %u, usage = %u, box(x = %u, y = %u, z = %u "
			"width = %u, height = %u, depth = %u)\n", level, usage,
			box->x, box->y, box->z, box->width, box->height,
			box->depth);

	transfer->resource = resource;
	transfer->level = level;
	transfer->usage = usage;
	transfer->box = *box;
	transfer->stride = 0;
	transfer->layer_stride = 0;

	assert(transfer->resource->target == PIPE_BUFFER);
	assert(transfer->resource->bind & PIPE_BIND_GLOBAL);
	assert(transfer->box.x >= 0);
	assert(transfer->box.y == 0);
	assert(transfer->box.z == 0);

	///TODO: do it better, mapping is not possible if the pool is too big

	COMPUTE_DBG(rctx->screen, "* r600_compute_global_transfer_map()\n");

	if (!(map = r600_buffer_mmap_sync_with_rings(rctx, buffer->chunk->pool->bo, transfer->usage))) {
		util_slab_free(&rctx->pool_transfers, transfer);
		return NULL;
	}

	*ptransfer = transfer;

	COMPUTE_DBG(rctx->screen, "Buffer: %p + %u (buffer offset in global memory) "
		"+ %u (box.x)\n", map, buffer->chunk->start_in_dw, transfer->box.x);
	return ((char*)(map + buffer->chunk->start_in_dw)) + transfer->box.x;
}
static void *
fd_resource_transfer_map(struct pipe_context *pctx,
		struct pipe_resource *prsc,
		unsigned level, unsigned usage,
		const struct pipe_box *box,
		struct pipe_transfer **pptrans)
{
	struct fd_context *ctx = fd_context(pctx);
	struct fd_resource *rsc = fd_resource(prsc);
	struct pipe_transfer *ptrans = util_slab_alloc(&ctx->transfer_pool);
	enum pipe_format format = prsc->format;
	uint32_t op = 0;
	char *buf;

	if (!ptrans)
		return NULL;

	/* util_slab_alloc() doesn't zero: */
	memset(ptrans, 0, sizeof(*ptrans));

	pipe_resource_reference(&ptrans->resource, prsc);
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = rsc->pitch * rsc->cpp;
	ptrans->layer_stride = ptrans->stride;

	/* some state trackers (at least XA) don't do this.. */
	if (!(usage & PIPE_TRANSFER_FLUSH_EXPLICIT))
		fd_resource_transfer_flush_region(pctx, ptrans, box);

	buf = fd_bo_map(rsc->bo);
	if (!buf) {
		fd_resource_transfer_unmap(pctx, ptrans);
		return NULL;
	}

	if (usage & PIPE_TRANSFER_READ)
		op |= DRM_FREEDRENO_PREP_READ;

	if (usage & PIPE_TRANSFER_WRITE)
		op |= DRM_FREEDRENO_PREP_WRITE;

	if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED))
		fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);

	*pptrans = ptrans;

	return buf +
		box->y / util_format_get_blockheight(format) * ptrans->stride +
		box->x / util_format_get_blockwidth(format) * rsc->cpp;
}
Exemple #9
0
static void
resume_query(struct fd_context *ctx, struct fd_hw_query *hq,
		struct fd_ringbuffer *ring)
{
	int idx = pidx(hq->provider->query_type);
	assert(idx >= 0);   /* query never would have been created otherwise */
	assert(!hq->period);
	ctx->active_providers |= (1 << idx);
	hq->period = util_slab_alloc(&ctx->sample_period_pool);
	list_inithead(&hq->period->list);
	hq->period->start = get_sample(ctx, ring, hq->base.type);
	/* NOTE: util_slab_alloc() does not zero out the buffer: */
	hq->period->end = NULL;
}
Exemple #10
0
static struct pipe_transfer *r600_get_transfer(struct pipe_context *ctx,
        struct pipe_resource *resource,
        unsigned level,
        unsigned usage,
        const struct pipe_box *box)
{
    struct r600_context *rctx = (struct r600_context*)ctx;
    struct pipe_transfer *transfer = util_slab_alloc(&rctx->pool_transfers);

    transfer->resource = resource;
    transfer->level = level;
    transfer->usage = usage;
    transfer->box = *box;
    transfer->stride = 0;
    transfer->layer_stride = 0;
    transfer->data = NULL;

    /* Note strides are zero, this is ok for buffers, but not for
     * textures 2d & higher at least.
     */
    return transfer;
}
struct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
					 const struct pipe_resource *templ)
{
    struct r300_screen *r300screen = r300_screen(screen);
    struct r300_resource *rbuf;
    unsigned alignment = 16;

    rbuf = util_slab_alloc(&r300screen->pool_buffers);

    rbuf->b.b = *templ;
    rbuf->b.vtbl = &r300_buffer_vtbl;
    pipe_reference_init(&rbuf->b.b.reference, 1);
    rbuf->b.b.screen = screen;
    rbuf->b.b.user_ptr = NULL;
    rbuf->domain = RADEON_DOMAIN_GTT;
    rbuf->buf = NULL;
    rbuf->constant_buffer = NULL;

    /* Alloc constant buffers in RAM. */
    if (templ->bind & PIPE_BIND_CONSTANT_BUFFER) {
        rbuf->constant_buffer = MALLOC(templ->width0);
        return &rbuf->b.b;
    }

    rbuf->buf =
        r300screen->rws->buffer_create(r300screen->rws,
                                       rbuf->b.b.width0, alignment,
                                       rbuf->b.b.bind, rbuf->domain);
    if (!rbuf->buf) {
        util_slab_free(&r300screen->pool_buffers, rbuf);
        return NULL;
    }

    rbuf->cs_buf =
        r300screen->rws->buffer_get_cs_handle(rbuf->buf);

    return &rbuf->b.b;
}
Exemple #12
0
static void *r600_buffer_get_transfer(struct pipe_context *ctx,
				      struct pipe_resource *resource,
                                      unsigned level,
                                      unsigned usage,
                                      const struct pipe_box *box,
				      struct pipe_transfer **ptransfer,
				      void *data, struct r600_resource *staging)
{
	struct r600_context *rctx = (struct r600_context*)ctx;
	struct r600_transfer *transfer = util_slab_alloc(&rctx->pool_transfers);

	transfer->transfer.resource = resource;
	transfer->transfer.level = level;
	transfer->transfer.usage = usage;
	transfer->transfer.box = *box;
	transfer->transfer.stride = 0;
	transfer->transfer.layer_stride = 0;
	transfer->staging = NULL;
	transfer->offset = 0;
	transfer->staging = staging;
	*ptransfer = &transfer->transfer;
	return data;
}
Exemple #13
0
static void *
i915_buffer_transfer_map(struct pipe_context *pipe,
                         struct pipe_resource *resource,
                         unsigned level,
                         unsigned usage,
                         const struct pipe_box *box,
                         struct pipe_transfer **ptransfer)
{
   struct i915_context *i915 = i915_context(pipe);
   struct i915_buffer *buffer = i915_buffer(resource);
   struct pipe_transfer *transfer = util_slab_alloc(&i915->transfer_pool);

   if (transfer == NULL)
      return NULL;

   transfer->resource = resource;
   transfer->level = level;
   transfer->usage = usage;
   transfer->box = *box;
   *ptransfer = transfer;

   return buffer->data + transfer->box.x;
}
static void *
fd_resource_transfer_map(struct pipe_context *pctx,
		struct pipe_resource *prsc,
		unsigned level, unsigned usage,
		const struct pipe_box *box,
		struct pipe_transfer **pptrans)
{
	struct fd_context *ctx = fd_context(pctx);
	struct fd_resource *rsc = fd_resource(prsc);
	struct fd_resource_slice *slice = fd_resource_slice(rsc, level);
	struct pipe_transfer *ptrans;
	enum pipe_format format = prsc->format;
	uint32_t op = 0;
	uint32_t offset;
	char *buf;
	int ret = 0;

	DBG("prsc=%p, level=%u, usage=%x", prsc, level, usage);

	ptrans = util_slab_alloc(&ctx->transfer_pool);
	if (!ptrans)
		return NULL;

	/* util_slab_alloc() doesn't zero: */
	memset(ptrans, 0, sizeof(*ptrans));

	pipe_resource_reference(&ptrans->resource, prsc);
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = slice->pitch * rsc->cpp;
	ptrans->layer_stride = slice->size0;

	if (usage & PIPE_TRANSFER_READ)
		op |= DRM_FREEDRENO_PREP_READ;

	if (usage & PIPE_TRANSFER_WRITE)
		op |= DRM_FREEDRENO_PREP_WRITE;

	if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
		realloc_bo(rsc, fd_bo_size(rsc->bo));
		fd_invalidate_resource(ctx, prsc);
	} else if ((usage & PIPE_TRANSFER_WRITE) &&
			   prsc->target == PIPE_BUFFER &&
			   !util_ranges_intersect(&rsc->valid_buffer_range,
									  box->x, box->x + box->width)) {
		/* We are trying to write to a previously uninitialized range. No need
		 * to wait.
		 */
	} else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
		/* If the GPU is writing to the resource, or if it is reading from the
		 * resource and we're trying to write to it, flush the renders.
		 */
		if (rsc->dirty ||
			((ptrans->usage & PIPE_TRANSFER_WRITE) && rsc->reading))
			fd_context_render(pctx);

		/* The GPU keeps track of how the various bo's are being used, and
		 * will wait if necessary for the proper operation to have
		 * completed.
		 */
		ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);
		if (ret)
			goto fail;
	}

	buf = fd_bo_map(rsc->bo);
	if (!buf) {
		fd_resource_transfer_unmap(pctx, ptrans);
		return NULL;
	}

	*pptrans = ptrans;

	if (rsc->layer_first) {
		offset = slice->offset +
			box->y / util_format_get_blockheight(format) * ptrans->stride +
			box->x / util_format_get_blockwidth(format) * rsc->cpp +
			box->z * rsc->layer_size;
	} else {
		offset = slice->offset +
			box->y / util_format_get_blockheight(format) * ptrans->stride +
			box->x / util_format_get_blockwidth(format) * rsc->cpp +
			box->z * slice->size0;
	}

	return buf + offset;

fail:
	fd_resource_transfer_unmap(pctx, ptrans);
	return NULL;
}
Exemple #15
0
static void *
fd_resource_transfer_map(struct pipe_context *pctx,
		struct pipe_resource *prsc,
		unsigned level, unsigned usage,
		const struct pipe_box *box,
		struct pipe_transfer **pptrans)
{
	struct fd_context *ctx = fd_context(pctx);
	struct fd_resource *rsc = fd_resource(prsc);
	struct fd_resource_slice *slice = fd_resource_slice(rsc, level);
	struct pipe_transfer *ptrans;
	enum pipe_format format = prsc->format;
	uint32_t op = 0;
	char *buf;
	int ret = 0;

	ptrans = util_slab_alloc(&ctx->transfer_pool);
	if (!ptrans)
		return NULL;

	/* util_slab_alloc() doesn't zero: */
	memset(ptrans, 0, sizeof(*ptrans));

	pipe_resource_reference(&ptrans->resource, prsc);
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = slice->pitch * rsc->cpp;
	ptrans->layer_stride = slice->size0;

	if (usage & PIPE_TRANSFER_READ)
		op |= DRM_FREEDRENO_PREP_READ;

	if (usage & PIPE_TRANSFER_WRITE)
		op |= DRM_FREEDRENO_PREP_WRITE;

	if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)
		op |= DRM_FREEDRENO_PREP_NOSYNC;

	/* some state trackers (at least XA) don't do this.. */
	if (!(usage & (PIPE_TRANSFER_FLUSH_EXPLICIT | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)))
		fd_resource_transfer_flush_region(pctx, ptrans, box);

	if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
		ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);
		if ((ret == -EBUSY) && (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE))
			realloc_bo(rsc, fd_bo_size(rsc->bo));
		else if (ret)
			goto fail;
	}

	buf = fd_bo_map(rsc->bo);
	if (!buf) {
		fd_resource_transfer_unmap(pctx, ptrans);
		return NULL;
	}

	*pptrans = ptrans;

	return buf + slice->offset +
		box->y / util_format_get_blockheight(format) * ptrans->stride +
		box->x / util_format_get_blockwidth(format) * rsc->cpp +
		box->z * slice->size0;

fail:
	fd_resource_transfer_unmap(pctx, ptrans);
	return NULL;
}
Exemple #16
0
static void *virgl_texture_transfer_map(struct pipe_context *ctx,
                                        struct pipe_resource *resource,
                                        unsigned level,
                                        unsigned usage,
                                        const struct pipe_box *box,
                                        struct pipe_transfer **transfer)
{
   struct virgl_context *vctx = virgl_context(ctx);
   struct virgl_screen *vs = virgl_screen(ctx->screen);
   struct virgl_texture *vtex = virgl_texture(resource);
   enum pipe_format format = resource->format;
   struct virgl_transfer *trans;
   void *ptr;
   boolean readback = TRUE;
   uint32_t offset;
   struct virgl_hw_res *hw_res;
   const unsigned h = u_minify(vtex->base.u.b.height0, level);
   const unsigned nblocksy = util_format_get_nblocksy(format, h);
   bool is_depth = util_format_has_depth(util_format_description(resource->format));
   uint32_t l_stride;
   bool doflushwait;

   doflushwait = virgl_res_needs_flush_wait(vctx, &vtex->base, usage);
   if (doflushwait)
      ctx->flush(ctx, NULL, 0);

   trans = util_slab_alloc(&vctx->texture_transfer_pool);
   if (!trans)
      return NULL;

   trans->base.resource = resource;
   trans->base.level = level;
   trans->base.usage = usage;
   trans->base.box = *box;
   trans->base.stride = vtex->stride[level];
   trans->base.layer_stride = trans->base.stride * nblocksy;

   if (resource->target != PIPE_TEXTURE_3D &&
       resource->target != PIPE_TEXTURE_CUBE &&
       resource->target != PIPE_TEXTURE_1D_ARRAY &&
       resource->target != PIPE_TEXTURE_2D_ARRAY &&
       resource->target != PIPE_TEXTURE_CUBE_ARRAY)
      l_stride = 0;
   else
      l_stride = trans->base.layer_stride;

   if (is_depth && resource->nr_samples > 1) {
      struct pipe_resource tmp_resource;
      virgl_init_temp_resource_from_box(&tmp_resource, resource, box,
                                        level, 0);

      trans->resolve_tmp = (struct virgl_resource *)ctx->screen->resource_create(ctx->screen, &tmp_resource);

      virgl_copy_region_with_blit(ctx, &trans->resolve_tmp->u.b, 0, 0, 0, 0, resource, level, box);
      ctx->flush(ctx, NULL, 0);
      /* we want to do a resolve blit into the temporary */
      hw_res = trans->resolve_tmp->hw_res;
      offset = 0;
   } else {
      offset = vrend_get_tex_image_offset(vtex, level, box->z);

      offset += box->y / util_format_get_blockheight(format) * trans->base.stride +
      box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
      hw_res = vtex->base.hw_res;
      trans->resolve_tmp = NULL;
   }

   readback = virgl_res_needs_readback(vctx, &vtex->base, usage);
   if (readback)
      vs->vws->transfer_get(vs->vws, hw_res, box, trans->base.stride, l_stride, offset, level);

   if (doflushwait || readback)
      vs->vws->resource_wait(vs->vws, vtex->base.hw_res);

   ptr = vs->vws->resource_map(vs->vws, hw_res);
   if (!ptr) {
      return NULL;
   }

   trans->offset = offset;
   *transfer = &trans->base;

   return ptr + trans->offset;
}
Exemple #17
0
static void *
r300_buffer_transfer_map( struct pipe_context *context,
                          struct pipe_resource *resource,
                          unsigned level,
                          unsigned usage,
                          const struct pipe_box *box,
                          struct pipe_transfer **ptransfer )
{
    struct r300_context *r300 = r300_context(context);
    struct radeon_winsys *rws = r300->screen->rws;
    struct r300_resource *rbuf = r300_resource(resource);
    struct pipe_transfer *transfer;
    uint8_t *map;

    transfer = util_slab_alloc(&r300->pool_transfers);
    transfer->resource = resource;
    transfer->level = level;
    transfer->usage = usage;
    transfer->box = *box;
    transfer->stride = 0;
    transfer->layer_stride = 0;

    if (rbuf->malloced_buffer) {
        *ptransfer = transfer;
        return rbuf->malloced_buffer + box->x;
    }

    if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE &&
        !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
        assert(usage & PIPE_TRANSFER_WRITE);

        /* Check if mapping this buffer would cause waiting for the GPU. */
        if (r300->rws->cs_is_buffer_referenced(r300->cs, rbuf->cs_buf, RADEON_USAGE_READWRITE) ||
            !r300->rws->buffer_wait(rbuf->buf, 0, RADEON_USAGE_READWRITE)) {
            unsigned i;
            struct pb_buffer *new_buf;

            /* Create a new one in the same pipe_resource. */
            new_buf = r300->rws->buffer_create(r300->rws, rbuf->b.b.width0,
                                               R300_BUFFER_ALIGNMENT, TRUE,
                                               rbuf->domain, 0);
            if (new_buf) {
                /* Discard the old buffer. */
                pb_reference(&rbuf->buf, NULL);
                rbuf->buf = new_buf;
                rbuf->cs_buf = r300->rws->buffer_get_cs_handle(rbuf->buf);

                /* We changed the buffer, now we need to bind it where the old one was bound. */
                for (i = 0; i < r300->nr_vertex_buffers; i++) {
                    if (r300->vertex_buffer[i].buffer == &rbuf->b.b) {
                        r300->vertex_arrays_dirty = TRUE;
                        break;
                    }
                }
            }
        }
    }

    /* Buffers are never used for write, therefore mapping for read can be
     * unsynchronized. */
    if (!(usage & PIPE_TRANSFER_WRITE)) {
       usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
    }

    map = rws->buffer_map(rbuf->cs_buf, r300->cs, usage);

    if (map == NULL) {
        util_slab_free(&r300->pool_transfers, transfer);
        return NULL;
    }

    *ptransfer = transfer;
    return map + box->x;
}
Exemple #18
0
static void *etna_pipe_transfer_map(struct pipe_context *pipe,
                         struct pipe_resource *resource,
                         unsigned level,
                         unsigned usage,  /* a combination of PIPE_TRANSFER_x */
                         const struct pipe_box *box,
                         struct pipe_transfer **out_transfer)
{
    struct etna_pipe_context *priv = etna_pipe_context(pipe);
    struct etna_transfer *ptrans = util_slab_alloc(&priv->transfer_pool);
    struct etna_resource *resource_priv = etna_resource(resource);
    enum pipe_format format = resource->format;
    if (!ptrans)
        return NULL;
    assert(level <= resource->last_level);

    /* PIPE_TRANSFER_READ always requires a sync. */
    if(usage & PIPE_TRANSFER_READ)
    {
        etna_finish(priv->ctx);
    }
    /* XXX we don't handle PIPE_TRANSFER_FLUSH_EXPLICIT; this flag can be ignored when mapping in-place,
     * but when not in place we need to fire off the copy operation in transfer_flush_region (currently
     * a no-op) instead of unmap. Need to handle this to support ARB_map_buffer_range extension at least.
     */
    /* XXX we don't take care of current operations on the resource; which can be, at some point in the pipeline
       which is not yet executed:

       - bound as surface
       - bound through vertex buffer
       - bound through index buffer
       - bound in sampler view
       - used in clear_render_target / clear_depth_stencil operation
       - used in blit
       - used in resource_copy_region

       How do other drivers record this information over course of the rendering pipeline?
       Is it necessary at all? Only in case we want to provide a fast path and map the resource directly
       (and for PIPE_TRANSFER_MAP_DIRECTLY) and we don't want to force a sync.
       We also need to know whether the resource is in use to determine if a sync is needed (or just do it
       always, but that comes at the expense of performance).

       A conservative approximation without too much overhead would be to mark all resources that have
       been bound at some point as busy. A drawback would be that accessing resources that have
       been bound but are no longer in use for a while still carry a performance penalty. On the other hand,
       the program could be using PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE or PIPE_TRANSFER_UNSYNCHRONIZED to
       avoid this in the first place...

       A) We use an in-pipe copy engine, and queue the copy operation after unmap so that the copy
          will be performed when all current commands have been executed.
          Using the RS is possible, not sure if always efficient. This can also do any kind of tiling for us.
          Only possible when PIPE_TRANSFER_DISCARD_RANGE is set.
       B) We discard the entire resource (or at least, the mipmap level) and allocate new memory for it.
          Only possible when mapping the entire resource or 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.
     */
    ptrans->in_place = resource_priv->layout == ETNA_LAYOUT_LINEAR ||
                       (resource_priv->layout == ETNA_LAYOUT_TILED && util_format_is_compressed(resource->format));
    ptrans->base.resource = resource;
    ptrans->base.level = level;
    ptrans->base.usage = usage;
    ptrans->base.box = *box;

    struct etna_resource_level *res_level = &resource_priv->levels[level];
    /* map buffer object */
    void *mapped = etna_bo_map(resource_priv->bo) + res_level->offset;
    if(likely(ptrans->in_place))
    {
        ptrans->base.stride = res_level->stride;
        ptrans->base.layer_stride = res_level->layer_stride;
        ptrans->buffer = mapped + etna_compute_offset(resource->format, box, res_level->stride, res_level->layer_stride);
    } else {
        unsigned divSizeX = util_format_get_blockwidth(format);
        unsigned divSizeY = util_format_get_blockheight(format);
        if(usage & PIPE_TRANSFER_MAP_DIRECTLY)
        {
            /* No in-place transfer possible */
            util_slab_free(&priv->transfer_pool, ptrans);
            return NULL;
        }

        ptrans->base.stride = align(box->width, divSizeX) * util_format_get_blocksize(format); /* row stride in bytes */
        ptrans->base.layer_stride = align(box->height, divSizeY) * ptrans->base.stride;
        size_t size = ptrans->base.layer_stride * box->depth;
        ptrans->buffer = MALLOC(size);

        if(usage & PIPE_TRANSFER_READ)
        {
            /* untile or copy resource for reading */
            if(resource_priv->layout == ETNA_LAYOUT_LINEAR || resource_priv->layout == ETNA_LAYOUT_TILED)
            {
                if(resource_priv->layout == ETNA_LAYOUT_TILED && !util_format_is_compressed(resource_priv->base.format))
                {
                    etna_texture_untile(ptrans->buffer, mapped + ptrans->base.box.z * res_level->layer_stride,
                            ptrans->base.box.x, ptrans->base.box.y, res_level->stride,
                            ptrans->base.box.width, ptrans->base.box.height, ptrans->base.stride,
                            util_format_get_blocksize(resource_priv->base.format));
                } else { /* non-tiled or compressed format */
                    util_copy_box(ptrans->buffer,
                      resource_priv->base.format,
                      ptrans->base.stride, ptrans->base.layer_stride,
                      0, 0, 0, /* dst x,y,z */
                      ptrans->base.box.width, ptrans->base.box.height, ptrans->base.box.depth,
                      mapped,
                      res_level->stride, res_level->layer_stride,
                      ptrans->base.box.x, ptrans->base.box.y, ptrans->base.box.z);
                }
            } else /* TODO supertiling */
            {
                BUG("unsupported tiling %i for reading", resource_priv->layout);
            }
        }
    }

    *out_transfer = &ptrans->base;
    return ptrans->buffer;
}
static void *
vc4_resource_transfer_map(struct pipe_context *pctx,
                          struct pipe_resource *prsc,
                          unsigned level, unsigned usage,
                          const struct pipe_box *box,
                          struct pipe_transfer **pptrans)
{
    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;

    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++;

    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(trans, 0, sizeof(*trans));
    ptrans = &trans->base;

    pipe_resource_reference(&ptrans->resource, prsc);
    ptrans->level = level;
    ptrans->usage = usage;
    ptrans->box = *box;

    /* Note that the current kernel implementation is synchronous, so no
     * need to do syncing stuff here yet.
     */

    buf = vc4_bo_map(rsc->bo);
    if (!buf) {
        fprintf(stderr, "Failed to map bo\n");
        goto fail;
    }

    *pptrans = ptrans;

    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);
    return NULL;
}
static void *
fd_resource_transfer_map(struct pipe_context *pctx,
		struct pipe_resource *prsc,
		unsigned level, unsigned usage,
		const struct pipe_box *box,
		struct pipe_transfer **pptrans)
{
	struct fd_context *ctx = fd_context(pctx);
	struct fd_resource *rsc = fd_resource(prsc);
	struct fd_resource_slice *slice = fd_resource_slice(rsc, level);
	struct fd_transfer *trans;
	struct pipe_transfer *ptrans;
	enum pipe_format format = prsc->format;
	uint32_t op = 0;
	uint32_t offset;
	char *buf;
	int ret = 0;

	DBG("prsc=%p, level=%u, usage=%x, box=%dx%d+%d,%d", prsc, level, usage,
		box->width, box->height, box->x, box->y);

	ptrans = util_slab_alloc(&ctx->transfer_pool);
	if (!ptrans)
		return NULL;

	/* util_slab_alloc() doesn't zero: */
	trans = fd_transfer(ptrans);
	memset(trans, 0, sizeof(*trans));

	pipe_resource_reference(&ptrans->resource, prsc);
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = util_format_get_nblocksx(format, slice->pitch) * rsc->cpp;
	ptrans->layer_stride = rsc->layer_first ? rsc->layer_size : slice->size0;

	if (usage & PIPE_TRANSFER_READ)
		op |= DRM_FREEDRENO_PREP_READ;

	if (usage & PIPE_TRANSFER_WRITE)
		op |= DRM_FREEDRENO_PREP_WRITE;

	if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
		realloc_bo(rsc, fd_bo_size(rsc->bo));
		if (rsc->stencil)
			realloc_bo(rsc->stencil, fd_bo_size(rsc->stencil->bo));
		fd_invalidate_resource(ctx, prsc);
	} else if ((usage & PIPE_TRANSFER_WRITE) &&
			   prsc->target == PIPE_BUFFER &&
			   !util_ranges_intersect(&rsc->valid_buffer_range,
									  box->x, box->x + box->width)) {
		/* We are trying to write to a previously uninitialized range. No need
		 * to wait.
		 */
	} else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
		/* If the GPU is writing to the resource, or if it is reading from the
		 * resource and we're trying to write to it, flush the renders.
		 */
		if (((ptrans->usage & PIPE_TRANSFER_WRITE) &&
					pending(rsc, FD_PENDING_READ | FD_PENDING_WRITE)) ||
				pending(rsc, FD_PENDING_WRITE))
			fd_context_render(pctx);

		/* The GPU keeps track of how the various bo's are being used, and
		 * will wait if necessary for the proper operation to have
		 * completed.
		 */
		ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);
		if (ret)
			goto fail;
	}

	buf = fd_bo_map(rsc->bo);
	if (!buf)
		goto fail;

	offset = slice->offset +
		box->y / util_format_get_blockheight(format) * ptrans->stride +
		box->x / util_format_get_blockwidth(format) * rsc->cpp +
		fd_resource_layer_offset(rsc, slice, box->z);

	if (prsc->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT ||
		prsc->format == PIPE_FORMAT_X32_S8X24_UINT) {
		assert(trans->base.box.depth == 1);

		trans->base.stride = trans->base.box.width * rsc->cpp * 2;
		trans->staging = malloc(trans->base.stride * trans->base.box.height);
		if (!trans->staging)
			goto fail;

		/* if we're not discarding the whole range (or resource), we must copy
		 * the real data in.
		 */
		if (!(usage & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE |
					   PIPE_TRANSFER_DISCARD_RANGE))) {
			struct fd_resource_slice *sslice =
				fd_resource_slice(rsc->stencil, level);
			void *sbuf = fd_bo_map(rsc->stencil->bo);
			if (!sbuf)
				goto fail;

			float *depth = (float *)(buf + slice->offset +
				fd_resource_layer_offset(rsc, slice, box->z) +
				box->y * slice->pitch * 4 + box->x * 4);
			uint8_t *stencil = sbuf + sslice->offset +
				fd_resource_layer_offset(rsc->stencil, sslice, box->z) +
				box->y * sslice->pitch + box->x;

			if (format != PIPE_FORMAT_X32_S8X24_UINT)
				util_format_z32_float_s8x24_uint_pack_z_float(
						trans->staging, trans->base.stride,
						depth, slice->pitch * 4,
						box->width, box->height);

			util_format_z32_float_s8x24_uint_pack_s_8uint(
					trans->staging, trans->base.stride,
					stencil, sslice->pitch,
					box->width, box->height);
		}

		buf = trans->staging;
		offset = 0;
	} else if (rsc->internal_format != format &&
			   util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_RGTC) {
		assert(trans->base.box.depth == 1);

		trans->base.stride = util_format_get_stride(
				format, trans->base.box.width);
		trans->staging = malloc(
				util_format_get_2d_size(format, trans->base.stride,
										trans->base.box.height));
		if (!trans->staging)
			goto fail;

		/* if we're not discarding the whole range (or resource), we must copy
		 * the real data in.
		 */
		if (!(usage & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE |
					   PIPE_TRANSFER_DISCARD_RANGE))) {
			uint8_t *rgba8 = (uint8_t *)buf + slice->offset +
				fd_resource_layer_offset(rsc, slice, box->z) +
				box->y * slice->pitch * rsc->cpp + box->x * rsc->cpp;

			switch (format) {
			case PIPE_FORMAT_RGTC1_UNORM:
			case PIPE_FORMAT_RGTC1_SNORM:
			case PIPE_FORMAT_LATC1_UNORM:
			case PIPE_FORMAT_LATC1_SNORM:
				util_format_rgtc1_unorm_pack_rgba_8unorm(
					trans->staging, trans->base.stride,
					rgba8, slice->pitch * rsc->cpp,
					box->width, box->height);
				break;
			case PIPE_FORMAT_RGTC2_UNORM:
			case PIPE_FORMAT_RGTC2_SNORM:
			case PIPE_FORMAT_LATC2_UNORM:
			case PIPE_FORMAT_LATC2_SNORM:
				util_format_rgtc2_unorm_pack_rgba_8unorm(
					trans->staging, trans->base.stride,
					rgba8, slice->pitch * rsc->cpp,
					box->width, box->height);
				break;
			default:
				assert(!"Unexpected format");
				break;
			}
		}

		buf = trans->staging;
		offset = 0;
	}

	*pptrans = ptrans;

	return buf + offset;

fail:
	fd_resource_transfer_unmap(pctx, ptrans);
	return NULL;
}