Example #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;
}
Example #2
0
static void* si_texture_transfer_map(struct pipe_context *ctx,
				     struct pipe_transfer* transfer)
{
	struct r600_context *rctx = (struct r600_context *)ctx;
	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
	struct radeon_winsys_cs_handle *buf;
	enum pipe_format format = transfer->resource->format;
	unsigned offset = 0;
	char *map;

	if (rtransfer->staging_texture) {
		buf = si_resource(rtransfer->staging_texture)->cs_buf;
	} else {
		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;

		if (rtex->flushed_depth_texture)
			buf = rtex->flushed_depth_texture->resource.cs_buf;
		else
			buf = si_resource(transfer->resource)->cs_buf;

		offset = rtransfer->offset +
			transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
			transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
	}

	if (!(map = rctx->ws->buffer_map(buf, rctx->cs, transfer->usage))) {
		return NULL;
	}

	return map + offset;
}
Example #3
0
void* r300_texture_transfer_map(struct pipe_context *ctx,
				struct pipe_transfer *transfer)
{
    struct r300_context *r300 = r300_context(ctx);
    struct radeon_winsys *rws = (struct radeon_winsys *)ctx->winsys;
    struct r300_transfer *r300transfer = r300_transfer(transfer);
    struct r300_resource *tex = r300_resource(transfer->resource);
    char *map;
    enum pipe_format format = tex->b.b.b.format;

    if (r300transfer->linear_texture) {
        /* The detiled texture is of the same size as the region being mapped
         * (no offset needed). */
        return rws->buffer_map(r300transfer->linear_texture->buf,
                               r300->cs,
                               transfer->usage);
    } else {
        /* Tiling is disabled. */
        map = rws->buffer_map(tex->buf, r300->cs,
                              transfer->usage);

        if (!map) {
            return NULL;
        }

        return map + r300_transfer(transfer)->offset +
            transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
            transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
    }
}
Example #4
0
static void
i915_clear_render_target_blitter(struct pipe_context *pipe,
                                 struct pipe_surface *dst,
                                 const union pipe_color_union *color,
                                 unsigned dstx, unsigned dsty,
                                 unsigned width, unsigned height)
{
   struct i915_texture *tex = i915_texture(dst->texture);
   struct pipe_resource *pt = &tex->b.b;
   union util_color uc;
   unsigned offset = i915_texture_offset(tex, dst->u.tex.level, dst->u.tex.first_layer);

   assert(util_format_get_blockwidth(pt->format) == 1);
   assert(util_format_get_blockheight(pt->format) == 1);

   util_pack_color(color->f, dst->format, &uc);
   i915_fill_blit( i915_context(pipe),
                   util_format_get_blocksize(pt->format),
                   XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB,
                   (unsigned short) tex->stride,
                   tex->buffer, offset,
                   (short) dstx, (short) dsty,
                   (short) width, (short) height,
                   uc.ui );
}
Example #5
0
static void *
brw_texture_transfer_map(struct pipe_context *pipe,
                 struct pipe_transfer *transfer)
{
   struct pipe_resource *resource = transfer->resource;
   struct brw_texture *tex = brw_texture(transfer->resource);
   struct brw_winsys_screen *sws = brw_screen(pipe->screen)->sws;
   struct pipe_box *box = &transfer->box;
   enum pipe_format format = resource->format;
   unsigned usage = transfer->usage;
   unsigned offset;
   char *map;

   if (resource->target != PIPE_TEXTURE_3D &&
       resource->target != PIPE_TEXTURE_CUBE)
      assert(box->z == 0);
   offset = tex->image_offset[transfer->level][box->z];

   map = sws->bo_map(tex->bo, 
                     BRW_DATA_OTHER,
                     0,
                     tex->bo->size,
                     (usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE,
                     (usage & 0) ? TRUE : FALSE,
                     (usage & 0) ? TRUE : FALSE);

   if (!map)
      return NULL;

   return map + offset +
      box->y / util_format_get_blockheight(format) * transfer->stride +
      box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
}
Example #6
0
static int amdgpu_surface_init(struct radeon_winsys *rws,
                               const struct pipe_resource *tex,
                               unsigned flags, unsigned bpe,
                               enum radeon_surf_mode mode,
                               struct radeon_surf *surf)
{
   struct amdgpu_winsys *ws = (struct amdgpu_winsys*)rws;
   int r;

   r = amdgpu_surface_sanity(tex);
   if (r)
      return r;

   surf->blk_w = util_format_get_blockwidth(tex->format);
   surf->blk_h = util_format_get_blockheight(tex->format);
   surf->bpe = bpe;
   surf->flags = flags;

   struct ac_surf_config config;

   config.info.width = tex->width0;
   config.info.height = tex->height0;
   config.info.depth = tex->depth0;
   config.info.array_size = tex->array_size;
   config.info.samples = tex->nr_samples;
   config.info.levels = tex->last_level + 1;
   config.is_3d = !!(tex->target == PIPE_TEXTURE_3D);
   config.is_cube = !!(tex->target == PIPE_TEXTURE_CUBE);

   return ac_compute_surface(ws->addrlib, &ws->info, &config, mode, surf);
}
Example #7
0
static void
tex_layout_init_format(struct tex_layout *layout)
{
   const struct pipe_resource *templ = layout->templ;
   enum pipe_format format;

   switch (templ->format) {
   case PIPE_FORMAT_ETC1_RGB8:
      format = PIPE_FORMAT_R8G8B8X8_UNORM;
      break;
   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
      if (layout->separate_stencil)
         format = PIPE_FORMAT_Z24X8_UNORM;
      else
         format = templ->format;
      break;
   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
      if (layout->separate_stencil)
         format = PIPE_FORMAT_Z32_FLOAT;
      else
         format = templ->format;
      break;
   default:
      format = templ->format;
      break;
   }

   layout->format = format;

   layout->block_width = util_format_get_blockwidth(format);
   layout->block_height = util_format_get_blockheight(format);
   layout->block_size = util_format_get_blocksize(format);
   layout->compressed = util_format_is_compressed(format);
}
Example #8
0
/* 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.
 */
static inline size_t etna_compute_offset(enum pipe_format format, const struct pipe_box *box,
        size_t stride, size_t layer_stride)
{
    return box->z * layer_stride +
           box->y / util_format_get_blockheight(format) * stride +
           box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
}
Example #9
0
/* Assumes all values are within bounds -- no checking at this level -
 * do it higher up if required.
 */
static void
i915_surface_copy_blitter(struct pipe_context *pipe,
                          struct pipe_resource *dst, unsigned dst_level,
                          unsigned dstx, unsigned dsty, unsigned dstz,
                          struct pipe_resource *src, unsigned src_level,
                          const struct pipe_box *src_box)
{
   struct i915_texture *dst_tex = i915_texture(dst);
   struct i915_texture *src_tex = i915_texture(src);
   struct pipe_resource *dpt = &dst_tex->b.b;
   struct pipe_resource *spt = &src_tex->b.b;
   unsigned dst_offset, src_offset;  /* in bytes */

   /* Fallback for buffers. */
   if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
      util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
                                src, src_level, src_box);
      return;
   }

   /* XXX cannot copy 3d regions at this time */
   assert(src_box->depth == 1);
   if (dst->target != PIPE_TEXTURE_CUBE &&
       dst->target != PIPE_TEXTURE_3D)
      assert(dstz == 0);
   dst_offset = i915_texture_offset(dst_tex, dst_level, dstz);

   if (src->target != PIPE_TEXTURE_CUBE &&
       src->target != PIPE_TEXTURE_3D)
      assert(src_box->z == 0);
   src_offset = i915_texture_offset(src_tex, src_level, src_box->z);

   assert( util_format_get_blocksize(dpt->format) == util_format_get_blocksize(spt->format) );
   assert( util_format_get_blockwidth(dpt->format) == util_format_get_blockwidth(spt->format) );
   assert( util_format_get_blockheight(dpt->format) == util_format_get_blockheight(spt->format) );
   assert( util_format_get_blockwidth(dpt->format) == 1 );
   assert( util_format_get_blockheight(dpt->format) == 1 );

   i915_copy_blit( i915_context(pipe),
                   util_format_get_blocksize(dpt->format),
                   (unsigned short) src_tex->stride, src_tex->buffer, src_offset,
                   (unsigned short) dst_tex->stride, dst_tex->buffer, dst_offset,
                   (short) src_box->x, (short) src_box->y, (short) dstx, (short) dsty,
                   (short) src_box->width, (short) src_box->height );
}
Example #10
0
static struct pipe_resource *
llvmpipe_resource_create(struct pipe_screen *_screen,
                         const struct pipe_resource *templat)
{
   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
   struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
   if (!lpr)
      return NULL;

   lpr->base = *templat;
   pipe_reference_init(&lpr->base.reference, 1);
   lpr->base.screen = &screen->base;

   /* assert(lpr->base.bind); */

   if (resource_is_texture(&lpr->base)) {
      if (lpr->base.bind & PIPE_BIND_DISPLAY_TARGET) {
         /* displayable surface */
         if (!llvmpipe_displaytarget_layout(screen, lpr))
            goto fail;
         assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
      }
      else {
         /* texture map */
         if (!llvmpipe_texture_layout(screen, lpr))
            goto fail;
         assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
      }
      assert(lpr->layout[0]);
   }
   else {
      /* other data (vertex buffer, const buffer, etc) */
      const enum pipe_format format = templat->format;
      const uint w = templat->width0 / util_format_get_blockheight(format);
      /* XXX buffers should only have one dimension, those values should be 1 */
      const uint h = templat->height0 / util_format_get_blockwidth(format);
      const uint d = templat->depth0;
      const uint bpp = util_format_get_blocksize(format);
      const uint bytes = w * h * d * bpp;
      lpr->data = align_malloc(bytes, 16);
      if (!lpr->data)
         goto fail;
      memset(lpr->data, 0, bytes);
   }

   lpr->id = id_counter++;

#ifdef DEBUG
   insert_at_tail(&resource_list, lpr);
#endif

   return &lpr->base;

 fail:
   FREE(lpr);
   return NULL;
}
Example #11
0
/**
 * Helper function to decompress an image.  The result is a 32-bpp RGBA
 * image with stride==width.
 */
static void
decompress_image(enum pipe_format format, int datatype,
                 const uint8_t *src, void *dst,
                 unsigned width, unsigned height, unsigned src_stride)
{
   const struct util_format_description *desc = util_format_description(format);
   const uint bw = util_format_get_blockwidth(format);
   const uint bh = util_format_get_blockheight(format);
   uint dst_stride = 4 * MAX2(width, bw);

   if (datatype == GL_FLOAT) {
      desc->unpack_rgba_float((float *)dst, dst_stride * sizeof(GLfloat), src, src_stride, width, height);
      if (width < bw || height < bh) {
	 float *dst_p = (float *)dst;
	 /* We're decompressing an image smaller than the compression
	  * block size.  We don't want garbage pixel values in the region
	  * outside (width x height) so replicate pixels from the (width
	  * x height) region to fill out the (bw x bh) block size.
	  */
	 uint x, y;
	 for (y = 0; y < bh; y++) {
	    for (x = 0; x < bw; x++) {
	       if (x >= width || y >= height) {
		  uint p = (y * bw + x) * 4;
		  dst_p[p + 0] = dst_p[0];
		  dst_p[p + 1] = dst_p[1];
		  dst_p[p + 2] = dst_p[2];
		  dst_p[p + 3] = dst_p[3];
	       }
	    }
	 }
      }
   } else {
      desc->unpack_rgba_8unorm((uint8_t *)dst, dst_stride, src, src_stride, width, height);
      if (width < bw || height < bh) {
	 uint8_t *dst_p = (uint8_t *)dst;
	 /* We're decompressing an image smaller than the compression
	  * block size.  We don't want garbage pixel values in the region
	  * outside (width x height) so replicate pixels from the (width
	  * x height) region to fill out the (bw x bh) block size.
	  */
	 uint x, y;
	 for (y = 0; y < bh; y++) {
	    for (x = 0; x < bw; x++) {
	       if (x >= width || y >= height) {
		  uint p = (y * bw + x) * 4;
		  dst_p[p + 0] = dst_p[0];
		  dst_p[p + 1] = dst_p[1];
		  dst_p[p + 2] = dst_p[2];
		  dst_p[p + 3] = dst_p[3];
	       }
	    }
	 }
      }
   }
}
static unsigned r600_texture_get_offset(struct r600_texture *rtex, unsigned level,
					const struct pipe_box *box)
{
	enum pipe_format format = rtex->resource.b.b.format;

	return rtex->surface.level[level].offset +
	       box->z * rtex->surface.level[level].slice_size +
	       box->y / util_format_get_blockheight(format) * rtex->surface.level[level].pitch_bytes +
	       box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
}
Example #13
0
static void
layout_init_size_and_format(struct ilo_layout *layout,
                            struct ilo_layout_params *params)
{
   const struct pipe_resource *templ = params->templ;
   enum pipe_format format = templ->format;
   bool require_separate_stencil;

   layout->width0 = templ->width0;
   layout->height0 = templ->height0;

   /*
    * From the Sandy Bridge PRM, volume 2 part 1, page 317:
    *
    *     "This field (Separate Stencil Buffer Enable) must be set to the same
    *      value (enabled or disabled) as Hierarchical Depth Buffer Enable."
    *
    * GEN7+ requires separate stencil buffers.
    */
   if (templ->bind & PIPE_BIND_DEPTH_STENCIL) {
      if (ilo_dev_gen(params->dev) >= ILO_GEN(7))
         require_separate_stencil = true;
      else
         require_separate_stencil = (layout->aux == ILO_LAYOUT_AUX_HIZ);
   }

   switch (format) {
   case PIPE_FORMAT_ETC1_RGB8:
      format = PIPE_FORMAT_R8G8B8X8_UNORM;
      break;
   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
      if (require_separate_stencil) {
         format = PIPE_FORMAT_Z24X8_UNORM;
         layout->separate_stencil = true;
      }
      break;
   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
      if (require_separate_stencil) {
         format = PIPE_FORMAT_Z32_FLOAT;
         layout->separate_stencil = true;
      }
      break;
   default:
      break;
   }

   layout->format = format;
   layout->block_width = util_format_get_blockwidth(format);
   layout->block_height = util_format_get_blockheight(format);
   layout->block_size = util_format_get_blocksize(format);

   params->compressed = util_format_is_compressed(format);
}
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;
}
Example #15
0
static INLINE void
svga_transfer_dma_band(struct svga_context *svga,
                       struct svga_transfer *st,
                       SVGA3dTransferType transfer,
                       unsigned y, unsigned h, unsigned srcy,
                       SVGA3dSurfaceDMAFlags flags)
{
    struct svga_texture *texture = svga_texture(st->base.resource);
    SVGA3dCopyBox box;
    enum pipe_error ret;

    box.x = st->base.box.x;
    box.y = y;
    box.z = st->base.box.z;
    box.w = st->base.box.width;
    box.h = h;
    box.d = 1;
    box.srcx = 0;
    box.srcy = srcy;
    box.srcz = 0;

    if (st->base.resource->target == PIPE_TEXTURE_CUBE) {
        st->face = st->base.box.z;
        box.z = 0;
    }
    else
        st->face = 0;

    SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n",
             transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",
             texture->handle,
             st->face,
             st->base.box.x,
             y,
             box.z,
             st->base.box.x + st->base.box.width,
             y + h,
             box.z + 1,
             util_format_get_blocksize(texture->b.b.format) * 8 /
             (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format)));

    ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
    if(ret != PIPE_OK) {
        svga_context_flush(svga, NULL);
        ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
        assert(ret == PIPE_OK);
    }
}
static void
svga_transfer_dma_band(struct svga_context *svga,
                       struct svga_transfer *st,
                       SVGA3dTransferType transfer,
                       unsigned x, unsigned y, unsigned z,
                       unsigned w, unsigned h, unsigned d,
                       unsigned srcx, unsigned srcy, unsigned srcz,
                       SVGA3dSurfaceDMAFlags flags)
{
   struct svga_texture *texture = svga_texture(st->base.resource);
   SVGA3dCopyBox box;
   enum pipe_error ret;

   assert(!st->use_direct_map);

   box.x = x;
   box.y = y;
   box.z = z;
   box.w = w;
   box.h = h;
   box.d = d;
   box.srcx = srcx;
   box.srcy = srcy;
   box.srcz = srcz;

   SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - "
            "(%u, %u, %u), %ubpp\n",
            transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",
            texture->handle,
            st->slice,
            x,
            y,
            z,
            x + w,
            y + h,
            z + 1,
            util_format_get_blocksize(texture->b.b.format) * 8 /
            (util_format_get_blockwidth(texture->b.b.format)
             * util_format_get_blockheight(texture->b.b.format)));

   ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
   if (ret != PIPE_OK) {
      svga_context_flush(svga, NULL);
      ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
      assert(ret == PIPE_OK);
   }
}
Example #17
0
/**
 * Copy 2D rect from one place to another.
 * Position and sizes are in pixels.
 * src_stride may be negative to do vertical flip of pixels from source.
 */
void
util_copy_rect(ubyte * dst,
               enum pipe_format format,
               unsigned dst_stride,
               unsigned dst_x,
               unsigned dst_y,
               unsigned width,
               unsigned height,
               const ubyte * src,
               int src_stride,
               unsigned src_x,
               unsigned src_y)
{
   unsigned i;
   int src_stride_pos = src_stride < 0 ? -src_stride : src_stride;
   int blocksize = util_format_get_blocksize(format);
   int blockwidth = util_format_get_blockwidth(format);
   int blockheight = util_format_get_blockheight(format);

   assert(blocksize > 0);
   assert(blockwidth > 0);
   assert(blockheight > 0);

   dst_x /= blockwidth;
   dst_y /= blockheight;
   width = (width + blockwidth - 1)/blockwidth;
   height = (height + blockheight - 1)/blockheight;
   src_x /= blockwidth;
   src_y /= blockheight;

   dst += dst_x * blocksize;
   src += src_x * blocksize;
   dst += dst_y * dst_stride;
   src += src_y * src_stride_pos;
   width *= blocksize;

   if (width == dst_stride && width == src_stride)
      memcpy(dst, src, height * width);
   else {
      for (i = 0; i < height; i++) {
         memcpy(dst, src, width);
         dst += dst_stride;
         src += src_stride;
      }
   }
}
Example #18
0
static void* r300_transfer_map(struct pipe_screen* screen,
                              struct pipe_transfer* transfer)
{
    struct r300_texture* tex = (struct r300_texture*)transfer->texture;
    char* map;
    enum pipe_format format = tex->tex.format;

    map = pipe_buffer_map(screen, tex->buffer,
                          pipe_transfer_buffer_flags(transfer));

    if (!map) {
        return NULL;
    }

    return map + r300_transfer(transfer)->offset +
        transfer->y / util_format_get_blockheight(format) * transfer->stride +
        transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
}
Example #19
0
static void virgl_vtest_flush_frontbuffer(struct virgl_winsys *vws,
                                          struct virgl_hw_res *res,
                                          unsigned level, unsigned layer,
                                          void *winsys_drawable_handle,
                                          struct pipe_box *sub_box)
{
   struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
   struct pipe_box box;
   void *map;
   uint32_t size;
   uint32_t offset = 0, valid_stride;
   if (!res->dt)
      return;

   memset(&box, 0, sizeof(box));

   if (sub_box) {
      box = *sub_box;
      offset = box.y / util_format_get_blockheight(res->format) * res->stride +
               box.x / util_format_get_blockwidth(res->format) * util_format_get_blocksize(res->format);
   } else {
      box.z = layer;
      box.width = res->width;
      box.height = res->height;
      box.depth = 1;
   }

   size = vtest_get_transfer_size(res, &box, res->stride, 0, level, &valid_stride);

   virgl_vtest_busy_wait(vtws, res->res_handle, VCMD_BUSY_WAIT_FLAG_WAIT);
   map = vtws->sws->displaytarget_map(vtws->sws, res->dt, 0);

   /* execute a transfer */
   virgl_vtest_send_transfer_cmd(vtws, VCMD_TRANSFER_GET, res->res_handle,
                                 level, res->stride, 0, &box, size);
   virgl_vtest_recv_transfer_get_data(vtws, map + offset, size, valid_stride,
                                      &box, res->format);
   vtws->sws->displaytarget_unmap(vtws->sws, res->dt);

   vtws->sws->displaytarget_display(vtws->sws, res->dt, winsys_drawable_handle,
                                    sub_box);
}
Example #20
0
/**
 * The texutre is for transfer only.  We can define our own layout to save
 * space.
 */
static void
layout_init_for_transfer(struct ilo_layout *layout,
                         const struct ilo_dev_info *dev,
                         const struct pipe_resource *templ)
{
   const unsigned num_layers = (templ->target == PIPE_TEXTURE_3D) ?
      templ->depth0 : templ->array_size;
   unsigned layer_width, layer_height;

   assert(templ->last_level == 0);
   assert(templ->nr_samples <= 1);

   layout->aux = ILO_LAYOUT_AUX_NONE;
   layout->width0 = templ->width0;
   layout->height0 = templ->height0;
   layout->format = templ->format;
   layout->block_width = util_format_get_blockwidth(templ->format);
   layout->block_height = util_format_get_blockheight(templ->format);
   layout->block_size = util_format_get_blocksize(templ->format);
   layout->walk = ILO_LAYOUT_WALK_LOD;

   layout->valid_tilings = LAYOUT_TILING_NONE;
   layout->tiling = INTEL_TILING_NONE;

   layout->align_i = layout->block_width;
   layout->align_j = layout->block_height;

   assert(util_is_power_of_two(layout->block_width) &&
          util_is_power_of_two(layout->block_height));

   /* use packed layout */
   layer_width = align(templ->width0, layout->align_i);
   layer_height = align(templ->height0, layout->align_j);

   layout->lods[0].slice_width = layer_width;
   layout->lods[0].slice_height = layer_height;

   layout->bo_stride = (layer_width / layout->block_width) * layout->block_size;
   layout->bo_stride = align(layout->bo_stride, 64);

   layout->bo_height = (layer_height / layout->block_height) * num_layers;
}
void* r600_texture_transfer_map(struct pipe_context *ctx,
				struct pipe_transfer* transfer)
{
	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
	struct radeon_bo *bo;
	enum pipe_format format = transfer->resource->format;
	struct r600_screen *rscreen = r600_screen(ctx->screen);
	struct r600_resource_texture *rtex;
	unsigned long offset = 0;
	char *map;
	int r;

	r600_flush(ctx, 0, NULL);
	if (rtransfer->linear_texture) {
		bo = ((struct r600_resource *)rtransfer->linear_texture)->bo;
	} else {
		rtex = (struct r600_resource_texture*)transfer->resource;
		if (rtex->depth) {
			r = r600_texture_from_depth(ctx, rtex, transfer->sr.level);
			if (r) {
				return NULL;
			}
			r600_flush(ctx, 0, NULL);
			bo = rtex->uncompressed;
		} else {
			bo = ((struct r600_resource *)transfer->resource)->bo;
		}
		offset = rtransfer->offset +
			transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
			transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
	}
	if (radeon_bo_map(rscreen->rw, bo)) {
		return NULL;
	}
	radeon_bo_wait(rscreen->rw, bo);

	map = bo->data;
	return map + offset;
}
Example #22
0
static void
i915_clear_depth_stencil_blitter(struct pipe_context *pipe,
                                 struct pipe_surface *dst,
                                 unsigned clear_flags,
                                 double depth,
                                 unsigned stencil,
                                 unsigned dstx, unsigned dsty,
                                 unsigned width, unsigned height,
                                 bool render_condition_enabled)
{
   struct i915_texture *tex = i915_texture(dst->texture);
   struct pipe_resource *pt = &tex->b.b;
   unsigned packedds;
   unsigned mask = 0;
   unsigned offset = i915_texture_offset(tex, dst->u.tex.level, dst->u.tex.first_layer);

   assert(util_format_get_blockwidth(pt->format) == 1);
   assert(util_format_get_blockheight(pt->format) == 1);

   packedds = util_pack_z_stencil(dst->format, depth, stencil);

   if (clear_flags & PIPE_CLEAR_DEPTH)
      mask |= XY_COLOR_BLT_WRITE_RGB;
   /* XXX presumably this does read-modify-write
      (otherwise this won't work anyway). Hence will only want to
      do it if really have stencil and it isn't cleared */
   if ((clear_flags & PIPE_CLEAR_STENCIL) ||
       (dst->format != PIPE_FORMAT_Z24_UNORM_S8_UINT))
      mask |= XY_COLOR_BLT_WRITE_ALPHA;

   i915_fill_blit( i915_context(pipe),
                   util_format_get_blocksize(pt->format),
                   mask,
                   (unsigned short) tex->stride,
                   tex->buffer, offset,
                   (short) dstx, (short) dsty,
                   (short) width, (short) height,
                   packedds );
}
Example #23
0
/**
 * Fallback function for pipe->resource_copy_region().
 * Note: (X,Y)=(0,0) is always the upper-left corner.
 */
void
util_resource_copy_region(struct pipe_context *pipe,
                          struct pipe_resource *dst,
                          unsigned dst_level,
                          unsigned dst_x, unsigned dst_y, unsigned dst_z,
                          struct pipe_resource *src,
                          unsigned src_level,
                          const struct pipe_box *src_box)
{
   struct pipe_transfer *src_trans, *dst_trans;
   uint8_t *dst_map;
   const uint8_t *src_map;
   enum pipe_format src_format, dst_format;
   struct pipe_box dst_box;
   int z;

   assert(src && dst);
   if (!src || !dst)
      return;

   assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) ||
          (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER));

   src_format = src->format;
   dst_format = dst->format;

   assert(util_format_get_blocksize(dst_format) == util_format_get_blocksize(src_format));
   assert(util_format_get_blockwidth(dst_format) == util_format_get_blockwidth(src_format));
   assert(util_format_get_blockheight(dst_format) == util_format_get_blockheight(src_format));

   src_map = pipe->transfer_map(pipe,
                                src,
                                src_level,
                                PIPE_TRANSFER_READ,
                                src_box, &src_trans);
   assert(src_map);
   if (!src_map) {
      goto no_src_map;
   }

   dst_box.x = dst_x;
   dst_box.y = dst_y;
   dst_box.z = dst_z;
   dst_box.width  = src_box->width;
   dst_box.height = src_box->height;
   dst_box.depth  = src_box->depth;

   dst_map = pipe->transfer_map(pipe,
                                dst,
                                dst_level,
                                PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
                                &dst_box, &dst_trans);
   assert(dst_map);
   if (!dst_map) {
      goto no_dst_map;
   }

   if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
      assert(src_box->height == 1);
      assert(src_box->depth == 1);
      memcpy(dst_map, src_map, src_box->width);
   } else {
      for (z = 0; z < src_box->depth; ++z) {
         util_copy_rect(dst_map,
                        dst_format,
                        dst_trans->stride,
                        0, 0,
                        src_box->width, src_box->height,
                        src_map,
                        src_trans->stride,
                        0, 0);

         dst_map += dst_trans->layer_stride;
         src_map += src_trans->layer_stride;
      }
   }

   pipe->transfer_unmap(pipe, dst_trans);
no_dst_map:
   pipe->transfer_unmap(pipe, src_trans);
no_src_map:
   ;
}
Example #24
0
static void
svga_transfer_dma(struct svga_context *svga,
                  struct svga_transfer *st,
                  SVGA3dTransferType transfer,
                  SVGA3dSurfaceDMAFlags flags)
{
   struct svga_texture *texture = svga_texture(st->base.resource);
   struct svga_screen *screen = svga_screen(texture->b.b.screen);
   struct svga_winsys_screen *sws = screen->sws;
   struct pipe_fence_handle *fence = NULL;

   assert(!st->use_direct_map);

   if (transfer == SVGA3D_READ_HOST_VRAM) {
      SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__);
   }

   /* Ensure any pending operations on host surfaces are queued on the command
    * buffer first.
    */
   svga_surfaces_flush( svga );

   if (!st->swbuf) {
      /* Do the DMA transfer in a single go */
      svga_transfer_dma_band(svga, st, transfer,
                             st->base.box.y, st->base.box.height, 0,
                             flags);

      if (transfer == SVGA3D_READ_HOST_VRAM) {
         svga_context_flush(svga, &fence);
         sws->fence_finish(sws, fence, 0);
         sws->fence_reference(sws, &fence, NULL);
      }
   }
   else {
      int y, h, srcy;
      unsigned blockheight =
         util_format_get_blockheight(st->base.resource->format);

      h = st->hw_nblocksy * blockheight;
      srcy = 0;

      for (y = 0; y < st->base.box.height; y += h) {
         unsigned offset, length;
         void *hw, *sw;

         if (y + h > st->base.box.height)
            h = st->base.box.height - y;

         /* Transfer band must be aligned to pixel block boundaries */
         assert(y % blockheight == 0);
         assert(h % blockheight == 0);

         offset = y * st->base.stride / blockheight;
         length = h * st->base.stride / blockheight;

         sw = (uint8_t *) st->swbuf + offset;

         if (transfer == SVGA3D_WRITE_HOST_VRAM) {
            unsigned usage = PIPE_TRANSFER_WRITE;

            /* Wait for the previous DMAs to complete */
            /* TODO: keep one DMA (at half the size) in the background */
            if (y) {
               svga_context_flush(svga, NULL);
               usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
            }

            hw = sws->buffer_map(sws, st->hwbuf, usage);
            assert(hw);
            if (hw) {
               memcpy(hw, sw, length);
               sws->buffer_unmap(sws, st->hwbuf);
            }
         }

         svga_transfer_dma_band(svga, st, transfer, y, h, srcy, flags);

         /*
          * Prevent the texture contents to be discarded on the next band
          * upload.
          */
         flags.discard = FALSE;

         if (transfer == SVGA3D_READ_HOST_VRAM) {
            svga_context_flush(svga, &fence);
            sws->fence_finish(sws, fence, 0);

            hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ);
            assert(hw);
            if (hw) {
               memcpy(sw, hw, length);
               sws->buffer_unmap(sws, st->hwbuf);
            }
         }
      }
   }
}
Example #25
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;
}
static int r600_init_surface(struct r600_common_screen *rscreen,
			     struct radeon_surf *surface,
			     const struct pipe_resource *ptex,
			     unsigned array_mode,
			     bool is_flushed_depth)
{
	const struct util_format_description *desc =
		util_format_description(ptex->format);
	bool is_depth, is_stencil;

	is_depth = util_format_has_depth(desc);
	is_stencil = util_format_has_stencil(desc);

	surface->npix_x = ptex->width0;
	surface->npix_y = ptex->height0;
	surface->npix_z = ptex->depth0;
	surface->blk_w = util_format_get_blockwidth(ptex->format);
	surface->blk_h = util_format_get_blockheight(ptex->format);
	surface->blk_d = 1;
	surface->array_size = 1;
	surface->last_level = ptex->last_level;

	if (rscreen->chip_class >= EVERGREEN && !is_flushed_depth &&
	    ptex->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
		surface->bpe = 4; /* stencil is allocated separately on evergreen */
	} else {
		surface->bpe = util_format_get_blocksize(ptex->format);
		/* align byte per element on dword */
		if (surface->bpe == 3) {
			surface->bpe = 4;
		}
	}

	surface->nsamples = ptex->nr_samples ? ptex->nr_samples : 1;
	surface->flags = RADEON_SURF_SET(array_mode, MODE);

	switch (ptex->target) {
	case PIPE_TEXTURE_1D:
		surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE);
		break;
	case PIPE_TEXTURE_RECT:
	case PIPE_TEXTURE_2D:
		surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
		break;
	case PIPE_TEXTURE_3D:
		surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE);
		break;
	case PIPE_TEXTURE_1D_ARRAY:
		surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE);
		surface->array_size = ptex->array_size;
		break;
	case PIPE_TEXTURE_2D_ARRAY:
	case PIPE_TEXTURE_CUBE_ARRAY: /* cube array layout like 2d array */
		surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE);
		surface->array_size = ptex->array_size;
		break;
	case PIPE_TEXTURE_CUBE:
		surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE);
		break;
	case PIPE_BUFFER:
	default:
		return -EINVAL;
	}
	if (ptex->bind & PIPE_BIND_SCANOUT) {
		surface->flags |= RADEON_SURF_SCANOUT;
	}

	if (!is_flushed_depth && is_depth) {
		surface->flags |= RADEON_SURF_ZBUFFER;

		if (is_stencil) {
			surface->flags |= RADEON_SURF_SBUFFER |
					  RADEON_SURF_HAS_SBUFFER_MIPTREE;
		}
	}
	if (rscreen->chip_class >= SI) {
		surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
	}
	return 0;
}
Example #27
0
/**
 * Geta pipe_transfer object which is used for moving data in/out of
 * a resource object.
 * \param pipe  rendering context
 * \param resource  the resource to transfer in/out of
 * \param level  which mipmap level
 * \param usage  bitmask of PIPE_TRANSFER_x flags
 * \param box  the 1D/2D/3D region of interest
 */
static struct pipe_transfer *
softpipe_get_transfer(struct pipe_context *pipe,
                      struct pipe_resource *resource,
                      unsigned level,
                      unsigned usage,
                      const struct pipe_box *box)
{
   struct softpipe_resource *spr = softpipe_resource(resource);
   struct softpipe_transfer *spt;

   assert(resource);
   assert(level <= resource->last_level);

   /* make sure the requested region is in the image bounds */
   assert(box->x + box->width <= u_minify(resource->width0, level));
   if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
      assert(box->y + box->height <= resource->array_size);
   }
   else {
      assert(box->y + box->height <= u_minify(resource->height0, level));
      if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
         assert(box->z + box->depth <= resource->array_size);
      }
      else if (resource->target == PIPE_TEXTURE_CUBE) {
         assert(box->z < 6);
      }
      else {
         assert(box->z + box->depth <= (u_minify(resource->depth0, level)));
      }
   }

   /*
    * Transfers, like other pipe operations, must happen in order, so flush the
    * context if necessary.
    */
   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
      boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
      boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
      if (!softpipe_flush_resource(pipe, resource,
                                   level, box->depth > 1 ? -1 : box->z,
                                   0, /* flush_flags */
                                   read_only,
                                   TRUE, /* cpu_access */
                                   do_not_block)) {
         /*
          * It would have blocked, but state tracker requested no to.
          */
         assert(do_not_block);
         return NULL;
      }
   }

   spt = CALLOC_STRUCT(softpipe_transfer);
   if (spt) {
      struct pipe_transfer *pt = &spt->base;
      enum pipe_format format = resource->format;
      const unsigned hgt = u_minify(spr->base.height0, level);
      const unsigned nblocksy = util_format_get_nblocksy(format, hgt);

      pipe_resource_reference(&pt->resource, resource);
      pt->level = level;
      pt->usage = usage;
      pt->box = *box;
      pt->stride = spr->stride[level];
      pt->layer_stride = pt->stride * nblocksy;

      spt->offset = sp_get_tex_image_offset(spr, level, box->z);
 
      spt->offset += 
         box->y / util_format_get_blockheight(format) * spt->base.stride +
         box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);

      return pt;
   }
   return NULL;
}
Example #28
0
/**
 * Fallback function for pipe->resource_copy_region().
 * We support copying between different formats (including compressed/
 * uncompressed) if the bytes per block or pixel matches.  If copying
 * compressed -> uncompressed, the dst region is reduced by the block
 * width, height.  If copying uncompressed -> compressed, the dest region
 * is expanded by the block width, height.  See GL_ARB_copy_image.
 * Note: (X,Y)=(0,0) is always the upper-left corner.
 */
void
util_resource_copy_region(struct pipe_context *pipe,
                          struct pipe_resource *dst,
                          unsigned dst_level,
                          unsigned dst_x, unsigned dst_y, unsigned dst_z,
                          struct pipe_resource *src,
                          unsigned src_level,
                          const struct pipe_box *src_box_in)
{
   struct pipe_transfer *src_trans, *dst_trans;
   uint8_t *dst_map;
   const uint8_t *src_map;
   MAYBE_UNUSED enum pipe_format src_format;
   enum pipe_format dst_format;
   struct pipe_box src_box, dst_box;
   unsigned src_bs, dst_bs, src_bw, dst_bw, src_bh, dst_bh;

   assert(src && dst);
   if (!src || !dst)
      return;

   assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) ||
          (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER));

   src_format = src->format;
   dst_format = dst->format;

   /* init src box */
   src_box = *src_box_in;

   /* init dst box */
   dst_box.x = dst_x;
   dst_box.y = dst_y;
   dst_box.z = dst_z;
   dst_box.width  = src_box.width;
   dst_box.height = src_box.height;
   dst_box.depth  = src_box.depth;

   src_bs = util_format_get_blocksize(src_format);
   src_bw = util_format_get_blockwidth(src_format);
   src_bh = util_format_get_blockheight(src_format);
   dst_bs = util_format_get_blocksize(dst_format);
   dst_bw = util_format_get_blockwidth(dst_format);
   dst_bh = util_format_get_blockheight(dst_format);

   /* Note: all box positions and sizes are in pixels */
   if (src_bw > 1 && dst_bw == 1) {
      /* Copy from compressed to uncompressed.
       * Shrink dest box by the src block size.
       */
      dst_box.width /= src_bw;
      dst_box.height /= src_bh;
   }
   else if (src_bw == 1 && dst_bw > 1) {
      /* Copy from uncompressed to compressed.
       * Expand dest box by the dest block size.
       */
      dst_box.width *= dst_bw;
      dst_box.height *= dst_bh;
   }
   else {
      /* compressed -> compressed or uncompressed -> uncompressed copy */
      assert(src_bw == dst_bw);
      assert(src_bh == dst_bh);
   }

   assert(src_bs == dst_bs);
   if (src_bs != dst_bs) {
      /* This can happen if we fail to do format checking before hand.
       * Don't crash below.
       */
      return;
   }

   /* check that region boxes are block aligned */
   assert(src_box.x % src_bw == 0);
   assert(src_box.y % src_bh == 0);
   assert(src_box.width % src_bw == 0 ||
          src_box.x + src_box.width == u_minify(src->width0, src_level));
   assert(src_box.height % src_bh == 0 ||
          src_box.y + src_box.height == u_minify(src->height0, src_level));
   assert(dst_box.x % dst_bw == 0);
   assert(dst_box.y % dst_bh == 0);
   assert(dst_box.width % dst_bw == 0 ||
          dst_box.x + dst_box.width == u_minify(dst->width0, dst_level));
   assert(dst_box.height % dst_bh == 0 ||
          dst_box.y + dst_box.height == u_minify(dst->height0, dst_level));

   /* check that region boxes are not out of bounds */
   assert(src_box.x + src_box.width <= u_minify(src->width0, src_level));
   assert(src_box.y + src_box.height <= u_minify(src->height0, src_level));
   assert(dst_box.x + dst_box.width <= u_minify(dst->width0, dst_level));
   assert(dst_box.y + dst_box.height <= u_minify(dst->height0, dst_level));

   /* check that total number of src, dest bytes match */
   assert((src_box.width / src_bw) * (src_box.height / src_bh) * src_bs ==
          (dst_box.width / dst_bw) * (dst_box.height / dst_bh) * dst_bs);

   src_map = pipe->transfer_map(pipe,
                                src,
                                src_level,
                                PIPE_TRANSFER_READ,
                                &src_box, &src_trans);
   assert(src_map);
   if (!src_map) {
      goto no_src_map;
   }

   dst_map = pipe->transfer_map(pipe,
                                dst,
                                dst_level,
                                PIPE_TRANSFER_WRITE |
                                PIPE_TRANSFER_DISCARD_RANGE, &dst_box,
                                &dst_trans);
   assert(dst_map);
   if (!dst_map) {
      goto no_dst_map;
   }

   if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
      assert(src_box.height == 1);
      assert(src_box.depth == 1);
      memcpy(dst_map, src_map, src_box.width);
   } else {
      util_copy_box(dst_map,
                    src_format,
                    dst_trans->stride, dst_trans->layer_stride,
                    0, 0, 0,
                    src_box.width, src_box.height, src_box.depth,
                    src_map,
                    src_trans->stride, src_trans->layer_stride,
                    0, 0, 0);
   }

   pipe->transfer_unmap(pipe, dst_trans);
no_dst_map:
   pipe->transfer_unmap(pipe, src_trans);
no_src_map:
   ;
}
Example #29
0
/**
 * Geta pipe_transfer object which is used for moving data in/out of
 * a resource object.
 * \param pipe  rendering context
 * \param resource  the resource to transfer in/out of
 * \param level  which mipmap level
 * \param usage  bitmask of PIPE_TRANSFER_x flags
 * \param box  the 1D/2D/3D region of interest
 */
static void *
softpipe_transfer_map(struct pipe_context *pipe,
                      struct pipe_resource *resource,
                      unsigned level,
                      unsigned usage,
                      const struct pipe_box *box,
                      struct pipe_transfer **transfer)
{
   struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
   struct softpipe_resource *spr = softpipe_resource(resource);
   struct softpipe_transfer *spt;
   struct pipe_transfer *pt;
   enum pipe_format format = resource->format;
   uint8_t *map;

   assert(resource);
   assert(level <= resource->last_level);

   /* make sure the requested region is in the image bounds */
   assert(box->x + box->width <= (int) u_minify(resource->width0, level));
   if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
      assert(box->y + box->height <= (int) resource->array_size);
   }
   else {
      assert(box->y + box->height <= (int) u_minify(resource->height0, level));
      if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
         assert(box->z + box->depth <= (int) resource->array_size);
      }
      else if (resource->target == PIPE_TEXTURE_CUBE) {
         assert(box->z < 6);
      }
      else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) {
         assert(box->z <= (int) resource->array_size);
      }
      else {
         assert(box->z + box->depth <= (int) u_minify(resource->depth0, level));
      }
   }

   /*
    * Transfers, like other pipe operations, must happen in order, so flush the
    * context if necessary.
    */
   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
      boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
      boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
      if (!softpipe_flush_resource(pipe, resource,
                                   level, box->depth > 1 ? -1 : box->z,
                                   0, /* flush_flags */
                                   read_only,
                                   TRUE, /* cpu_access */
                                   do_not_block)) {
         /*
          * It would have blocked, but state tracker requested no to.
          */
         assert(do_not_block);
         return NULL;
      }
   }

   spt = CALLOC_STRUCT(softpipe_transfer);
   if (!spt)
      return NULL;

   pt = &spt->base;

   pipe_resource_reference(&pt->resource, resource);
   pt->level = level;
   pt->usage = usage;
   pt->box = *box;
   pt->stride = spr->stride[level];
   pt->layer_stride = spr->img_stride[level];

   spt->offset = softpipe_get_tex_image_offset(spr, level, box->z);

   spt->offset +=
         box->y / util_format_get_blockheight(format) * spt->base.stride +
         box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);

   /* resources backed by display target treated specially:
    */
   if (spr->dt) {
      map = winsys->displaytarget_map(winsys, spr->dt, usage);
   }
   else {
      map = spr->data;
   }

   if (!map) {
      pipe_resource_reference(&pt->resource, NULL);
      FREE(spt);
      return NULL;
   }

   *transfer = pt;
   return map + spt->offset;
}
static void *
etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
                  unsigned level,
                  unsigned usage,
                  const struct pipe_box *box,
                  struct pipe_transfer **out_transfer)
{
   struct etna_context *ctx = etna_context(pctx);
   struct etna_resource *rsc = etna_resource(prsc);
   struct etna_transfer *trans;
   struct pipe_transfer *ptrans;
   enum pipe_format format = prsc->format;

   trans = slab_alloc(&ctx->transfer_pool);
   if (!trans)
      return NULL;

   /* 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;

   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
       * pixels between the two resources, and we can de-tile it in s/w. */
      rsc = etna_resource(rsc->texture);
   } else if (rsc->ts_bo ||
              (rsc->layout != ETNA_LAYOUT_LINEAR &&
               util_format_get_blocksize(format) > 1 &&
               /* HALIGN 4 resources are incompatible with the resolve engine,
                * so fall back to using software to detile this resource. */
               rsc->halign != TEXTURE_HALIGN_FOUR)) {
      /* If the surface has tile status, we need to resolve it first.
       * The strategy we implement here is to use the RS to copy the
       * depth buffer, filling in the "holes" where the tile status
       * indicates that it's clear. We also do this for tiled
       * resources, but only if the RS can blit them. */
      if (usage & PIPE_TRANSFER_MAP_DIRECTLY) {
         slab_free(&ctx->transfer_pool, trans);
         BUG("unsupported transfer flags %#x with tile status/tiled layout", usage);
         return NULL;
      }

      if (prsc->depth0 > 1) {
         slab_free(&ctx->transfer_pool, trans);
         BUG("resource has depth >1 with tile status");
         return NULL;
      }

      struct pipe_resource templ = *prsc;
      templ.nr_samples = 0;
      templ.bind = PIPE_BIND_RENDER_TARGET;

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

      /* Need to align the transfer region to satisfy RS restrictions, as we
       * really want to hit the RS blit path here.
       */
      unsigned w_align, h_align;

      if (rsc->layout & ETNA_LAYOUT_BIT_SUPER) {
         w_align = h_align = 64;
      } else {
         w_align = ETNA_RS_WIDTH_MASK + 1;
         h_align = ETNA_RS_HEIGHT_MASK + 1;
      }
      h_align *= ctx->screen->specs.pixel_pipes;

      ptrans->box.width += ptrans->box.x & (w_align - 1);
      ptrans->box.x = ptrans->box.x & ~(w_align - 1);
      ptrans->box.width = align(ptrans->box.width, (ETNA_RS_WIDTH_MASK + 1));
      ptrans->box.height += ptrans->box.y & (h_align - 1);
      ptrans->box.y = ptrans->box.y & ~(h_align - 1);
      ptrans->box.height = align(ptrans->box.height,
                                 (ETNA_RS_HEIGHT_MASK + 1) *
                                  ctx->screen->specs.pixel_pipes);

      if (!(usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE))
         etna_copy_resource_box(pctx, trans->rsc, prsc, level, &ptrans->box);

      /* Switch to using the temporary resource instead */
      rsc = etna_resource(trans->rsc);
   }

   struct etna_resource_level *res_level = &rsc->levels[level];

   /*
    * Always flush if we have the temporary resource and have a copy to this
    * outstanding. Otherwise infer flush requirement from resource access and
    * current GPU usage (reads must wait for GPU writes, writes must have
    * exclusive access to the buffer).
    */
   if ((trans->rsc && (etna_resource(trans->rsc)->status & ETNA_PENDING_WRITE)) ||
       (!trans->rsc &&
        (((usage & PIPE_TRANSFER_READ) && (rsc->status & ETNA_PENDING_WRITE)) ||
        ((usage & PIPE_TRANSFER_WRITE) && rsc->status))))
      pctx->flush(pctx, NULL, 0);

   /* 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.
    */

   /*
    * Pull resources into the CPU domain. Only skipped for unsynchronized
    * transfers without a temporary resource.
    */
   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 (etna_bo_cpu_prep(rsc->bo, prep_flags))
         goto fail_prep;
   }

   /* map buffer object */
   void *mapped = etna_bo_map(rsc->bo);
   if (!mapped)
      goto fail;

   *out_transfer = ptrans;

   if (rsc->layout == ETNA_LAYOUT_LINEAR) {
      ptrans->stride = res_level->stride;
      ptrans->layer_stride = res_level->layer_stride;

      return mapped + res_level->offset +
             etna_compute_offset(prsc->format, box, res_level->stride,
                                 res_level->layer_stride);
   } else {
      unsigned divSizeX = util_format_get_blockwidth(format);
      unsigned divSizeY = util_format_get_blockheight(format);

      /* No direct mappings of tiled, since we need to manually
       * tile/untile.
       */
      if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
         goto fail;

      mapped += res_level->offset;
      ptrans->stride = align(box->width, divSizeX) * util_format_get_blocksize(format); /* row stride in bytes */
      ptrans->layer_stride = align(box->height, divSizeY) * ptrans->stride;
      size_t size = ptrans->layer_stride * box->depth;

      trans->staging = MALLOC(size);
      if (!trans->staging)
         goto fail;

      if (usage & PIPE_TRANSFER_READ) {
         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);
         }
      }

      return trans->staging;
   }

fail:
   etna_bo_cpu_fini(rsc->bo);
fail_prep:
   etna_transfer_unmap(pctx, ptrans);
   return NULL;
}